spring循环依赖
出现循环依赖的情况
1 // setter方式注入 2 @Component("A") 3 public static class A { 4 5 @Autowired 6 private B b; 7 } 8 9 @Component("B") 10 public static class B { 11 12 @Autowired 13 private A a; 14 } 15 //构造器方式注入 16 @Component("A") 17 public static class A { 18 19 private final B b; 20 21 @Autowired 22 public A(B b) { 23 this.b = b; 24 } 25 } 26 27 @Component("B") 28 public static class B { 29 30 private final A a; 31 32 @Autowired 33 public B(A a) { 34 this.a = a; 35 } 36 }
如上代码所示,两个bean之间互相注入即为循环依赖。
废话不多说,实验对象时两个bean,实验变量有三个:
1. 注入方式:setter注入、构造器注入
2. 是否是懒加载
3. 是否是单例
每个变量有四种情况,一共4x4x4=64种情况先说结论:
1. 如果采用构造器方式注入,必然会出现循环依赖问题。
2. 如果采用setter方式注入,结论如下:
1)如果bean都不是单例,注入失败
2)如果bean都是单例,注入成功
3)如果bean一个是单例一个是非单例(prototype)且非单例bean比单例bean先创建,注入失败,否则注入成功(对应代码就是单例bean是懒加载,spring容器启动不会创建prototype的bean,如果程序先使用prototype的bean,那么注入会失败)
3. 如果一个采用构造器注入一个采用setter注入,一共3x4x4=48种情况,情况太多,无法罗列,但是无妨。理解原理才是理工科的重点,结论只是检验理解的工具。
原因分析
首先看一下涉及到的几个属性对象在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory以及org.springframework.beans.factory.support.AbstractBeanFactory中。
1 /** Cache of singleton objects: bean name to bean instance. */ 2 /** 已初始化完成的单例bean,key为beanName,value为bean实例 **/ 3 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); 4 5 /** Cache of singleton factories: bean name to ObjectFactory. */ 6 /** 未初始化完成的bean,key为beanName,value为创建bean实例的方法**/ 7 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); 8 9 /** Cache of early singleton objects: bean name to bean instance. */ 10 /** 未初始化完成的bean,key为beanName,value为bean实例**/ 11 private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); 12 13 /** Names of beans that are currently in creation. */ 14 /** 正在创建的单例bean的name **/ 15 private final Set<String> singletonsCurrentlyInCreation = 16 Collections.newSetFromMap(new ConcurrentHashMap<>(16)); 17 18 /** Names of beans that are currently in creation. */ 19 /** 正在创建的prototype bean的name **/ 20 private final ThreadLocal<Object> prototypesCurrentlyInCreation = 21 new NamedThreadLocal<>("Prototype beans currently in creation");:
首先是获取bean的方法:org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean()方法:
1 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) 2 throws BeanCreationException { 3 4 // Instantiate the bean. 5 BeanWrapper instanceWrapper = null; 6 if (mbd.isSingleton()) { 7 instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); 8 } 9 if (instanceWrapper == null) { 10 // 具体创建bean实例的方法 11 instanceWrapper = createBeanInstance(beanName, mbd, args); 12 } 13 final Object bean = instanceWrapper.getWrappedInstance(); 14 Class<?> beanType = instanceWrapper.getWrappedClass(); 15 // 部分代码省略 16 // Eagerly cache singletons to be able to resolve circular references 17 // even when triggered by lifecycle interfaces like BeanFactoryAware. 18 // 如果bean是单例&&允许重复引用(默认为true)&& 当前bean正在创建中 19 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && 20 isSingletonCurrentlyInCreation(beanName)); 21 if (earlySingletonExposure) { 22 // 将bean添加到singletonFactories中 23 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); 24 } 25 26 // Initialize the bean instance. 27 Object exposedObject = bean; 28 try { 29 // 计算bean的依赖,其作用是将依赖的bean注入到当前bean中(不存在则创建) 30 populateBean(beanName, mbd, instanceWrapper); 31 // 初始化当前bean中的其他属性值 32 exposedObject = initializeBean(beanName, exposedObject, mbd); 33 } 34 catch (Throwable ex) { 35 if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { 36 throw (BeanCreationException) ex; 37 } 38 else { 39 throw new BeanCreationException( 40 mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); 41 } 42 } 43 // 省略部分代码 44 return exposedObject; 45 }
创建bean实例的方法:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBeanInstance()方法:
1 protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { 2 // Make sure bean class is actually resolved at this point. 3 Class<?> beanClass = resolveBeanClass(mbd, beanName); 4 // 省略部分代码 5 6 // Shortcut when re-creating the same bean... 7 boolean resolved = false; 8 boolean autowireNecessary = false; 9 if (args == null) { 10 synchronized (mbd.constructorArgumentLock) { 11 if (mbd.resolvedConstructorOrFactoryMethod != null) { 12 resolved = true; 13 autowireNecessary = mbd.constructorArgumentsResolved; 14 } 15 } 16 } 17 if (resolved) { 18 if (autowireNecessary) { 19 /** 20 bean没有无参构造函数时使用此方法实例化, 21 如果构造函数中有依赖的bean,则创建此bean并注入 22 返回实例化后的bean 23 **/ 24 return autowireConstructor(beanName, mbd, null, null); 25 } 26 else { 27 /** 28 使用无参的构造函数时使用此方法实例化 29 返回实例化后的bean 30 **/ 31 return instantiateBean(beanName, mbd); 32 } 33 } 34 35 // Candidate constructors for autowiring? 36 Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); 37 if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || 38 mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { 39 return autowireConstructor(beanName, mbd, ctors, args); 40 } 41 42 // Preferred constructors for default construction? 43 ctors = mbd.getPreferredConstructors(); 44 if (ctors != null) { 45 return autowireConstructor(beanName, mbd, ctors, null); 46 } 47 48 // No special handling: simply use no-arg constructor. 49 return instantiateBean(beanName, mbd); 50 }
将上面的代码转换成流程图,获取bean的主要流程图如下:
创建bean的主要流程图如下:
经过上面的分析之后我们知道,在获取单例bean时会先从缓存中获取bean,获取到了则返回,未获取到才创建。在创建bean时,如果是单例bean,则他会在注入依赖之前先将自己未初始化的bean存入到缓存中。经过上面两步,循环依赖就解决了。
现在来分析一下一些结论:
1. 为什么bean都是非单例就不行?
原因已经显而易见了,因为只有单例bean才会将其放入缓存中。
2. 构造器注入跟setter注入的区别?
setter注入是先创建完bean,然后将bean放入缓存,最后注入依赖;而构造器注入是在创建bean之前先获取依赖,如果依赖没有在缓存中或者创建,则创建依赖bean,依赖bean又会去创建当前bean,所以失败。
3. 为什么懒加载会影响循环依赖的结果?
循环依赖的根本问题其实就是加载顺序的问题,比如类A是单例懒加载,类B是prototype立即加载,都采用setter注入。那么启动会报错,因为创建B需要A,因为A懒加载所以缓存中不存在,需要新建,创建A又需要B,因为B不是单例,所以缓存中不存在B,B也会新建,产生了循环依赖问题。
而如果类B也是懒加载的话,如果你先获取B则会报错,先获取A则不会报错,这就是加载顺序的问题。而懒加载就会影响到加载顺序。