当前位置: 首页 > 科技观察

SpringBoot中的AOP是JDK动态代理还是Cglib动态代理?

时间:2023-03-17 19:24:52 科技观察

好了,开始今天的正文。大家都知道AOP的底层是动态代理,而在Java中实现动态代理有两种方式:基于JDK的动态代理和基于Cglib的动态代理。两者最大的区别是基于JDK的动态代理需要代理。Interface,而基于Cglib的动态代理不需要代理对象有接口。那么小伙伴们不禁要问,Spring中的AOP是如何实现的呢?是基于JDK的动态代理还是基于Cglib的动态代理?1、Spring先说结论,用Spring中的哪个动态代理,看情况:如果代理对象有接口,就用JDK动态代理,否则就是Cglib动态代理。如果代理对象没有接口,则直接是一个Cglib动态代理。我们来看看官方文档中的这段说法:可以看到,即使在最新版本的Spring中,上述策略也没有改变。即能用JDK做动态代理就用JDK,不能用JDK做动态代理就用Cglib,也就是首选JDK做动态代理。2、SpringBootSpringBoot和Spring是一脉相承的,那么在动态代理的问题上是不是同一个策略呢?对不起,这个真的很不一样。SpringBoot对这个问题的处理,以SpringBoot2.0为节点,前后不一样。在SpringBoot2.0之前Aop的自动配置代码是这样的(SpringBoot1.5.22.RELEASE):@Configuration@ConditionalOnClass({EnableAspectJAutoProxy.class,Aspect.class,Advice.class})@ConditionalOnProperty(prefix="spring.aop",name="auto",havingValue="true",matchIfMissing=true)publicclassAopAutoConfiguration{@Configuration@EnableAspectJAutoProxy(proxyTargetClass=false)@ConditionalOnProperty(prefix="spring.aop",name="代理目标-class",havingValue="false",matchIfMissing=true)publicstaticclassJdkDynamicAutoProxyConfiguration{}@Configuration@EnableAspectJAutoProxy(proxyTargetClass=true)@ConditionalOnProperty(prefix="spring.aop",name="proxy-target-class",havingValue="true",matchIfMissing=false)publicstaticclassCglibAutoProxyConfiguration{}}可以看到,这个自动配置主要是在application.properties配置文件中讨论spring.aop.proxy-target-class属性的值。具体起作用的是@ConditionalOnProperty注释。关于这个注解中的几个属性,宋大哥也会稍微说一下:prefix:配置文件的前缀。name:配置文件的名称,与前缀一起构成配置键。having:预期的配置值。如果实际配置与having值相同则配置生效,否则不生效。matchIfMissing:如果开发者没有在application.properties中配置,这个配置类是否生效。根据上面的介绍,我们不难看出,如果开发者将spring.aop.proxy-target-class设置为false,就会使用JDK代理。如果开发人员将spring.aop.proxy-target-class设置为true,则使用Cglib代理。如果开发者一开始就没有配置spring.aop.proxy-target-class属性,则使用JDK代理。在SpringBoot2.0之前就是这样。我们看一下SpringBoot2.0(含)(SpringBoot2.0.0.RELEASE)之后的情况:="spring.aop",name="auto",havingValue="true",matchIfMissing=true)publicclassAopAutoConfiguration{@Configuration@EnableAspectJAutoProxy(proxyTargetClass=false)@ConditionalOnProperty(prefix="spring.aop",name="proxy-target-class",havingValue="false",matchIfMissing=false)publicstaticclassJdkDynamicAutoProxyConfiguration{}@Configuration@EnableAspectJAutoProxy(proxyTargetClass=true)@ConditionalOnProperty(prefix="spring.aop",name="代理目标-class",havingValue="true",matchIfMissing=true)publicstaticclassCglibAutoProxyConfiguration{}}可以看到大部分的配置都是一样的,但是有一点不同,就是matchIfMissing属性的取值。可以看出,从SpringBoot2.0开始,如果用户什么都不配置,默认使用Cglib代理。3.实践最后,我们写一个简单的例子来验证我们的想法。首先创建一个SpringBoot项目(本例使用最新版本的SpringBoot,即默认使用Cglib代理),添加三个依赖即可,如下:org.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starterorg.springframework.bootspring-boot-starter-aop接下来我们创建一个IUserService接口,如下:publicinterfaceIUserService{voidhello();}然后我们再创建这个接口的实现类:@ServicepublicclassUserServiceImplimplementsIUserService{@Overridepublicvoidhello(){}}方法不需要实现。另一个简单的方面:@EnableAspectJAutoProxy@Aspect@ComponentpublicclassLogAspect{@Before("execution(*org.javaboy.demo.UserServiceImpl.*(..))")publicvoidbefore(JoinPointjp){System.out.println("jp.getSignature().getName()="+jp.getSignature().getName());}}最后,一个注入IUserService实例的简单测试方法:@RestControllerpublicclassHelloController{@AutowiredIUserServiceiUserService;@GetMapping("/hello")publicvoidhello(){iUserService.hello();}}DBUEG运行,可以看到IUserService是通过Cglib代理的。如果我们要使用JDK作为代理,只需要在application.properties中添加如下配置:spring.aop.proxy-target-class=false添加后,重新DEBUG,如下图所示:可以看到,它已经使用了JDK动态代理。如果你使用的是SpringBoot1.5.22.RELEASE版本,即使不在application.properties中添加配置,默认也是JDK代理。我不会测试这个,你可以自己试试。4.总结总结一下:Spring中的AOP,有接口就用JDK动态代理,没有接口就用Cglib动态代理。SpringBoot中的AOP与2.0之前的Spring是一样的;2.0以后首选cglib动态代理。如果用户想使用JDK动态代理,需要手动配置。只是这个。