一、背景
在 SpringBoot 2.x AOP中会默认使用Cglib来实现,但是Spring5中默认还是使用jdk动态代理。Spring AOP 默认使用 JDK 动态代理,如果对象没有实现接口,则使用 CGLIB 代理。也可以强制使用 CGLIB 代理。springboot默认使用cglib实现代码逻辑来记录一下。
二、自动配置
1、springboot aop自动配置类为AopAutoConfiguration.java
@Configuration
@ConditionalOnClass({EnableAspectJAutoProxy.class, Aspect.class, Advice.class, AnnotatedElement.class})
@ConditionalOnProperty(prefix = "spring.aop",name = {"auto"},havingValue = "true",matchIfMissing = true
)
public class AopAutoConfiguration {public AopAutoConfiguration() {}@Configuration@EnableAspectJAutoProxy(proxyTargetClass = true)@ConditionalOnProperty(prefix = "spring.aop",name = {"proxy-target-class"},havingValue = "true",matchIfMissing = true)public static class CglibAutoProxyConfiguration {public CglibAutoProxyConfiguration() {}}@Configuration@EnableAspectJAutoProxy(proxyTargetClass = false)@ConditionalOnProperty(prefix = "spring.aop",name = {"proxy-target-class"},havingValue = "false",matchIfMissing = false)public static class JdkDynamicAutoProxyConfiguration {public JdkDynamicAutoProxyConfiguration() {}}
}
2、 CglibAutoProxyConfiguration上注解
@ConditionalOnProperty(
prefix = “spring.aop”,
name = {“proxy-target-class”},
havingValue = “true”,
matchIfMissing = true
)
当spring.aop.proxy-target-class是否配置都会设置成true.关于ConditionalOnProperty注解参数可以参照这个博客
3、 @EnableAspectJAutoProxy(proxyTargetClass = true)这个注解中导入@Import(AspectJAutoProxyRegistrar.class)
可以看到把beanName:org.springframework.aop.config.internalAutoProxyCreator
,类型为:AnnotationAwareAspectJAutoProxyCreator的proxyTargetClass 属性设置成true。
三、bean在spirng中被代理过程
1、不存在循环依赖的时候
bean属性赋值后,发生在bean initializeBean初始化方法applyBeanPostProcessorsAfterInitialization后置处理中。
执行AbstractAutoProxyCreator的后置处理方法,如果没有调用过三级缓存earlyProxyReferences中就没有存储当前对象名称。如图1
wrapIfNecessary->createProxy-> proxyFactory.getProxy
当这三个条件都满足时,会使用jdk动态代理.
!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)
看一下ProxyConfig和AnnotationAwareAspectJAutoProxyCreator的继承关系,可以发现自动配置中设置的ProxyTargetClass=true其实就是设置父类中proxyConfig中的属性。config.isProxyTargetClass()是true,所以执行cglib动态代理创建。isOptimize配置文件可以配置,默认为false
hasNoUserSuppliedProxyInterfaces可以理解为判断被代理类是否有实现接口。
2、循环依赖的时候
populateBean属性赋值前,三级缓存中vulue存入函数式接口,this.singletonFactories.put(beanName, singletonFactory);当调用getObject方法时,会执行getEarlyBeanReference(beanName, mbd, bean)。
先看一下getEarlyBeanReference这个方法,再看什么时候执行三级缓存中的函数式接口。遍历所有后置处理器,会执行AbstractAutoProxyCreator的getEarlyBeanReference方法,如下图可以看到earlyProxyReferences放入值,防止初始化中后置处理器会判断是有值,防止重复创建代理类,可以往上翻看图1。wrapIfNecessary方法和无循环依赖方法一样,这里不再赘述。
下面看一下什么时候会执行三级缓存里面的函数式接口。如果A中有属性B,B中有属性A,当创建A的时候,A在属性赋值前三级缓存存入A的创建代理类的函数式接口。当A属性赋值时,会创建B,因为B有属性A,又会重新进入创建A的逻辑,doGetBean->getSingleton
如果一级和二级缓存都没有值,就会获取三级缓存函数式接口,执行getObject(),返回代理对象,把代理对象存入二级缓存,最后返回代理对象完成B的属性A的赋值。A继续完成B的属性赋值把创建完成的类再放入一级缓存。可以看到如果有循环依赖会在属性赋值时完成代理类的创建,而不会到后置处理器。这也是三级缓存的作用就是完成循环依赖的创建代理对象。