Spring5 AOP 默认使用 JDK

这是博主在使用dubbo实现远程过程调用的时候遇到的问题:

我们如果在服务提供者类上加入@Transactional事务控制注解后,服务就发布不成功了。原因是事务控制的底层原理是为服务提供者类创建代理对象,而默认情况下Spring是基于JDK动态代理方式创建代理对象,而此代理对象的完整类名为com.sun.proxy.$Proxy42(最后两位数字不是固定的),导致Dubbo在发布服务前进行包匹配时无法完成匹配,进而没有进行服务的发布。

1. 疑问

大家都知道 Spring5 之前的版本 AOP 在默认情况下是使用 JDK 动态代理的,那 Spring5 版本是不是真的做了修改呢?于是我打开 Spring Framework 5.x 文档,再次进行了确认:

文档地址:https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/core.html#aop


Spring5 AOP 默认使用 JDK_第1张图片

Spring Framework 5.x 文档

简单翻译一下。Spring AOP 默认使用 JDK 动态代理,如果对象没有实现接口,则使用 CGLIB 代理。 默认情况下,如果业务对象没有实现接口,则使用CGLIB。由于面向接口而不是类进行编程是一个最佳实践,所以业务类通常实现一个或多个业务接口。当然,也可以强制使用 CGLIB 代理,在那些(希望很少)情况下,您需要通知[advise]一个没有在接口上声明的方法,或者需要将经过代理的对象作为具体类型传递给方法。

2. 真相大白

在 SpringBoot2.x 版本中,通过AopAutoConfiguration来自动装配 AOP。

默认情况下,是肯定没有spring.aop.proxy-target-class这个配置项的。而此时,在 SpringBoot 2.x 版本中会默认使用 CGLIB 来实现。

SpringBoot 2.x 中如何修改 AOP 实现

通过源码我们也就可以知道,在 SpringBoot 2.x 中如果需要修改 AOP 的实现,需要通过spring.aop.proxy-target-class这个配置项来修改。

#在application.properties文件中通过spring.aop.proxy-target-class来配置
spring.aop.proxy-target-class=false


Spring5 AOP 默认使用 JDK_第2张图片

 

JDK 动态代理是基于接口的,代理生成的对象只能赋值给接口变量

而 CGLIB 就不存在这个问题。因为 CGLIB 是通过动态生成的子类继承目标类的方式来实现的,代理对象无论是赋值给接口还是实现类这两者都是代理对象的父类。 CGLIB的限制/问题:目标类不能使用final修饰。因为final修饰的类是不能被继承的。

SpringBoot 正是出于这种考虑,于是在 2.x 版本中,将 AOP 默认实现改为了 CGLIB。

总结:

1. Spring 5.x 中 AOP 默认依旧使用 JDK 动态代理。

2. SpringBoot 2.x 开始,为了解决使用 JDK 动态代理可能导致的类型转化异常而默认使用 CGLIB。

3. 在 SpringBoot 2.x 中,如果需要默认使用 JDK 动态代理可以通过配置项spring.aop.proxy-target-class=false来进行修改,proxyTargetClass配置已无效。

你可能感兴趣的:(java后端,Spring,Aop,java,spring,boot,代理模式,spring)