Spring中获取一个bean的流程-2

上篇,进入第4节,实质性地创建一个Bean信息。

4 doCreateBean

4.1 首先创建一个原始对象的包装对象,即BeanWrapper,这通过对bean进行包装而来,如下代码所示:

instanceWrapper = createBeanInstance(beanName, mbd, args);

在这个createBeanInstance方法中,首先会创建原始对象,这就有几个策略。如下所示:
如果存在工厂方法,即在xml中定义了factory-method,就会调用工厂方法进行创建,代码如下所示:

if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

如果已经确认或者解析了候选构造方法,则调用此方法进行创建

if (resolved) {
			if (autowireNecessary) {
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				return instantiateBean(beanName, mbd);
			}
		}

如果存在SmartInstantiationAwareBeanPostProcessor并且对象解析出指定的bean Class有候选的构造方法,如在构造方法上追加@Autowired的话,会优化使用这个构造方法。
最后,采用默认的构造策略进行对象创建,如调用Class.newInstance()方法创建。

继续阅读“Spring中获取一个bean的流程-2”

Spring中获取一个bean的流程-1

本文从ClasspathXmlApplication进行入手,未考虑针对于Annotation的处理,仅从xml方向对getBean进行代码追踪,以形成一个完整的链条。以下代码从取得一个singleton对象入手进行分析。

1 获取Bean信息

1.1 首先这里会调用AbstractApplicationContext.getBean(String name),这个方法直接会转向1.2
1.2 进入方法AbstractBeanFactory.getBean(String name),这个方法会直接进入1.3
1.3 进入方法AbstractBeanFactory.doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)。这个方法是获取bean的主要入口。此方法的详细叙述在第2节

2 doGetBean信息

2.1 首先这里会将传入的beanName进行转化。代码如下所示:

		final String beanName = transformedBeanName(name);
protected String transformedBeanName(String name) {
		return canonicalName(BeanFactoryUtils.transformedBeanName(name));
	}

转化有两个步骤,首先处理beanName为&XXX的格式,这里表示要取指定name的factoryBean。在这里先把&符号取消,先获取bean再处理。然后,针对bean的alias机制,这里传入的参数可能是一个bean别名,那么我们先获取这个bean的主要id,只需要根据id值取bean就可以了。

继续阅读“Spring中获取一个bean的流程-1”

Spring中循环引用的处理-3

上文中对调用点A和调用点B的调用方法进行了陈述。接下来,针对创建bean的不同顺序对调用点和调用方法进行分析。

在正常的情况下,调用顺序如下:以下有无,表示是否持有对指定Bean的引用

  singletonFactories earlySingletonObjects singletonObjects
getSingleton(beanName, true)
doCreateBean(beanName,mdb,args)
getSingleton(beanName, true);
addSingleton(beanName, singletonObject)

但是出现循环引用之后呢,就会出现这种情况:

  singletonFactories earlySingletonObjects singletonObjects
getSingleton(A, true); A无B无 A无B无 A无B无
doCreateBean(A,mdb,args) A有B无 A无B无 A无B无
       
populateBean(A, mbd, instanceWrapper) 解析B……  
getSingleton(B, true) A有B无 A无B无 A无B无
doCreateBean(B,mdb,args) A有B有 A无B无 A无B无
populateBean(B, mbd, instanceWrapper)由B准备解析A……  
getSingleton(A, true) A无B有 A有B无 A无B无
完成populateBean(B, mbd, instanceWrapper)解析……  
addSingleton(B, singletonObject) A无B无 A有B无 A无B有
完成populateBean(A, mbd, instanceWrapper)  
       
A- = initializeBean(beanName, exposedObject, mbd)在initializeBean之后A变为A-  
getSingleton(A, false);验证  
addSingleton(A, singletonObject)    ……  

在上面这个过程中,在对A进行验证时,就会从earlySingletonObjects中取得一个A,但是这个A和后面的A-可能不是同一个对象,这是因为有了beanPostProcessor存在,它可以改变bean的最终值,比如对原始bean进行封装,代理等。在这个过程中,出现了3个对象A,A-,B,而B中所持有的A对象为原始的A。如果这里的A和A-不是同一个对象,即产生了beanA有了beanB的引用,但beanB并没有beanA的引用,而是另一个beanA的引用。这肯定不满足条件。

继续阅读“Spring中循环引用的处理-3”

Spring中循环引用的处理-2

上文中对涉及到循环引用的3个方法作了陈述。

在方法1中,对象信息对beanFactory的形式被放入singletonFactories中,这时earlySingletonObjects中肯定没有此对象(因为remove)。

在方法2中,在一定条件下(allowEarlyReference为true)的条件下,对象从singleFactories中的objectFactory中被取出来,同时remove掉,被放入earlySingletonObjects中。这时,earlySingletonObjects就持有对象信息了;当然,如果allowEarlyReference为false的情况下,且earlySingletonObjects本身就没有持有对象的情况下,肯定不会将对象从objectFactory中取出来的。这个很重要,因为后面将根据此信息进行循环引用处理。

在方法3中,对象被加入到singletonObjects中,同时singletonFactories和earlySingletonObjects中都remove掉持有的对象(不管持有与否),这就表示在之前的处理中,这只相当于一个临时容器,处理完毕之后都会remove掉。

继续阅读“Spring中循环引用的处理-2”

Spring中循环引用的处理-1

在使用spring的场景中,有时会碰到如下的一种情况,即bean之间的循环引用。即两个bean之间互相进行引用的情况。这时,在spring xml配置文件中,就会出现如下的配置:

<bean id="beanA" class="BeanA" p:beanB-ref="beaB"/>
<bean id="beanB" class="BeanB" p:beanA-ref="beaA"/>

并且,在一般情况下,这个配置在现有的spring3.0中是可以正常工作的,前提是没有对beanA和beanB进行增强。但是,如果任意一方进行了增强,比如通过spring的代理对beanA进行了增强,即实际返回的对象和原始对象不一致的情况,在这种情况下,就会报如下一个错误:

"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."

这个错误即对于一个bean,其所引用的对象并不是由spring容器最终生成的对象,而只是一个原始对象,而spring不允许这种情况出现,即持有过程中间对象。那么,这个错误是如何产生的,以及在spring内部,是如何来检测这种情况的呢。这就得从spring如何创建一个对象,以及如何处理bean间引用,以及spring使用何种策略处理循环引用问题说起。

继续阅读“Spring中循环引用的处理-1”