Spring 中 aop 为什么需要 jdk 动态和 cglib 两种方式?是因为性能差异?还是什么原因?
回答·35
最热
最新
- jdk 动态代理需要当前类实现一个接口,然后通过 Proxy 类的 newProxyInstance 方法为这个类生成一个代理对象,通过代理对象调用目标类中的方法,请求被转发给 InvocationHandler 中的 invoke 方法,最终通过反射的方式执行目标类中的方法。jdk 的动态代理只能代理实现了接口的类,而不能实现接口的类就不能使用 jdk 动态代理,此时可以使用 cglib 的动态代理,它是针对类来实现代理,通过对指定目标类生成一个子类,并覆盖类中的方法实现增强,但是因为采用的是继承的方式,所以不能对 final 修饰的类进行代理。spring 中默认是使用 jdk 的动态代理,其次是 cglib 动态代理。
- 好好想想,spring 为什么那么流行。就是因为 spring 大大简化了开发流程,很多本该我们做的,我们考虑的 spring 都帮我们考虑了。 再想想 jdk 动态代理与 cglib 动态代理有什么不同。最大的不同就是 jdk 动态代理作用的对象是实现了方法的类,而 cglib 代理可以对普通类做代理。 假设只有 jdk 动态代理,那么开发者岂不是必须要将类的方法实现了,才能做代理?我想 spring 的开发者们不会允许这样的情况发生。
- 个人感觉两种性能也差不多,cglib 是字节码增强,jdk 动态代理用了反射。springboot2.0 默认是 cglib 了,理由是避免某些莫名其妙错误。比如你使用了接口方式,但是@Autowired 注入的时候使用了接口实现类,这时候你 springboot 强指定使用 jdk 动态代理会报错
- 因为 java 是单继承,动态代理默认继承 proxy,所以接口是 cglib,类的话是 jdk 动态代理
- 有接口的话,一般使用 jdk 代理,如果没有接口,则使用 cglib 代理。两者的性能差异,主要是由于实现方式的区别,jdk 代理是在运行时通过反射实现,而 cglib 代理则是由 asm 字节码技术生成代理类实现,运行时性能上 cglib 更好一些,编译期 jdk 更好。
- 这两个都是动态代理而非静态代理,cglib 适用于无接口的类动态生成,通过 asm 实现的,jdk 的动态代理有限制必须有接口,如果没有想实现则要通过 javac 重写代码编译来编织实现。另外 cglib 性能大于 jdk 代理是很早前的事情,java 在 8 的时候性能上已经大于 cglib 了。
- 如果有接口,99%都是用的 jdk,没有接口都用的 cglib
- JDK 动态代理和 CGLIB 动态代理在 Spring AOP 中的选择,主要是因为它们对目标对象的支持度不同造成的。 JDK 动态代理只能对实现了接口的类生成代理,而不能针对没有实现接口的类进行代理。 CGLIB 动态代理不需要目标对象必须实现接口,它是针对类来实现代理的,也就是说,CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对 final 修饰的类进行代理。 所以,在选择 Spring AOP 实现时,要根据目标对象是否实现了接口来决定采用哪种方式。如果目标对象实现了接口,则采用 JDK 动态代理;如果目标对象没有实现接口,则采用 CGLIB 动态代理。 而对于性能差异,一般情况下,JDK 动态代理的效率略高于 CGLIB 动态代理。因此,如果目标对象实现了接口,则更推荐采用 JDK 动态代理。
- 可悲的 Java 技术内卷化
- jdK 可以对实现了某个接口的类产生动态代理。如果沒有实现接口的类,可以用 cglib 来产生动态代理类