什么是循环依赖

所谓的循环依赖是指,A 依赖 B,B 又依赖 A,它们之间形成了循环依赖。或者是 A 依赖 B,B 依赖 C,C 又依

赖 A。它们之间的依赖关系如下
image.png
代码示例:

  1. public class MainStart {
  2. private static Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
  3. /**
  4. * 读取bean定义,当然在spring中肯定是根据配置 动态扫描注册
  5. */
  6. public static void loadBeanDefinitions() {
  7. RootBeanDefinition aBeanDefinition=new RootBeanDefinition(InstanceA.class);
  8. RootBeanDefinition bBeanDefinition=new RootBeanDefinition(InstanceB.class);
  9. beanDefinitionMap.put("instanceA",aBeanDefinition);
  10. beanDefinitionMap.put("instanceB",bBeanDefinition);
  11. }
  12. public static void main(String[] args) throws Exception {
  13. // 加载了BeanDefinition
  14. loadBeanDefinitions();
  15. // 注册Bean的后置处理器
  16. // 循环创建Bean
  17. for (String key : beanDefinitionMap.keySet()){
  18. // 先创建A
  19. getBean(key);
  20. }
  21. InstanceA instanceA = (InstanceA) getBean("instanceA");
  22. instanceA.say();
  23. }
  24. // 一级缓存
  25. public static Map<String,Object> singletonObjects=new ConcurrentHashMap<>();
  26. // 二级缓存: 为了将 成熟Bean和纯净Bean分离,避免读取到不完整得Bean
  27. public static Map<String,Object> earlySingletonObjects=new ConcurrentHashMap<>();
  28. // 三级缓存
  29. public static Map<String,ObjectFactory> singletonFactories=new ConcurrentHashMap<>();
  30. // 循环依赖标识
  31. public static Set<String> singletonsCurrennlyInCreation=new HashSet<>();
  32. // 假设A 使用了Aop @PointCut("execution(* *..InstanceA.*(..))") 要给A创建动态代理
  33. // 获取Bean
  34. public static Object getBean(String beanName) throws Exception {
  35. Object singleton = getSingleton(beanName);
  36. if(singleton!=null){
  37. return singleton;
  38. }
  39. // 正在创建
  40. if(!singletonsCurrennlyInCreation.contains(beanName)){
  41. singletonsCurrennlyInCreation.add(beanName);
  42. }
  43. // createBean
  44. // 实例化
  45. RootBeanDefinition beanDefinition = (RootBeanDefinition) beanDefinitionMap.get(beanName);
  46. Class<?> beanClass = beanDefinition.getBeanClass();
  47. Object instanceBean = beanClass.newInstance(); // 通过无参构造函数
  48. // 创建动态代理 (耦合 、BeanPostProcessor) Spring还是希望正常的Bean 还是再初始化后创建
  49. // 只在循环依赖的情况下在实例化后创建proxy 判断当前是不是循环依赖
  50. singletonFactories.put(beanName, () -> new JdkProxyBeanPostProcessor().getEarlyBeanReference(earlySingletonObjects.get(beanName),beanName));
  51. // 添加到二级缓存
  52. // earlySingletonObjects.put(beanName,instanceBean);
  53. // 属性赋值
  54. Field[] declaredFields = beanClass.getDeclaredFields();
  55. for (Field declaredField : declaredFields) {
  56. Autowired annotation = declaredField.getAnnotation(Autowired.class);
  57. // 说明属性上面有Autowired
  58. if(annotation!=null){
  59. declaredField.setAccessible(true);
  60. // byname bytype byconstrator
  61. // instanceB
  62. String name = declaredField.getName();
  63. Object fileObject= getBean(name); //拿到B得Bean
  64. declaredField.set(instanceBean,fileObject);
  65. }
  66. }
  67. // 初始化 init-mthod
  68. // 放在这里创建已经完了 B里面的A 不是proxy
  69. // 正常情况下会再 初始化之后创建proxy
  70. // 由于递归完后A 还是原实例,, 所以要从二级缓存中拿到proxy 。
  71. if(earlySingletonObjects.containsKey(beanName)){
  72. instanceBean=earlySingletonObjects.get(beanName);
  73. }
  74. // 添加到一级缓存 A
  75. singletonObjects.put(beanName,instanceBean);
  76. // remove 二级缓存和三级缓存
  77. return instanceBean;
  78. }
  79. public static Object getSingleton(String beanName){
  80. // 先从一级缓存中拿
  81. Object bean = singletonObjects.get(beanName);
  82. // 说明是循环依赖
  83. if(bean==null && singletonsCurrennlyInCreation.contains(beanName)){
  84. bean=earlySingletonObjects.get(beanName);
  85. // 如果二级缓存没有就从三级缓存中拿
  86. if(bean==null) {
  87. // 从三级缓存中拿
  88. ObjectFactory factory = singletonFactories.get(beanName);
  89. if (factory != null) {
  90. bean=factory.getObject(); // 拿到动态代理
  91. earlySingletonObjects.put(beanName, bean);
  92. }
  93. }
  94. }
  95. return bean;
  96. }
  97. }

总结:getBean()核心方法

1:先实例化化,采用反射无参构造
Object beanInstanc = beanClass.newInstance();
2:获取filed 对filed 赋值,递归调用getBean方法
Object fileObject= getBean(name);
3:将bean 放到 一级缓存
singletonObjects.put(beanName,instanceBean);

tip:获取过程判断的各种判断

如何解决循环依赖

引入第三方

三级缓存

一级缓存
保存的是单实例的bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

二级缓存
缓存的是早期对象,不完整的bean对象
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

