写点什么

Spring 动态代理时是如何解决循环依赖的?为啥用三级缓存?

用户头像
极客good
关注
发布于: 刚刚

@Before("execution(public?void?com.liuzhihang.circular.CircularServiceA.methodA())")?


public?void?beforeA()?{?


System.out.println("beforeA?执行");?


}?


}?


只有 A 的情况下,给 A 添加切面,开始 Debug。


前面的流程都相同,在 initializeBean 开始出现差异。


这一步需要初始化 Bean 并执行 Bean 的后置处理器。



执行后置处理器


其中有一个处理器为:AnnotationAwareAspectJAutoProxyCreator 其实就是加的注解切面,会跳转到 AbstractAutoProxyCreator 类的 postProcessAfterInitialization 方法



postProcessAfterInitialization


如图所示:wrapIfNecessary 方法会判断是否满足代理条件,是的话返回一个代理对象,否则返回当前 Bean。


后续调用 getProxy 、createAopProxy 等等,最终执行到下面一部分。



最终会执行到这里,AOP 代理相关的就不细看了。


一路前行,直到 initializeBean 执行结束。



A 被替换为了代理对象


此时发现:A 被替换为了代理对象。


所以 doCreateBean 返回,以及后面放到一级缓存中的都是代理对象。



红框部分为差异


有循环依赖的动态代理


==========


这一次把循环依赖打开:


@Service?


public?class?CircularServiceA?{?


private?String?fieldA?=?"字段?A";?


@Autowired?


private?CircularServiceB?circularServiceB;?


public?void?methodA()?{?


System.out.println("方法?A?执行");?


}?


}?


@Aspect?


@Component?


public?class?AspectA?{?


@Before("execution(public?void?com.liuzhihang.circular.CircularServiceA.methodA())")?


public?void?beforeA()?{?


System.out.println("beforeA?执行");?


}?


}?


@Service?


public?class?CircularServiceB?{?


@Autowired?


private?CircularServiceA?circularServiceA;?


public?void?methodB()?{?


}?


}?


@Aspect?


@Component?


public?class?AspectB?{?


@Before("execution(public?void?com.liuzhihang.circular.CircularServiceB.methodB())")?


public?void?beforeB()?{?


System.out.println("beforeB?执行");?


}?


}?


开始 Debug,前面的一些列流程,都和正常的没有什么区别。而唯一的区别在于,创建 B 的时候,需要从三级缓存获取 A。


此时在 getSingleton 方法中会调用:singletonObject = singletonFactory.getObject();



B 属性赋值时,从三级缓存获取 A


有时会比较疑惑 singletonFactory.getObject() 调用的是哪里?



三级缓存获取对象


所以这一块调用的是 getEarlyBeanReference,开始遍历执行 BeanPostProcessor。



getEarlyBeanReference



getEarlyBeanReference


看到 wrapIfNecessary 就明白了吧!这块会获取一个代理对象。


也就是说此时返回,并放到二级缓存的是一个 A 的代理对象。


这样 B 就创建完毕了!


到 A 开始初始化并执行后置处理器了!因为 A 也有代理,所以 A 也会执行到 postProcessAfterInitialization 这一部分!



判断二级缓存


但是在执行 wrapIfNecessary 之前,会先判断二级缓存是否有 A 了。


this.earlyProxyReferences.remove(cacheKey)?!=?bean?


但是这块获取到的是 A 的代理对象。肯定是 false 。所以不会再生成一次 A 的代理对象。



代理 - 循环依赖


总结


==


可以看到,循环依赖下,有没有代理情况下的区别就在:


singletonObject?=?singletonFactory.getObject();?


在循环依赖发生的情况下 B 中的 A 赋值时:


  1. 无代理:getObject 直接返回原来的 Bean

  2. 有代理:getObject 返回的是代理对象


然后都放到二级缓存。


为什么要三级缓存?


=========


假设去掉三级缓存


========


去掉三级缓存之后,Bean 直接创建 earlySingletonObjects, 看着好像也可以。


如果有代理的时候,在 earlySingletonObjects 直接放代理对象就行了。


但是会导致一个问题:在实例化阶段就得执行后置处理器,判断有 AnnotationAwareAspectJAutoProxyCreator 并创建代理对象。


这么一想,是不是会对 Bean 的生命周期有影响。


同样,先创建 singletonFactory 的好处就是:在真正需要实例化的时候,再使用 singletonFactory.getObject() 获取 Bean 或者 Bean 的代理。相当于是延迟实例化。


假设去掉二级缓存


========


如果去掉了二级缓存,则需要直接在 singletonFactory.getObject() 阶段初始化完毕,并放到一级缓存中。



B 和 C 都依赖 A


哪有这么一种


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


场景,B 和 C 都依赖了 A。


要知道在有代理的情况下 singletonFactory.getObject() 获取的是代理对象。



多次获取代理对象不同


而多次调用 singletonFactory.getObject() 返回的代理对象是不同的,就会导致 B 和 C 依赖了不同的 A。


那如果获取 B 到之后直接放到一级缓存,然后 C 再获取呢?


用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
Spring动态代理时是如何解决循环依赖的?为啥用三级缓存?