动态代理和静态代理的区别
在 Java 中,动态代理是一种通过反射机制在运行时动态生成代理对象的技术,它能够在不修改原有代码的基础上增强目标对象的功能。以下是关于动态代理的详细说明:
一、静态代理 vs 动态代理
1. 静态代理
定义:手动编写代理类,代理类需要实现与目标类相同的接口,并在方法中调用目标对象的方法。
缺点:
每个目标类需要一个对应的代理类,代码冗余。
接口或目标类变更时,代理类需要同步修改。
示例:
1 interface UserService { 2 void save(); 3 } 4 5 class UserServiceImpl implements UserService { 6 public void save() { System.out.println("保存用户"); } 7 } 8 9 // 静态代理类 10 class UserServiceProxy implements UserService { 11 private UserService target; 12 public UserServiceProxy(UserService target) { this.target = target; } 13 public void save() { 14 System.out.println("前置操作"); 15 target.save(); 16 System.out.println("后置操作"); 17 } 18 }
2. 动态代理
定义:在运行时动态生成代理类,无需手动编写代理类。
优点:
一个代理类可以代理多个目标类。
代码复用性高,维护成本低。
核心机制:通过反射(java.lang.reflect.Proxy)或字节码增强(如 CGLIB)生成代理对象。
二、Java 动态代理的实现方式
1. JDK 动态代理(基于接口)
要求:目标对象必须实现至少一个接口。
核心类:
java.lang.reflect.Proxy:生成代理对象。
java.lang.reflect.InvocationHandler:定义代理逻辑。
实现步骤:
定义接口和实现类(目标对象)。
实现 InvocationHandler 接口,编写增强逻辑。
通过 Proxy.newProxyInstance() 生成代理对象。
代码示例:
1 interface UserService { void save(); } 2 3 class UserServiceImpl implements UserService { 4 public void save() { System.out.println("保存用户"); } 5 } 6 7 class MyInvocationHandler implements InvocationHandler { 8 private Object target; 9 public MyInvocationHandler(Object target) { this.target = target; } 11 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 12 System.out.println("前置操作"); 13 Object result = method.invoke(target, args); // 反射调用目标方法 14 System.out.println("后置操作"); 15 return result; 16 } 17 } 18 19 // 生成代理对象 20 UserService proxy = (UserService) Proxy.newProxyInstance( 21 UserService.class.getClassLoader(), 22 new Class[]{UserService.class}, 23 new MyInvocationHandler(new UserServiceImpl()) 24 ); 25 proxy.save(); // 调用代理方法
2. CGLIB 动态代理(基于继承)
要求:目标类不需要实现接口,通过继承目标类生成子类代理。
依赖:需要引入 cglib 库(Spring Core 已内置)。
核心类:
net.sf.cglib.proxy.Enhancer:生成代理对象。
net.sf.cglib.proxy.MethodInterceptor:定义代理逻辑。
代码示例:
1 class UserService { 2 public void save() { System.out.println("保存用户"); } 3 } 4 5 class MyMethodInterceptor implements MethodInterceptor { 6 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { 7 System.out.println("前置操作"); 8 Object result = proxy.invokeSuper(obj, args); // 调用父类方法 9 System.out.println("后置操作"); 10 return result; 11 } 12 } 13 14 // 生成代理对象 15 Enhancer enhancer = new Enhancer(); 16 enhancer.setSuperclass(UserService.class); 17 enhancer.setCallback(new MyMethodInterceptor()); 18 UserService proxy = (UserService) enhancer.create(); 19 proxy.save();
三、动态代理的应用场景
AOP 编程:如 Spring AOP 的切面(日志、事务、权限控制)。
RPC 框架:远程方法调用的客户端代理。
延迟加载:Hibernate 的延迟加载实现。
单元测试:Mock 对象的动态生成。
四、JDK 动态代理 vs CGLIB 动态代理
特性 JDK 动态代理 CGLIB 动态代理
依赖 目标类必须实现接口 无接口要求
生成方式 反射生成代理类 继承目标类生成子类
性能 调用较快,生成较慢 生成较快,调用较慢
局限性 无法代理未实现接口的类 无法代理 final 类/方法
应用框架 Spring AOP(默认接口场景) Spring AOP(非接口场景)
五、总结
静态代理适合简单场景,但代码冗余。
动态代理通过反射或字节码技术动态生成代理类,灵活且高效。
JDK 动态代理基于接口,CGLIB基于继承,根据需求选择合适方式。
原文链接:https://blog.csdn.net/weixin_73355042/article/details/146885653