三级缓存
缓存的是 ObjectFactory
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

创建的步骤

  1. 创建原始 bean 对象

    1. instanceWrapper = createBeanInstance(beanName, mbd, args);
    2. final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
  2. 暴露早期的引用
    把早期对象包装称ObjectFactory 放在三级缓存

  3. 解析依赖
    populateBean(beanName, mbd, instanceWrapper);对对象A填充属性B,会调用BeanFactory.getBean(方法
  4. 获取早期引用
    this.earlySingletonObjects.get("beanA")

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

  1. protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  2. // Quick check for existing instance without full singleton lock
  3. // 从单例对象缓存中获取beanName对应的单例对象
  4. Object singletonObject = this.singletonObjects.get(beanName);
  5. // 如果单例对象缓存中没有,并且该beanName对应的单例bean正在创建中
  6. if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
  7. //从早期单例对象缓存中获取单例对象(之所称成为早期单例对象,是因为earlySingletonObjects里
  8. // 的对象的都是通过提前曝光的ObjectFactory创建出来的,还未进行属性填充等操作)
  9. singletonObject = this.earlySingletonObjects.get(beanName);
  10. // 如果在早期单例对象缓存中也没有,并且允许创建早期单例对象引用
  11. if (singletonObject == null && allowEarlyReference) {
  12. // 如果为空,则锁定全局变量并进行处理
  13. synchronized (this.singletonObjects) {
  14. // Consistent creation of early reference within full singleton lock
  15. singletonObject = this.singletonObjects.get(beanName);
  16. if (singletonObject == null) {
  17. singletonObject = this.earlySingletonObjects.get(beanName);
  18. if (singletonObject == null) {
  19. // 当某些方法需要提前初始化的时候则会调用addSingletonFactory方法将对应的ObjectFactory初始化策略存储在singletonFactories
  20. ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
  21. if (singletonFactory != null) {
  22. // 如果存在单例对象工厂,则通过工厂创建一个单例对象
  23. singletonObject = singletonFactory.getObject();
  24. // 记录在缓存中,二级缓存和三级缓存的对象不能同时存在
  25. this.earlySingletonObjects.put(beanName, singletonObject);
  26. // 从三级缓存中移除
  27. this.singletonFactories.remove(beanName);
  28. }
  29. }
  30. }
  31. }
  32. }
  33. }
  34. return singletonObject;
  35. }

对应过程的流程图

https://www.processon.com/view/link/5f1fb2cf1e08533a628a7b4c
image.png
image.png

三级缓存的原因

二级缓存:分离完整bean和初始化bean,多线程下要保证getBean是完整bean

为什么三级:
bean的aop实在初始化之后,
如果循环依赖Bean使用aop,需要提前创建aop

三级缓存,是一个函数接口,代理对象,普通对象都在BeanPostProcessore,可以解耦,
?我在看看吧

spring不能解决构造器的循环依赖:
实例化之前,缓存没有bean的信息,也就取不到

多例不能解决循环依赖:
如果是原型bean: 每次都有创建对象
如果是构造注入,需要调用构造注入,无法利用缓存

循环依赖的关闭功能

  1. public class Main {
  2. public static void main(String[] args) {
  3. AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
  4. applicationContext.setAllowCircularReferences(false);
  5. applicationContext.register(AppConfig.class);
  6. applicationContext.refresh();
  7. }
  8. }

如何扩展

SmartInstantiationAwareBeanPostProcessor 重写 getEarlyBeanReference

  1. protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)throws BeanCreationException {
  2. //省略其他代码,只保留了关键代码
  3. //...
  4. // Eagerly cache singletons to be able to resolve circular references
  5. // even when triggered by lifecycle interfaces like BeanFactoryAware.
  6. boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
  7. isSingletonCurrentlyInCreation(beanName));
  8. if (earlySingletonExposure) {
  9. if (logger.isDebugEnabled()) {
  10. logger.debug("Eagerly caching bean '" + beanName +
  11. "' to allow for resolving potential circular references");
  12. }
  13. //将刚实例化好的bean添加到一级缓存中
  14. addSingletonFactory(beanName, new ObjectFactory
  15. @Override
  16. public Object getObject()throws BeansException {
  17. //执行拓展的后置处理器
  18. return getEarlyBeanReference(beanName, mbd, bean);
  19. }
  20. });
  21. }
  22. }

getEarlyBeanRerence方法

  1. protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
  2. Object exposedObject = bean;
  3. //判读我们容器中是否有InstantiationAwareBeanPostProcessors类型的后置处理器
  4. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
  5. //获取我们所有的后置处理器
  6. for (BeanPostProcessor bp : getBeanPostProcessors()) {
  7. //判断我们的后置处理器是不是实现了SmartInstantiationAwareBeanPostProcessor接口
  8. if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
  9. //进行强制转换
  10. SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
  11. //挨个调用SmartInstantiationAwareBeanPostProcessor的getEarlyBeanReference
  12. exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
  13. }
  14. }
  15. }
  16. return exposedObject;
  17. }

扩展实例code

  1. @Component
  2. public class TulingBPP implements SmartInstantiationAwareBeanPostProcessor {
  3. public Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
  4. if(beanName.equals("instanceA") || beanName.equals("instanceB")) {
  5. JdkDynimcProxy jdkDynimcProxy = new JdkDynimcProxy(bean);
  6. return jdkDynimcProxy.getProxy();
  7. }
  8. return bean;
  9. }
  10. }

还得自己多看code
源码入口:
// 初始化剩下的单实例(非懒加载的)
finishBeanFactoryInitialization(beanFactory);