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