Skip to content

Hot reload of proxy classes ​

Hot reload of proxy classes is very important because Spring and MyBatisPlus etc. enhance the code through proxy classes.

JDK ​

Define interface

java
public interface UserService {

    void addUser(String name);

}

Define the implementation class

java
public class UserServiceImpl implements UserService {

    @Override
    public void addUser(String name) {
        System.out.println("Add user: " + name); 
        printName(name); 
    }
    
    public void printName(String name) { 
        System.out.println("printName: " + name); 
    } 
}

Define the InvocationHandler class

java
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class UserServiceInvocationHandler implements InvocationHandler {

    private final Object target;

    public UserServiceInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("addUser")) {
            System.out.println("Before method: " + method.getName()); 
            printName("Before", method.getName()); 
            Object result = method.invoke(target, args);
            System.out.println("After method: " + method.getName()); 
            printName("After", method.getName()); 
            return result;
        } else {
            return method.invoke(target, args);
        }
    }
    
    private void printName(String hook, String name) { 
        System.out.println(hook + " printName :" + name); 
    } 
}

Using Proxy to create a proxy object

java
import java.lang.reflect.Proxy;

public class ProxyTest {

    public static void main(String[] args) throws InterruptedException {
        UserService target = new UserServiceImpl();
        UserServiceInvocationHandler handler = new UserServiceInvocationHandler(target);
        UserService proxy = (UserService) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                handler
        );
        while (true) {
            Thread.sleep(10000);
            proxy.addUser("DebugTools");
        }
    }
}

Print Result

text
# Before hot reload
Before method: addUser
Add user: DebugTools
After method: addUser
# After hot reload
Before printName: addUser
printName: DebugTools
After printName: addUser

Cglib ​

Creating a proxy object

java
public class UserService {

    public void addUser(String name) {
        System.out.println("Add user: " + name); 
        printName(name); 
    }

    public void printName(String name) { 
        System.out.println("printName: " + name); 
    } 
}

Writing method interceptors

java
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class UserServiceInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        if (method.getName().equals("addUser")) {
            System.out.println("Before method: " + method.getName()); 
            printName("Before", method.getName()); 
            Object result = proxy.invokeSuper(obj, args);
            System.out.println("After method: " + method.getName()); 
            printName("After", method.getName()); 
            return result;
        } else {
            return proxy.invokeSuper(obj, args);
        }
    }

    private void printName(String hook, String name) { 
        System.out.println(hook + " printName :" + name); 
    } 
}

Use Enhancer to dynamically generate proxy classes

java
import net.sf.cglib.proxy.Enhancer;

public class ProxyTest {

    public static void main(String[] args) throws InterruptedException {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserService.class);
        enhancer.setCallback(new UserServiceInterceptor());
        UserService proxy = (UserService) enhancer.create();
        while (true) {
            Thread.sleep(1000);
            proxy.addUser("DebugTools");
        }
    }
}

Print Result

text
# Before hot reload
Before method: addUser
Add user: DebugTools
After method: addUser
# After hot reload
Before printName: addUser
printName: DebugTools
After printName: addUser