欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > Java的动态代理

Java的动态代理

2025/5/25 3:32:53 来源:https://blog.csdn.net/weixin_73916358/article/details/148163977  浏览:    关键词:Java的动态代理

Java的动态代理

1. 为什么需要动态代理?

动态代理的核心目的是在不修改原始代码的前提下,增强或控制对象的行为,解决以下问题:

  • 代码解耦:将通用逻辑(如日志、事务、权限校验)与业务逻辑分离,避免代码重复和侵入性修改。
  • 灵活性:运行时动态创建代理对象,适应不同场景的需求(如接口代理、类增强)。
  • 简化开发:通过统一拦截方法调用,减少重复代码,提升可维护性(例如 Spring AOP 的实现基础)。

2. 如何实现动态代理?

Java 动态代理的两种主要方式:
JDK 动态代理(基于接口)
// 1. 定义接口
public interface UserService {void save();
}// 2. 实现接口
public class UserServiceImpl implements UserService {@Overridepublic void save() { System.out.println("保存用户"); }
}// 3. 实现 InvocationHandler(增强逻辑)
public class LogHandler implements InvocationHandler {private final Object target;public LogHandler(Object target) { this.target = target; }@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("方法调用前记录日志");Object result = method.invoke(target, args); // 调用原始方法System.out.println("方法调用后记录日志");return result;}
}// 4. 创建代理对象
public static void main(String[] args) {UserService target = new UserServiceImpl();UserService proxy = (UserService) Proxy.newProxyInstance(target.getClass().getClassLoader(),  // 类加载器target.getClass().getInterfaces(),   // 代理接口new LogHandler(target)               // InvocationHandler 实现);proxy.save(); // 调用代理方法
}
CGLIB 动态代理(基于类)

适用于无接口的类,通过继承生成子类代理:

// 1. 定义真实类(无需接口)
public class UserService {public void save() { System.out.println("保存用户"); }
}// 2. 实现 MethodInterceptor(增强逻辑)
public class LogInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("方法调用前记录日志");Object result = proxy.invokeSuper(obj, args); // 调用父类方法System.out.println("方法调用后记录日志");return result;}
}// 3. 创建代理对象
public static void main(String[] args) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(UserService.class);       // 设置父类enhancer.setCallback(new LogInterceptor());      // 设置回调逻辑UserService proxy = (UserService) enhancer.create();proxy.save(); // 调用代理方法
}

3. 动态代理是什么?

定义:动态代理是一种在运行时动态生成代理对象的技术,通过拦截方法调用,在目标方法前后插入额外逻辑。其核心机制包括:

  • 代理模式:通过代理对象间接访问真实对象,实现增强功能。
  • 反射机制:动态调用目标方法(如 method.invoke())。
  • 字节码生成:JDK Proxy 或 CGLIB 在内存中生成代理类的字节码并加载。

特点

  • JDK 动态代理:依赖接口,通过 ProxyInvocationHandler 实现。
  • CGLIB 动态代理:通过继承生成子类代理,无法代理 final 类或方法。

4. CGLIB 和 JDK 动态代理的区别

以下为 CGLIB 和 JDK 动态代理的核心区别对比表格:

对比维度JDK 动态代理CGLIB 动态代理
实现原理基于接口,通过 Proxy 类生成代理对象基于继承,通过 Enhancer 生成目标类的子类代理
接口依赖目标类必须实现接口目标类无需实现接口,可直接代理普通类
继承限制无限制(代理接口)无法代理 final 类或 final 方法
性能特点JDK 8+ 反射调用优化后性能接近 CGLIB通过 FastClass 机制跳过反射,方法调用更快
生成方式运行时动态生成接口实现类字节码运行时动态生成目标类的子类字节码
方法调用通过反射 method.invoke() 调用目标方法通过 MethodProxy.invokeSuper() 直接调用父类方法
适用场景Spring AOP 默认代理有接口的类(JDK ≥ 8 前)Spring Boot 2.x+ 默认代理方式(无接口也可用)
依赖库JDK 原生支持(java.lang.reflect 包)需引入 CGLIB 库(如 cglib-corecglib-asm
补充说明
  1. 性能差异
    • JDK 动态代理:早期版本(JDK 6)反射性能较差,但 JDK 8+ 对反射调用进行了优化(如 MethodHandle),性能差距显著缩小。
    • CGLIB:通过 FastClass 机制为代理类的方法建立索引,直接调用目标方法,避免了反射开销,但生成代理类的过程较慢。
  2. 代理限制
    • CGLIB 无法代理 final 方法(子类不能重写),但 JDK 动态代理无此问题(代理接口方法)。
    • JDK 动态代理的接口方法不能为 staticfinal(接口方法默认 public abstract)。
  3. 框架选择
    • Spring 5.x / Spring Boot 2.x+:默认优先使用 CGLIB(即使目标类实现了接口)。
    • 旧版 Spring:若目标类有接口,默认使用 JDK 动态代理;否则使用 CGLIB。

总结

动态代理通过解耦增强逻辑与业务代码,结合反射和字节码技术,为框架设计(如 Spring AOP)提供了灵活、非侵入式的解决方案。选择 JDK 或 CGLIB 取决于目标类是否有接口,以及对性能的要求。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词