Java设计模式之代理模式(三)
spring和springboot中默认的代理方式
1、在Spring 5.x中AOP默认依旧使用JDK动态代理。
2、SpringBoot 2.x开始,为了解决使用JDK动态代理可能导致的类型转换异常,而使用CGLIB。
3、在SpringBoot 2.x中,如果需要替换使用JDK动态代理可以通过配置项spring.aop.proxy-target-class=false来进行修改,proxyTargetClass配置已无效。
在spring官网中,目前最新的6.0版本中,AOP默认依旧使用JDK动态代理。
官网地址:
https://docs.spring.io/spring-framework/docs/6.0.x/reference/html/core.html#aop-introduction-proxies
Springboot 2.x内嵌Spring版本为Spring5.x,在Spring5中默认还是使用jdk动态代理。
在 SpringBoot 1.5.x 版本中,默认还是使用 JDK 动态代理的。
搜索AopAutoConfiguration。matchIfMissing表示配置文件缺少该属性时是否可以加载,如果为true,则没有该属性也会正常加载,否则不能加载。由下图可知,在 SpringBoot 1.5.x 版本中,如果配置文件中没有配置spring.aop.proxy-target-class属性,则默认加载jdk动态代理配置类。如果配置文件中配置了spring.aop.proxy-target-class属性,且属性值为true,则加载cglib代理配置类。
在 SpringBoot 2.x 中会默认使用 cglib代理来实现,如下图所示。
如果要修改默认的代理方式,需要通过spring.aop.proxy-target-class这个配置项来修改。该配置项的意思是代理目标类,如果该配置项为false,则表示使用jdk动态代理,jdk是给接口生成代理类,如果为true,则表示使用cglib动态代理,cglib是给目标类生成代理类。
#在application.properties文件中通过spring.aop.proxy-target-class来配置
spring.aop.proxy-target-class=false
SpringBoot 2.x 为何默认使用 Cglib动态代理方式?
假设有一个UserService接口和UserServiceImpl实现类,此时需要在UserContoller中使用UserService。在 Spring 中通常都习惯这样写代码:
@Autowired
private UserService userService;
在这种情况下,无论是使用 JDK 动态代理,还是 CGLIB 都不会出现问题。但是,如果代码是这样的:
@Autowired
private UserServiceImpl userService;
此时如果使用 JDK 动态代理,启动时就会报错,因为 JDK 动态代理是基于接口的,代理生成的对象只能赋值给接口引用变量。而 CGLIB 就不存在这个问题,因为 CGLIB 是通过生成子类来实现的,代理对象无论是赋值给接口还是实现类,这两者都是代理对象的父类。
SpringBoot 正是出于这种考虑,于是在 2.x 版本中,将 AOP 默认实现改为了 CGLIB。