动态代理和静态代理的区别

在 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

posted @ 2025-04-24 15:49  走向大牛的路上  阅读(76)  评论(0)    收藏  举报