标签:
所谓的循环引用,就是A依赖B,B又依赖A,A与B两个对象相互持有。像下面这种情况:
class A { B b; public A(B b) { this.b=b; } } class B { A a; public B(A a ) { this.a=a; } }我们知道spring在获取对象或者在加载的时候,触发依赖注入。例如触发A对象的依赖注入,发现需要B对象,而此时B还没有初始化,就去实例化B对象,而又需要A对象,这样就进入了一种死循环状态,有点像操作系统里面的死锁。似乎这种情况发生了,Spring就陷入僵局了。显然Spring有方法去解决这个问题。对于依赖注入的情况,大致分为构造注入和设值注入两种方式,而实际上因为Spring注入的触发机制不一样,这个问题又被分为singleton对象和prototype(其他三个作用域大致相同)对象的区别。我们可以把问题大致分为三类。
这种依赖Spring是无法给你解决的,将会抛出BeanCurrentlyInCreationException异常。来看一下测试代码
(1) 定义两个类 A,B 构成构造成循环依赖的情况
class A { B b; public A(B b) { this.b=b; } } class B { A a; public B(A a ) { this.a=a; } }
<bean id="xiaoA" class="com.songxu.learn.A"> <constructor-arg name="b" ref="xiaoB" /> </bean> <bean id="xiaoB" class="com.songxu.learn.B"> <constructor-arg name="a" ref="xiaoA" /> </bean>
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); <span style="font-size:18px;"> </span>(4) 结果抛出了异常,来看一下日志输出
2015-08-01 02:39:15,869>>>>[org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] >>>>Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@2ef5e5e3: defining beans [xiaoA,xiaoB]; root of factory hierarchy 2015-08-01 02:39:15,869>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'xiaoA' 2015-08-01 02:39:15,869>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'xiaoA' 2015-08-01 02:39:15,889>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'xiaoB' 2015-08-01 02:39:15,889>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'xiaoB' 2015-08-01 02:39:15,889>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'xiaoA' 2015-08-01 02:39:15,889>>>>[org.springframework.context.support.AbstractApplicationContext]-[WARN] >>>>Exception encountered during context initialization - cancelling refresh attempt org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xiaoA' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'xiaoB' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xiaoB' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'xiaoA' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'xiaoA': Requested bean is currently in creation: Is there an unresolvable circular reference?
对于设值注入的情况,循环依赖是可以完成的。来看一下测试代码。
(1) 构造两个类 A,B 构成循环依赖,并且使用设值注入的方式。
class CircleA { private CircleB b; public CircleA(CircleB b) { this.b=b; } public CircleB getB() { return b; } public void setB(CircleB b) { this.b = b; } public CircleA() { } } class CircleB { private CircleA a; public CircleA getA() { return a; } public void setA(CircleA a) { this.a = a; } public CircleB(CircleA a) { this.a=a; } public CircleB() { } }
<bean id="circleA" class="com.songxu.learn.CircleA" > <property name="b" ref="circleB"></property> </bean> <bean id="circleB" class="com.songxu.learn.CircleB" > <property name="a" ref="circleA"></property> </bean>
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
2015-08-01 03:41:32,302>>>>[org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] >>>>Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@100fc185: defining beans [circleA,circleB]; root of factory hierarchy 2015-08-01 03:41:32,302>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'circleA' 2015-08-01 03:41:32,302>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleA' 2015-08-01 03:41:32,312>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'circleA' to allow for resolving potential circular references 2015-08-01 03:41:32,312>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'circleB' 2015-08-01 03:41:32,312>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleB' 2015-08-01 03:41:32,312>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'circleB' to allow for resolving potential circular references 2015-08-01 03:41:32,312>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning eagerly cached instance of singleton bean 'circleA' that is not fully initialized yet - a consequence of a circular reference 2015-08-01 03:41:32,322>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleB' 2015-08-01 03:41:32,322>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleA' 2015-08-01 03:41:32,322>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning cached instance of singleton bean 'circleB'这个过程是这样的,A构造空对象放入缓存池中(暂且称为A空),触发了B对象注入,然后去构造B对象,又触发了对A对象的注入,这个时候缓存中已经有一个空的A对象,就把A空对象注入给B,然后B构造完成,返回给A,这时A对象已经完成了注入。而同时B中持有的A对象也不再是A空了,因为A是单例的,且A完成了注入,此时A=A空。也就完成了整个注入过程。
依然设置A,B两个类,构成循环依赖,A采用设值注入B,B采用构造器注入A。对于这种情况,Spring是可以完成注入的。来查看示例代码
(1) 构造两个类 A,B 构成循环依赖关系,A采用设值注入B,B采用构造器注入A
class A { B b; public B getB() { return b; } public void setB(B b) { this.b = b; } } class B { A a; public B(A a ) { this.a=a; } }
<bean id="xiaoA" class="com.songxu.learn.A"> <constructor-arg name="b" ref="xiaoB" /> </bean> <bean id="xiaoB" class="com.songxu.learn.B"> <constructor-arg name="a" ref="xiaoA" /> </bean>
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); <span style="font-size:18px;"> </span>(4) 结果正常,A,B注入完成,查看一下日志输出
2015-08-01 04:00:32,884>>>>[org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] >>>>Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@6d00a15d: defining beans [xiaoA,xiaoB]; root of factory hierarchy 2015-08-01 04:00:32,884>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'xiaoA' 2015-08-01 04:00:32,884>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'xiaoA' 2015-08-01 04:00:32,894>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'xiaoA' to allow for resolving potential circular references 2015-08-01 04:00:32,904>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'xiaoB' 2015-08-01 04:00:32,904>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'xiaoB' 2015-08-01 04:00:32,904>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning eagerly cached instance of singleton bean 'xiaoA' that is not fully initialized yet - a consequence of a circular reference 2015-08-01 04:00:32,914>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'xiaoB' to allow for resolving potential circular references 2015-08-01 04:00:32,914>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'xiaoB' 2015-08-01 04:00:32,924>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'xiaoA' 2015-08-01 04:00:32,924>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning cached instance of singleton bean 'xiaoB'
两个类构成循环依赖并且需要完成Spring注入的唯一条件是,可以构造一个空的对象放入缓存,否则将会失败。而这种空对象的构造必须采用设值注入的方式。在后面将给出深度解析。
依然采用上面的三种情况去分析
(1)类与上面的一样,只是配置文件稍作修改
<bean id="xiaoA" class="com.songxu.learn.A" scope="prototype"> <constructor-arg name="b" ref="xiaoB" /> <!-- <property name="b" ref="xiaoB"></property> --> </bean> <bean id="xiaoB" class="com.songxu.learn.B" scope="prototype"> <constructor-arg name="a" ref="xiaoA" /> </bean>
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); A xiaoA=(A)applicationContext.getBean("xiaoA");
2015-08-01 04:09:31,425>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'xiaoA' 2015-08-01 04:09:31,435>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'xiaoB' Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xiaoA' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'xiaoB' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'xiaoB' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'xiaoA' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'xiaoA': Requested bean is currently in creation: Is there an unresolvable circular reference?
(1)类与上面的一样,只是配置文件稍作修改
<span style="font-size:18px;"><bean id="circleA" class="com.songxu.learn.CircleA" scope="prototype"> <property name="b" ref="circleB"></property> </bean> <bean id="circleB" class="com.songxu.learn.CircleB" scope="prototype" > <property name="a" ref="circleA"></property> </bean> </span>
<span style="font-size:18px;">ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); CircleB b=(CircleB)applicationContext.getBean("circleB"); </span>
2015-08-01 04:13:29,505>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleB' 2015-08-01 04:13:29,515>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleA' Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'circleB' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'circleA' while setting bean property 'a'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'circleA' defined in class path resource [applicationContext.xml]: Cannot resolve reference to bean 'circleB' while setting bean property 'b'; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'circleB': Requested bean is currently in creation: Is there an unresolvable circular reference?
测试代码与上面类似,结果同样是无法完成注入,抛出BeanCurrentlyInCreationException异常。
对于prototype来说,只有存在循环引用的情况,是无法完成注入的。
这种混合模式在某些情况下是成立的。这里只给出一种成功的案例,其他模式下无法完成。这一成功的类型是AB两个类都采用设值注入的方式。
(1) 构造A ,B两个类,构成循环依赖关系
class CircleA { private CircleB b; public CircleB getB() { return b; } public void setB(CircleB b) { this.b = b; } public CircleA() { } } class CircleB { private CircleA a; public CircleB() { } public CircleA getA() { return a; } public void setA(CircleA a) { this.a = a; } }
<bean id="circleA" class="com.songxu.learn.CircleA" scope="prototype" > <property name="b" ref="circleB"></property> </bean> <bean id="circleB" class="com.songxu.learn.CircleB" > <property name="a" ref="circleA"></property> </bean>
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); CircleA A=(CircleA)applicationContext.getBean("circleA"); CircleB B=(CircleB)applicationContext.getBean("circleB"); System.out.println(A==B.getA());
2015-08-01 04:45:08,952>>>>[org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] >>>>Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@100fc185: defining beans [circleA,circleB]; root of factory hierarchy 2015-08-01 04:45:08,952>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'circleB' 2015-08-01 04:45:08,952>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleB' 2015-08-01 04:45:08,962>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'circleB' to allow for resolving potential circular references 2015-08-01 04:45:08,962>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleA' 2015-08-01 04:45:08,962>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning eagerly cached instance of singleton bean 'circleB' that is not fully initialized yet - a consequence of a circular reference 2015-08-01 04:45:08,972>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleA' 2015-08-01 04:45:08,972>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleB' 2015-08-01 04:45:08,972>>>>[org.springframework.context.support.AbstractApplicationContext]-[DEBUG] >>>>Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@1dfe2924] 2015-08-01 04:45:08,972>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning cached instance of singleton bean 'lifecycleProcessor' 2015-08-01 04:45:08,982>>>>[org.springframework.core.env.PropertySourcesPropertyResolver]-[DEBUG] >>>>Searching for key 'spring.liveBeansView.mbeanDomain' in [systemProperties] 2015-08-01 04:45:08,982>>>>[org.springframework.core.env.PropertySourcesPropertyResolver]-[DEBUG] >>>>Searching for key 'spring.liveBeansView.mbeanDomain' in [systemEnvironment] 2015-08-01 04:45:08,982>>>>[org.springframework.core.env.PropertySourcesPropertyResolver]-[DEBUG] >>>>Could not find key 'spring.liveBeansView.mbeanDomain' in any property source. Returning [null] init finished============================================ 2015-08-01 04:45:08,982>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleA' 2015-08-01 04:45:08,982>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning cached instance of singleton bean 'circleB' 2015-08-01 04:45:08,982>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleA' 2015-08-01 04:45:08,982>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning cached instance of singleton bean 'circleB' false
下面的示意图大致显示了这个过程的关键步骤,关于细节的代码,可以查看另一篇博客。
这个图中的数字标识了各个过程,红色填图的区域表示关键步骤,黄色填图的区域为logger日志输出内容,虚线边框代表一个方法的内部。
下面是一段 singleon对象循环引用的日志输出。用来配合理解这个过程
2015-08-01 09:51:34,966>>>>[org.springframework.beans.factory.support.DefaultListableBeanFactory]-[DEBUG] >>>>Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@100fc185: defining beans [circleA,circleB]; root of factory hierarchy 2015-08-01 09:51:34,966>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'circleA' 2015-08-01 09:51:34,966>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleA' A开始初始化 2015-08-01 09:51:34,976>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'circleA' to allow for resolving potential circular references 2015-08-01 09:51:34,976>>>>[org.springframework.beans.factory.support.DefaultSingletonBeanRegistry]-[DEBUG] >>>>Creating shared instance of singleton bean 'circleB' 2015-08-01 09:51:34,976>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Creating instance of bean 'circleB' B开始初始化 2015-08-01 09:51:34,976>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Eagerly caching bean 'circleB' to allow for resolving potential circular references 2015-08-01 09:51:34,976>>>>[org.springframework.beans.factory.support.AbstractBeanFactory]-[DEBUG] >>>>Returning eagerly cached instance of singleton bean 'circleA' that is not fully initialized yet - a consequence of a circular reference B开始注入 B完成注入 2015-08-01 09:51:34,986>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleB' A开始注入 A完成注入 2015-08-01 09:51:34,986>>>>[org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory]-[DEBUG] >>>>Finished creating instance of bean 'circleA'
在DefaultSingletonBeanRegistry类中,定义了一些属性,它决定着整个依赖注入过程的关键步骤跳转,同时也伴随着整个bean的关键周期.
/** 保存所有的singletonBean的实例 */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64); /** singletonBean的生产工厂*/ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16); /** 保存所有早期创建的Bean对象,这个Bean还没有完成依赖注入 */ private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16); /** 保存所有已经完成初始化的Bean的名字(name) */ private final Set<String> registeredSingletons = new LinkedHashSet<String>(64); /** 标识指定name的Bean对象是否处于创建状态 这个状态非常重要 */ private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));
singleton的创建开始于getBean方法,关于这个流程,可以查看另外一篇博客。这个方法调用了doGetBean方法,也是示意图中最顶端的方法,这是创建singleton的开始。
整个过程的源码很多,这里仅截取与singleton创建相关的部分
(1)图中1号代码getSingleton
protected Object getSingleton(String beanName, boolean allowEarlyReference) { //在已经完成创建的singleton集合中查找 Object singletonObject = this.singletonObjects.get(beanName); //如果没有找到 并且还处于当前创建状态,就应该可以找到earlyReference if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName);//在earlyReference查找 if (singletonObject == null && allowEarlyReference) { //如果还没有找到,就去找对应的工厂方法,这里与9号代码回应。 //如果创建了空的Bean的话,在此处一定能拿到对应的工厂 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject();//在这获得对应的earlyBean this.earlySingletonObjects.put(beanName, singletonObject);//放入earlyBeanObjects集合中 this.singletonFactories.remove(beanName);//移除工厂方法 } } } } return (singletonObject != NULL_OBJECT ? singletonObject : null); }
// Eagerly check singleton cache for manually registered singletons. Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) { if (logger.isDebugEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); } } bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); }
if (mbd.isSingleton()) { //注册工厂 调用另一个getSingleton sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { try { //创建Bean的实际方法 return createBean(beanName, mbd, args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process, to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); }
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { //非空校验 Assert.notNull(beanName, "'beanName' must not be null"); synchronized (this.singletonObjects) { Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while the singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); } //前置处理 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<Exception>(); } try { //调用工程方法 singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // Has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } //后置处理 afterSingletonCreation(beanName); } if (newSingleton) { addSingleton(beanName, singletonObject); } } return (singletonObject != NULL_OBJECT ? singletonObject : null); } }
protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } }
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { //... if (instanceWrapper == null) { //创建Bean的实际方法 instanceWrapper = createBeanInstance(beanName, mbd, args); } //... boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } //注册getEaryBean的工厂方法 addSingletonFactory(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } }); } // Initialize the bean instance. Object exposedObject = bean; try { //开始依赖注入 触发getBean方法 populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { exposedObject = initializeBean(beanName, exposedObject, mbd); } } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex); } } //... return exposedObject; }
(7 )createBeanInstance方法,实际创建Bean的方法
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) { //... // 在这里去匹配合适的构造方法,如果存在构造注入,需要找到所有的注入的值,触发getBean Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } // No special handling: simply use no-arg constructor. return instantiateBean(beanName, mbd); }
通过上面的分析,已经基本可以看出设值注入与构造注入的区别在哪里,就是触发getBean递归的时机不一致,导致1号的getSingleton的结果不一样。
对于设值注入来说,首先进入getA的getBean,此时getSingleton返回null,进入Bean的创建阶段,此时采用设值注入,构造默认的空的Bean,并注册一个工厂方法,然后依赖注入,getBean的时候触发了对B的构造过程,与A一样,构造默认的空的Bean,并注册一个工厂方法,然后依赖注入,这时需要A,第二次进入A的getBean流程,而此时因为存在工厂方法,所以1号的getSingleton不再返回空,这样就返回了一个Earlybean对象注入到B中;然后B完成注入,接着A完成注入。
对于构造注入来说,首先进入getA的getBean,此时getSingleton返回null,进入Bean的创建阶段,此时采用构造注入,在查找注入参数的时候,就触发了B的getBean方法,注意此时并没有注册工厂方法,B的创建流程开始,采用构造注入,查找注入参数,第二次进入A的getBean方法,因为没有提供可以拿到earlyBean的工厂方法,1号getSingleton将返回空,此时将再次进入红色方法区,再次调用4号方法时,就会抛出重复创建的异常。
对于混合方式来说,因为其中之一采用设值注入,再第二个进入这个对象的getBean方法的时候,总会得到earlyBean,因此不会抛出异常,也就可以完成创建。
在此可以得出结论,Spring对于循环引用的解决方案就是暴露一个ObjectFactroy,对于未创建完成的Bean,可以通过这个工厂得到一个earlyBean保证“锁”被释放,完成流程。而可以暴露这个ObjectFactory的唯一条件就是必须采用设值注入,以保证可以提前构造一个空的earlyBean。
相对于singleton来说,prototype就简单的多,由于方法名都类似,在这直接给出整个流程的代码。
(1) 关键属性 只有一个,保存着正在创建的prototype的beanName
/** Names of beans that are currently in creation */ private final ThreadLocal<Object> prototypesCurrentlyInCreation = new NamedThreadLocal<Object>("Prototype beans currently in creation");
//流程1 检验当前的bean是否处于 // Fail if we're already creating this bean instance: // We're assumably within a circular reference. if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } //流程2 创建Bean else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. Object prototypeInstance = null; try { //前置处理 beforePrototypeCreation(beanName); //创建流程的开始 prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); }
前置处理看着挺复杂,其实就是把每个正在创建的prototype的BeanName放入一个set中
protected void beforePrototypeCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); if (curVal == null) { this.prototypesCurrentlyInCreation.set(beanName); } else if (curVal instanceof String) { Set<String> beanNameSet = new HashSet<String>(2); beanNameSet.add((String) curVal); beanNameSet.add(beanName); this.prototypesCurrentlyInCreation.set(beanNameSet); } else { Set<String> beanNameSet = (Set<String>) curVal; beanNameSet.add(beanName); } }
protected boolean isPrototypeCurrentlyInCreation(String beanName) { Object curVal = this.prototypesCurrentlyInCreation.get(); return (curVal != null && (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>) curVal).contains(beanName)))); }
从流程上就可以查看,无论是构造注入还是设值注入,第二次进入同一个Bean的getBean方法是,一定会在校验部分抛出异常,因此不能完成注入,也就不能实现循环引用。
版权声明:本文为博主原创文章,未经博主允许不得转载。
Spring 循环引用 ——理解singleton与prototype初始化的区别
标签:
原文地址:http://blog.csdn.net/u010723709/article/details/47185959