Java 的 动态代理入门
Java的动态代理是一种在运行时动态生成代理对象的机制,可以在不修改源代码的情况下,为类和接口创建代理对象,并在代理对象上实现一些自定义的逻辑,例如日志记录、安全控制、性能监控等。Java的动态代理通过反射机制实现,在运行时动态生成代理类,从而实现代理功能。
JDK动态代理主要涉及以下两个类:
java.lang.reflect.InvocationHandler
:定义了一个代理对象要执行的操作,即代理逻辑。该接口只有一个方法invoke
,在代理对象调用方法时,会自动回调该方法。
java.lang.reflect.Proxy
:提供了创建动态代理对象的方法。该类有一个静态方法newProxyInstance
,该方法接收一个ClassLoader
对象、一组接口和一个InvocationHandler
对象作为参数,返回一个代理对象。
在使用Java动态代理时,需要先创建一个实现了InvocationHandler
接口的类,在该类中实现代理逻辑,然后使用Proxy
类的newProxyInstance
方法创建代理对象。
动态代理有许多应用场景,例如AOP编程、RPC调用、对象持久化等。相比于静态代理,动态代理具有更好的灵活性和可扩展性,同时也减少了代码的重复性。
实例
- 创建接口
1 2 3 4
| public interface SmsService { String send(String message); String receive(String message); }
|
- 实现接口
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class SmsServiceImpl implements SmsService{ @Override public String send(String message) { System.out.println("message :" + message); return message; }
@Override public String receive(String message) { System.out.println("receive :" + message); return message; } }
|
- 定义一个JDK动态代理类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class DebugInvocationHandler implements InvocationHandler {
private final Object target;
public DebugInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(method); System.out.println("before method "+method.getName()); Object result = method.invoke(target,args); System.out.println("after method "+method.getName()); return result; } }
|
- 获取代理对象的工厂类
1 2 3 4 5 6 7 8 9 10
| public class JdkProxyFactory { public static Object getProxy(Object target) { return Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new DebugInvocationHandler(target) ); } }
|
- 使用
1 2 3 4 5 6 7 8
| public class Test { public static void main(String[] args) { SmsService smsService = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl()); smsService.send("Java"); smsService.receive("Java"); } }
|
CGLIB
静态代理和动态代理的对比
灵活性:动态代理更加灵活,不需要必须实现接口,可以直接代理实现类,并且可以不需要针对每个目标类都创建一个代理类。另外,静态代理中,接口一旦新增加方法,目标对象和代理对象都要进行修改,这是非常麻烦的!
JVM 层面 :静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的 class 文件。而动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。
参考
07 静态代理+JDK/CGLIB 动态代理实战 (yuque.com)