Spring是怎么创建一个Bean的?
1.前言
大致分析了下Spring的getBean过程,但主要关注doCreateBean。
2.整体流程
调用链:preInstantiateSingletons->getBean->doGetBean->getSingleton-> singletonFactory.getObject()->createBean->doCreateBean
图中,需要特别注意getBean
、createBean
、createBeanInstance
、populateBean
、initializeBean
。
3.preInstantiateSingletons 提前初始化非lazy的单实例
由SpringIOC源码学习总结可知,在Spring容器refresh的阶段会调用finishBeanFactoryInitialization->preInstantiateSingletons,然后提前实例化非lazy的单实例。
3.1 getBean 得到/创建bean
调用链:createBean->doGetBean->getSingleton
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
//doGetBean
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
3.2 getSingleton(String beanName, ObjectFactory<?> singletonFactory)
获得单实例
调用链:getSingleton->singletonFactory.getObject()->createBean
- 先尝试中
singletonObjects
拿到Spring已经缓存的bean实例。 - 标记该bean【正创建中】
- 调用
singletonFactory.getObject()
->createBean
创建bean。 - 添加到缓存。
- 去掉【正创建中】标记。
- 添加到缓存。
getSingleton源码
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//标记为该bean【正在创建】
beforeSingletonCreation(beanName);
...
//创建bean,重点关注
singletonObject = singletonFactory.getObject();
...
//添加到缓存
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}finally {
...
//去除 【正在创建】 的标记
afterSingletonCreation(beanName);
}
3.2.1 createBean`创建bean
调用链:createBean->doCreateBean
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
...
RootBeanDefinition mbdToUse = mbd;
//从BeanDefinition中取出Class信息
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
//为bean设置<bean>标签中的<replaced-method>方法。实现方法重载
mbdToUse.prepareMethodOverrides();
...
//有机会创建代理对象,暂不理会这里
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
...
//创建bean实例, 重点关注
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
...
return beanInstance;
}
3.3 getObjectForBeanInstance 处理FactoryBean
1.如果该bean是普通bean,则直接返回。如果该bean是FactoryBean,且getBean("&id")形式来获取,则返回该bean.
2.否则是需要取FactoryBean#getObject
对应的实例。因此调用该bean的getObject方法返回实例bean,并放入factoryBeanObjectCache
缓存。
关于FactoryBean可查看FactoryBean的作用
4.doCreateBean(beanName, mbdToUse, args)
终于到了今天的主角doCreateBean
。
这里就不贴代码了, 太多了。需要看源码直接看AbstractAutowireCapableBeanFactory#doCreateBean
直接看下流程图:
流程:
- 创建实例:
createBeanInstance(beanName, mbd, args)
创建一个带有bean实例的BeanWrapper
- 收集注解:通过
applyMergedBeanDefinitionPostProcessors
调用BeanPostProcessor收集@Resource、@Autowired、@PreConstruct等注解。 - 提前暴露Bean:如果是需要提前暴露bean,则添加一个暴露没有注入属性的bean的方法到缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
。此处是为了解决循环依赖,可查看:spring中怎么解决循环依赖。 - 注入属性:
populateBean
除了处理标签中的property,还利用BeanPostProcessor去处理【2】中收集的@Resource、@Autowired等,完成依赖注入。—CommonAnnotationBeanPostProcessor
以及AutowiredAnnotationBeanPostProcessor
- 初始化bean(完成注入后的操作):
initializeBean
,这里的钩子就比较多:
a. invokeAwareMethods:响应BeanNameAware、BeanClassLoaderAware、BeanFactoryAware接口。
b. applyBeanPostProcessorsBeforeInitialization:遍历BeanPostProcess调用BeanPostProcessor#postProcessBeforeInitialization
c. invokeInitMethods:
-InitializeBean.afterPropertiesSet
:如果该bean有实现InitializeBean接口,则调用。
- invokeCustomInitMethod(initMethod):如果有<bean>
有配置init-method
则调用。
d. applyBeanPostProcessorsAfterInitialization:遍历BeanPostProcess调用BeanPostProcessor#postProcessAfterInitialization
小结
1.a为常用的Aware接口,b、d为常用的BeanPostProcessor接口,c为常用InitializingBean接口。
2.重点类BeanpostProcessor:CommonAnnotationBeanPostProcessor
、AutowiredAnnotationBeanPostProcessor
总结
createBean 过程总之就是获得BeanDefinition的信息,通过反射创建实例,再注入依赖,然后initializeBean
完成特殊处理,最后放入缓存中。 在整个过程中,留下了许多钩子,我们可以使用Aware接口,BeanPostProcessor去做特殊处理。
最后再放一张详细的图: