一、问题引入:
ctx.getBean方法是如何运作的 ?
public
static
void
main(String[] args) {
ApplicationContext ctx =
new
ClassPathXmlApplicationContext(
"spring.xml"
);
TestBean testBean = ctx.getBean(
"testBean"
,TestBean.
class
);
System.out.println(testBean.getA());
}
|
二、doGetBean加载概述:
AbstractBeanFactory.doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
doGetBean()
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.判断这个beanName的bean是否已经创建了【缓存获取】,代码如下:
/** Cache of singleton objects: bean name --> bean instance */
private
final
Map<String, Object> singletonObjects =
new
ConcurrentHashMap<String, Object>(
64
);
/** Cache of singleton factories: bean name --> ObjectFactory */
private
final
Map<String, ObjectFactory<?>> singletonFactories =
new
HashMap<String, ObjectFactory<?>>(
16
);
/** Cache of early singleton objects: bean name --> bean instance */
private
final
Map<String, Object> earlySingletonObjects =
new
HashMap<String, Object>(
16
);
|
protected
Object getSingleton(String beanName,
boolean
allowEarlyReference) {
Object singletonObject =
this
.singletonObjects.get(beanName);
if
(singletonObject ==
null
) {
synchronized
(
this
.singletonObjects) {
singletonObject =
this
.earlySingletonObjects.get(beanName);
if
(singletonObject ==
null
&& allowEarlyReference) {
ObjectFactory singletonFactory =
this
.singletonFactories.get (beanName);
if
(singletonFactory !=
null
) {
singletonObject = singletonFactory.getObject();
this
.earlySingletonObjects.put(beanName, singletonObject);
this
.singletonFactories.remove(beanName);
}
}
}
}
return
(singletonObject != NULL_OBJECT ? singletonObject :
null
);
}
|
3.尝试从父容器中寻找,这一点和classLoader的父子加载机制相同。代码如下所示
BeanFactory parentBeanFactory = getParentBeanFactory();
if
(parentBeanFactory !=
null
&& !containsBeanDefinition(beanName)) {
String nameToLookup = originalBeanName(name);
if
(args !=
null
) {
return
(T) parentBeanFactory.getBean(nameToLookup, args);
}
else
{
return
parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
|
4.获取bean定义信息
final
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
|
这里会对bean信息进行一个封装,主要是处理parent信息和scope信息。将这些信息进行一次定义融合,同时接下来对bean进行检查。
5. 处理依赖信息,这里会针对xml定义中的depends-on进行处理。如下面代码所示:
String[] dependsOn = mbd.getDependsOn();
if
(dependsOn !=
null
) {
for
(String dependsOnBean : dependsOn) {
if
(isDependent(beanName, dependsOnBean)) {
throw
new
BeanCreationException(
"Circular depends-on relationship between '"
+
beanName +
"' and '"
+ dependsOnBean +
"'"
);
}
registerDependentBean(dependsOnBean, beanName);
getBean(dependsOnBean);
}
}
|
6.调用getSingleton(String beanName, ObjectFactory singletonFactory),最终会触发objectFactory的getObject方法,即调用createBean(beanName, mbd, args)方法进行bean创建。代码如下所示:
if
(mbd.isSingleton()) {
sharedInstance = getSingleton(beanName,
new
ObjectFactory<Object>() {
@Override
public
Object getObject()
throws
BeansException {
try
{
return
createBean(beanName, mbd, args);
}
catch
(BeansException ex) {
destroySingleton(beanName);
throw
ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
|
三、循环依赖
循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,比如CircleA引用CircleB,CircleB引用CircleC,CircleC引用CircleA,则它们最终反映为一个环。此处不是循环调用,循环调用是方法之间的环调用。
Spring容器循环依赖包括构造器循环依赖和setter循环依赖,那Spring容器如何解决循环依赖呢?
- 构造器循环依赖:表示通过构造器注入构成的循环依赖,此依赖是无法解决的,只能抛出BeanCurrentlyInCreationException异常表示循环依赖。
如在创建CircleA类时,构造器需要CircleB类,那将去创建CircleB,在创建CircleB类时又发现需要CircleC类,则又去创建CircleC,最终在创建CircleC时发现又需要CircleA;从而形成一个环,没办法创建。
Spring容器将每一个正在创建的Bean 标识符放在一个“当前创建Bean池”中,Bean标识符在创建过程中将一直保持在这个池中,因此如果在创建Bean过程中发现自己已经在“当前创建Bean池”里时将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的Bean将从“当前创建Bean池”中清除掉。
- setter循环依赖:表示通过setter注入方式构成的循环依赖。
对于setter注入造成的依赖是通过Spring容器提前暴露刚完成构造器注入但未完成其他步骤(如setter注入)的Bean来完成的,而且只能解决单例作用域的Bean循环依赖。
四、doCreateBean()-bean生命周期
AbstractAutowireCapableBeanFactory.createBean(String, RootBeanDefinition, Object[])
在进入doCreateBean()之前,执行一次如下的操作:
Object bean = resolveBeforeInstantiation(beanName, mbd
if
(bean !=
null
) {
return
bean;
}
|
我的理解:主要是处理实现了InstantiationAwareBeanPostProcessor的后置处理器,相当于给我们开发者一个在bean真正创建的的机会进行代理逃逸或者对配置做一些修改。
bean真正执行的函数:doCreateBean:
1:Bean的建立:
容器寻找Bean的定义信息并将其实例化。
(1)基于FactoryBean实例化
(2)基于构造器的实例化。
- 默认构造器或者是不带lookup或者replace配置方法时实例化使用java反射直接实现
- 否则使用动态代理将配置特性加入bean中
插一个过程,处理循环依赖的提前曝光策略:
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"
);
}
addSingletonFactory(beanName,
new
ObjectFactory<Object>() {
@Override
public
Object getObject()
throws
BeansException {
return
getEarlyBeanReference(beanName, mbd, bean);
}
});
}
|
2:属性注入:
使用依赖注入,Spring按照Bean定义信息配置Bean所有属性。
populateBean(beanName, mbd, instanceWrapper);
|
插一个过程:initializeBean():
后面的3-8的步骤均在此方法中调用:
protected
Object initializeBean(
final
String beanName,
final
Object bean, RootBeanDefinition mbd) {
if
(System.getSecurityManager() !=
null
) {
AccessController.doPrivileged(
new
PrivilegedAction<Object>() {
@Override
public
Object run() {
invokeAwareMethods(beanName, bean);
return
null
;
}
}, getAccessControlContext());
}
else
{
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if
(mbd ==
null
|| !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try
{
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch
(Throwable ex) {
throw
new
BeanCreationException(
(mbd !=
null
? mbd.getResourceDescription() :
null
),
beanName,
"Invocation of init method failed"
, ex);
}
if
(mbd ==
null
|| !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return
wrappedBean;
}
|
3:BeanNameAware的setBeanName():
如果Bean类有实现org.springframework.beans.BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。
4:BeanFactoryAware的setBeanFactory():
如果Bean类有实现org.springframework.beans.factory.BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身。
5:BeanPostProcessors的ProcessBeforeInitialization()
如果有org.springframework.beans.factory.config.BeanPostProcessors和Bean关联,那么其postProcessBeforeInitialization()方法将被将被调用。
6:initializingBean的afterPropertiesSet():
如果Bean类已实现org.springframework.beans.factory.InitializingBean接口,则执行他的afterProPertiesSet()方法
7:Bean定义文件中定义init-method:
可以在Bean定义文件中使用"init-method"属性设定方法名称例如:
如果有以上设置的话,则执行到这个阶段,就会执行initBean()方法
8:BeanPostProcessors的ProcessaAfterInitialization()
如果有任何的BeanPostProcessors实例与Bean实例关联,则执行BeanPostProcessors实例的ProcessaAfterInitialization()方法
五、Bean生命周期应用
自定义注解实现Logger