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就可以了。

2.2 判断这个beanName的bean是否已经创建了,代码如下:

Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			……
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

这里判断是否已经存在这个bean信息,如果已经存在,那么直接拿过来就可以了。不需要再次进行创建。这里传递的参数为true,表示将会在临时存储singletonFactories中寻找对象,并将对象放入临时对象earlySingletonObjects中。

2.3 尝试从父容器中寻找,这一点和classLoader的父子加载机制相同。代码如下所示:

BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				String nameToLookup = originalBeanName(name);
					return (T) parentBeanFactory.getBean(nameToLookup, args);
……
			}

注意这里首先进行了判断,父容器不能为null,其次在当前容器中不存在这个bean。如果当前容器存在的话(通过containsBeanDefinition判断),则直接从当前容器取。这两个判断,表明了当前容器肯定不存在指定的bean,那么只能从父容器取了,如果父容器再取不到,那么就肯定没有要创建的bean了,报异常吧。

2.4 进行创建标记,以避免重复创建,并且后续会使用此标记信息,同时标记这个bean已经被创建了,即已经被getBean至少调用过一次了。代码如下

if (!typeCheckOnly) {
	markBeanAsCreated(beanName);
	}

2.5 开始寻找bean定义信息,并针对bean定义进行验证,如下面代码所示:

final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
			checkMergedBeanDefinition(mbd, beanName, args);
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
		return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
	}

这里会对bean信息进行一个封装,主要是处理parent信息和scope信息。将这些信息进行一次定义融合。同时接下来对bean进行检查,首先这个bean不能是abstract的,因为abstract的bean定义不能被实例化,只能由其它bean继承。然后,在传递的参数不为null的情况下,要求只能处理prototype类型的bean。因为,如果不是prototype,无需传递参数,因为bean已经在第一次创建时确定,后续获取不能够改变原有bean信息。除了prototype类型才可以,后者为每一次请求都会创建新的对象。

2.6 处理依赖信息,这里会针对xml定义中的depends-on进行处理。如下面代码所示:

String[] dependsOn = mbd.getDependsOn();
			if (dependsOn != null) {
				for (String dependsOnBean : dependsOn) {
					getBean(dependsOnBean);
					registerDependentBean(dependsOnBean, beanName);
				}
			}

这里会触发对dependOn bean的创建。如A->B,表示A依赖于B,那么在创建A之前,必须保证B先被创建。
在创建了B之后,这里会进行依赖信息存储。信息会存储于两个地方,一是dependentBeanMap,存储为B-A,表示B被A依赖。另一个是dependenciesForBeanMap,存储为A-B,表示A依赖于B。这相当于是一个双向map,只不过通过两个map来存储。

2.7 调用getSingleton(String beanName, ObjectFactory singletonFactory),最终会触发objectFactory的getObject方法,即调用createBean(beanName, mbd, args)方法进行bean创建。代码如下所示:

sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
					public Object getObject() throws BeansException {
							return createBean(beanName, mbd, args);
					});
public Object getSingleton(String beanName, ObjectFactory singletonFactory) {
singletonObject = singletonFactory.getObject();
addSingleton(beanName, singletonObject);//添加到已成功创建列表中
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}

这里面省略了中间过程,如beforeSingletonCreation和afterSingletonCreation等,这主要是进行创建时验证。这时主要逻辑转向类AbstractAutowireCapableBeanFactory的protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)方法。

3 createBean

3.1 解析beanDefinition,以确保bean定义中的class可以被正确解析,这通过以下代码处理:

resolveBeanClass(mbd, beanName);

3.2 给InstantiationAwareBeanPostProcessor机会用于创建代理类,这通过以下代码完成

Object bean = resolveBeforeInstantiation(beanName, mbd);

在一般情况下,此方法会返回null。因为,此创建直接忽略了beanFactory的创建流程,而直接由InstantiationAwareBeanPostProcessor来进行创建。在本例中,返回结果为null。但有些例外,如创建proxy对象,如针对于AbstractSingletonProxyFactoryBean这个bean定义,这个完全可以通过InstantiationAwareBeanPostProcessor来创建,而不需要处理其他信息,因为目标对象已经在mdb中定义了。

3.3 进入实质性的创建bean阶段,这里需要调用以下代码来完成:

Object beanInstance = doCreateBean(beanName, mbd, args);

这就需要进入第4阶段
见下篇

转载请标明出处:i flym
本文地址:https://www.iflym.com/index.php/code/201208290001.html

相关文章:

作者: flym

I am flym,the master of the site:)

发表评论

邮箱地址不会被公开。 必填项已用*标注