Spring AOP 之JDK动态代理和CGLIB代理的区别

本文详细阐述了Spring AOP中两种动态代理机制——JDK动态代理与CGLIB代理的区别,包括它们的实现原理、应用场景及如何选择合适的代理方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring AOP 之JDK动态代理和CGLIB代理的区别

 

描述和实现原理

 

JDK动态代理

 

    1. 通过实现 InvocationHandler 接口创建自己的调用处理器;

    2. 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;

    3. 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;

    4. 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

 

 

GCLIB代理

 

 1. cglib(Code Generation Library)是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。

 2. cglib封装了asm,可以在运行期动态生成新的class。

 

 

 

区别

 

两者之间的区别

 

    1. JDK的动态代理必须基于接口,CGLIB没有这个要求

    2. java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

 

 

JDK动态代理和CGLIB字节码生成的区别? 

 

    1. JDK动态代理只能对实现了接口的类生成代理,而不能针对类 

    2. CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法因为是继承,所以该类或方法最好不要声明成final

 

 

 

具体应用

 

什么情况下会用哪种方式实现动态代理

 

    1. 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 

    2. 如果目标对象实现了接口,可以强制使用CGLIB实现AOP 

    3. 如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

 

 

如何强制使用CGLIB实现AOP? 

 

    1. 添加CGLIB库,SPRING_HOME/cglib/*.jar 

    2. 在spring配置文件中加入<aop:aspectj-autoproxy proxy-target-class="true"/>

### Spring AOPJDK 动态代理CGLIB区别 #### 区别概述 JDK 动态代理主要依赖于 Java 内置的 `java.lang.reflect.Proxy` 类来创建代理对象,而这些代理对象必须实现一个或多个接口。这种方式适用于目标类实现了至少一个接口的情况[^1]。 相比之下,CGLIB 是一种高性能的字节码生成库,它可以在运行时扩展 Java 类并定义新的方法。对于那些没有提供任何接口的目标类来说,CGLIB 提供了一种有效的解决方案。通过继承原始类并重写其非最终的方法,CGLIB 能够实现代理功能[^2]。 #### 实现原理 - **JDK 动态代理** 当使用 JDK 动态代理时,实际是在内存中构建了一个实现了相同接口的新类实例,并在这个新实例上调用指定的方法前/后执行额外逻辑。此过程利用了反射机制,因此性能上可能会稍逊一些,尤其是在频繁调用的情况下[^3]。 ```java // 创建 InvocationHandler 来处理方法调用 InvocationHandler handler = new MyInvocationHandler(target); // 获取被代理对象所实现的所有接口 Class<?>[] interfaces = target.getClass().getInterfaces(); // 返回由给定加载器接口数组构造的一个代理类的新实例 return Proxy.newProxyInstance(loader, interfaces, handler); ``` - **CGLIB** 对于未实现接口的对象,则采用 CGLIB 库来进行代理操作。CGLIB 可以直接子类化现有类,并覆盖其中的方法以便插入自定义行为。由于不需要借助接口,所以适用范围更广;不过需要注意的是,如果原类中有 final 方法则无法被覆写,也就意味着这部分不会受到 AOP 切面的影响[^4]。 ```java Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(Target.class); // 设置要代理的父类 enhancer.setCallback(new MethodInterceptor() { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 执行前置通知或其他业务逻辑... Object result = proxy.invokeSuper(obj, args); // 调用父类方法 // 执行后置通知或其他业务逻辑... return result; } }); Target proxy = (Target) enhancer.create(); // 创建代理对象 ``` #### 性能对比 通常情况下,CGLIB 在某些特定场景下可能比 JDK 动态代理表现得更好,特别是在大量实例化的环境中。然而,在大多数应用场景里两者之间的差异并不明显,除非有非常严格的性能需求才需考虑这一点。另外值得注意的是,随着 JVM 编译优化的进步,这种差距正在逐渐缩小。 #### 使用场景建议 - 如果应用程序中的服务层组件都遵循良好的面向接口编程原则(即每个具体的服务都有对应的接口),那么推荐优先选用 JDK 动态代理方式。 - 若遇到确实存在不带接口的具体类需要加入到 AOP 处理链路之中,此时应该选择 CGLIB 方案作为替代方案之一。 - 还有一点很重要,当涉及到对私有成员变量的操作或是希望避免因修改原有代码结构带来的风险时,也可以倾向于使用 CGLIB 技术。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值