spring针对循环依赖问题 不能完全解决 对于不能解决的只能检测到并抛出异常
1. spring针对构造器方法的 单实例对象和原型对象是无法解决循环依赖问题的
先说结论,
针对单例对象 getSingleton方法中 有个beforeSingletonCreation 方法 这个方法是用来检测循环依赖的
原型对象 isPrototypeCurrentlyInCreation方法beforePrototypeCreation方法配合检测循环依赖
注: inCreationCheckExclusions和singletonsCurrentlyInCreation 是两个set
1 protected void beforeSingletonCreation(String beanName) { 2 if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { 3 throw new BeanCurrentlyInCreationException(beanName); 4 } 5 }
以AB两个单例对象举例,
1 Class A(){ 2 A(B b){ 3 } 4 } 5 6 Class B(){ 7 B(A a){ 8 } 9 }
对象A在实例化的时候(getBean方法),会先执行beforeSingletonCreation方法 吧自己的beanName放入set中,然后去执行实例化 解析构造器方法的时候发现 需要用到对象B ,所以去getBean(B)
B对象在一级缓存是没有的(因为是还未实例化),所以去创建单例B,会执行和A一样的操作,把自己的beanName放入set中,然后解析构造器的时候发现依赖A对象,去一级缓存获取是没有的(因为A对象实例化还未完成 未放入到一级缓存中)
所以去实例化A 放入set的时候 发现已经存在及会抛出异常
1 protected boolean isPrototypeCurrentlyInCreation(String beanName) { 2 Object curVal = this.prototypesCurrentlyInCreation.get(); 3 return (curVal != null && 4 (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName)))); 5 }
1 protected void beforePrototypeCreation(String beanName) { 2 Object curVal = this.prototypesCurrentlyInCreation.get(); 3 if (curVal == null) { 4 this.prototypesCurrentlyInCreation.set(beanName); 5 } 6 else if (curVal instanceof String) { 7 Set<String> beanNameSet = new HashSet<>(2); 8 beanNameSet.add((String) curVal); 9 beanNameSet.add(beanName); 10 this.prototypesCurrentlyInCreation.set(beanNameSet); 11 } 12 else { 13 Set<String> beanNameSet = (Set<String>) curVal; 14 beanNameSet.add(beanName); 15 } 16 }
对象在实例化之前会先调用isPrototypeCurrentlyInCreation方法,如果set中没有继续执行,实例化的时候调用beforePrototypeCreation方法 放入set中,在之后的循环依赖中 查询到set中有自己的beanName 则抛出异常
那么spring对set方法注入 是如何解决循环依赖问题的呢,一样先说结论 是使用第三级缓存来解决的
1. 在实例化bean A的时候 先去查看一级缓存中是否有(执行的方法getSingleton)
并且会查询currentlyCreationSet中有没有
2. 处理一下depend-on依赖 或者检查一下是否是抽象等等安全性校验
3.把单实例的A 的beanName放入currentlyCreationSet中
4. 实例化A对象因为是set注入 所以这时使用的空参构造 去反射出实例对象 得到一个早期对象(未进行属性注入的对象,未执行init方法调用,未进行后处理器处理,早期对象和处理后的对象的内存地址是一样的aop对象除外)
5. 早期实例A封装到objectFactory对象中,放入三级缓存
6. 进行依赖注入 依赖注入的时候发现依赖Bean B 再去执行getBean方法 重复执行1-6步 拿到一个B的早期对象objectFactory 放入到三级缓存
7. 处理B的依赖注入 发现B依赖了A 执行getbean方法 从1开始执行 去一级缓存查询没有 去currentlyCreationSet查询有A 去三级缓存中拿到A的早期实例 放入二级缓存清除三级缓存中的A早期实例并返回这个早期实例 B继续执行完成了B对象的实例 放入一级缓存中 清除掉二三级缓存相关数据
8. 继续执行A的实例化步骤 A完成实例化 存入一级缓存 清除二三级缓存相关数据
1 protected Object getSingleton(String beanName, boolean allowEarlyReference) { 2 Object singletonObject = this.singletonObjects.get(beanName); 3 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { 4 synchronized (this.singletonObjects) { 5 singletonObject = this.earlySingletonObjects.get(beanName); 6 if (singletonObject == null && allowEarlyReference) { 7 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); 8 if (singletonFactory != null) { 9 singletonObject = singletonFactory.getObject(); 10 this.earlySingletonObjects.put(beanName, singletonObject); 11 this.singletonFactories.remove(beanName); 12 } 13 } 14 } 15 } 16 return singletonObject; 17 }