面试必考之Java的cglib和jdk动态代理对比

本文深入探讨了Java中两种常用的动态代理技术——JDK动态代理和cglib,包括它们的作用范围、技术实现、性能比较及底层原理。JDK代理适用于实现接口的类,而cglib则是通过继承非final类实现。在JDK 1.6和1.7中,cglib性能更优,但在1.8中,JDK表现更好。同时介绍了ASM和Javassist这两个字节码框架,用于理解动态代理的字节码生成过程。

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

1、作用范围 

    jdk:适用于实现接口的类。主要面向接口。

    cglib:通过继承类的方式来实现,该类应该为非final类型。

2、技术实现

    jdk:实现InvocationHandler横切+反射

    cglib:实现MethodInterceptor

接口。通过修改class文件字节码来对方法进行增强。

3、各jdk版本性能

 1.6,1.7: cglib 优于 jdk

 1.8:  jdk 优于 cglib

 为什么?

cglib通过fastclass来创建类,避免使用反射。

4、技术实现

  这里需要提到字节码和class类的相互生成。

  a. 字节码->class类:classloader

  b. class类->字节码增强:字节码框架asm,Javassist。对应类分别是:classwriterhe 和 classpool。

5、ASM介绍

   

<think>好的,我现在需要回答用户关于CGLIB动态代理JDK动态代理区别及使用场景的问题,这是一个常见的Java面试题。首先,我得回忆一下这两个动态代理的基本概念它们之间的主要差异。 首先,JDK动态代理是基于接口的,也就是说它只能为实现了接口的类生成代理。这是因为它通过反射机制调用目标对象的方法,而反射需要接口的支持。而CGLIB动态代理则是通过继承目标类来实现代理,因此它不需要目标类实现接口,这对于那些没有接口的类来说非常有用。不过,使用CGLIB的时候需要注意,如果目标类的方法是final的,那么就无法被代理,因为CGLIB无法覆盖final方法。 接下来是性能方面的问题。我记得以前有资料提到,在JDK 8之前,CGLIB的性能通常比JDK动态代理要好,尤其是在代理方法调用频繁的情况下。这是因为CGLIB生成的代理类直接继承目标类,方法调用可能更直接,而JDK动态代理则通过反射调用,可能会有额外的开销。不过,随着JDK版本的更新,尤其是JDK 8及以后,反射的性能有所提升,可能两者的差距变小了,甚至在某些情况下JDK代理更快。不过具体的数据可能需要查阅最新的基准测试结果,这点需要确认。 然后是生成代理的方式。JDK动态代理使用Java原生的Proxy类InvocationHandler接口,代理对象是在运行时动态生成的。而CGLIB则使用ASM库直接操作字节码,生成目标类的子类作为代理类。这也意味着CGLIB在生成代理时可能会比JDK动态代理慢一些,尤其是在首次生成时,但生成的代理类在方法调用时可能更快。 使用场景方面,如果目标对象已经实现了接口,那么JDK动态代理是一个自然的选择,因为它不需要引入额外的库。而如果目标类没有实现接口,或者需要代理没有接口的第三方类,CGLIB就是更好的选择。不过要注意,由于CGLIB通过继承实现代理,所以不能代理final类或final方法。 还有,依赖方面的问题。JDK动态代理Java标准库的一部分,不需要额外依赖。而CGLIB是一个第三方库,使用时需要添加到项目的依赖中,比如通过Maven或Gradle引入。 另外,异常处理也是一个区别JDK动态代理在调用方法时,如果方法声明了受检异常,代理类需要处理这些异常,或者声明抛出。而CGLIB在这方面可能更灵活,因为它生成的是子类,可以覆盖父类的方法,异常处理的方式可能有所不同。 需要确保提到的点准确无误,特别是性能部分,可能存在版本差异,所以最好引用可靠的资料。比如,Spring框架在选择代理方式时,会根据目标类是否实现接口来决定使用JDK还是CGLIB,这也是一个实际应用的例子。 现在,可能还需要考虑两者的实现原理的详细对比,比如JDK代理是基于接口,CGLIB基于继承,这导致它们在设计上的不同限制。此外,CGLIB不能代理private方法,因为子类无法访问父类的私有方法,而JDK代理则是通过接口方法调用来实现的,所以如果接口中没有定义的方法,也无法被代理。 最后,使用场景需要具体举例,比如在Spring AOP中,默认情况下如果目标对象实现了接口,就使用JDK动态代理,否则使用CGLIB。但在配置中也可以强制使用CGLIB,即使有接口存在,这时候可能需要考虑性能维护性的权衡。 总结一下,主要区别包括实现方式(接口 vs 继承)、性能差异、依赖关系、对目标类的要求(是否有接口、是否final)以及使用场景的选择。需要将这些点有条理地组织起来,用简洁明了的语言表达,同时准备好相关问题,比如性能优化、如何选择等。</think>### CGLIB动态代理JDK动态代理区别及使用场景 #### 1. **实现原理** - **JDK动态代理**:基于接口实现,通过反射机制生成代理类。要求目标类必须实现至少一个接口,代理对象会实现相同的接口并重写方法。 ```java // JDK代理示例 public interface UserService { void save(); } public class UserServiceImpl implements UserService { public void save() { /* 实现 */ } } // 代理处理器 public class MyInvocationHandler implements InvocationHandler { private Object target; public MyInvocationHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(target, args); } } // 生成代理对象 UserService proxy = (UserService) Proxy.newProxyInstance( loader, new Class[]{UserService.class}, new MyInvocationHandler(target) ); ``` - **CGLIB动态代理**:基于继承实现,通过ASM字节码框架生成目标类的子类作为代理类。不要求目标类实现接口,但无法代理`final`类或`final`方法。 ```java // CGLIB代理示例 public class UserService { public void save() { /* 实现 */ } } // 方法拦截器 public class MyMethodInterceptor implements MethodInterceptor { public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { return proxy.invokeSuper(obj, args); } } // 生成代理对象 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserService.class); enhancer.setCallback(new MyMethodInterceptor()); UserService proxy = (UserService) enhancer.create(); ``` #### 2. **性能对比** - **生成代理速度**:JDK动态代理在生成代理类时更快(直接使用Java原生API),而CGLIB首次生成较慢(需操作字节码)。 - **方法调用速度**:在JDK 8之前,CGLIB代理的方法调用性能优于JDK代理[^1]。但随着JDK反射优化(如`MethodHandle`),二者差距缩小,甚至JDK代理在某些场景下更快[^2]。 #### 3. **依赖与兼容性** - **JDK代理**:无需额外依赖,仅依赖Java标准库。 - **CGLIB**:需引入第三方库(如`cglib`或Spring的`spring-core`)。 #### 4. **使用场景** - **JDK动态代理适用场景**: - 目标类已实现接口。 - 需要轻量级代理且避免引入第三方库。 - 例如:Spring AOP默认对接口实现类使用JDK代理[^3]。 - **CGLIB适用场景**: - 目标类未实现接口。 - 需要代理`static`方法或非`final`方法。 - 例如:Spring AOP对未实现接口的类默认使用CGLIB[^3]。 #### 5. **限制与注意事项** - **JDK代理**:无法代理未在接口中声明的方法。 - **CGLIB**: - 无法代理`final`类或`final`方法。 - 代理类会重写目标类的方法,可能导致`equals()`或`hashCode()`行为异常。 ---
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老王随聊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值