Spring源码学习-容器BeanFactory Bean的创建-探寻Bean的新生之路
Posted zzlevolflash
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring源码学习-容器BeanFactory Bean的创建-探寻Bean的新生之路相关的知识,希望对你有一定的参考价值。
写在前面
上面四篇文章讲了Spring是如何将配置文件一步一步转化为BeanDefinition的整个流程,下面就到了正式创建Bean对象实例的环节了,我们一起继续学习吧。
2.初始化Bean对象实例
Resource resource = new ClassPathResource("beanFactory.xml");
BeanFactory beanFactory = new XmlBeanFactory(resource);
Student student = beanFactory.getBean(Student.class);
仍然使用我们最开的一串代码来讲解,前四章我们说了那么多其实只是创建了BeanFactory这个容器,并将BeanDefinition对象解析完毕,而真正的对象创建则是在BeanFactory.getBean()中执行的。
2.1 起源,探寻Bean的新生之路
一切起源于BeanFactory.getBean(),而对getBean()的实现是在AbstractBeanFactory这个类中实现的,所以我们着眼此类进行源码的阅读。如下为AbstractBeanFactory的继承实现图
getBean()方法调用了本类中自定义的doGetBean方法,接下来进入doGetBean()方法观察。
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//1、解析beanName,找出bean真正的名称
final String beanName = transformedBeanName(name);
Object bean;
//2.尝试从单例缓存池中直接获取对象
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);
}
else {
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//3.该容器缓存中没有,开始尝试加载父容器,检查父容器中是否存在该Bean对象
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);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
//4.父容器中仍然不存在,获取解析好的BeanDefinition,开始准备自己创建Bean
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);//获取bean的根路径信息
checkMergedBeanDefinition(mbd, beanName, args);
//重要一步,检查依赖关系,提前创建依赖的bean对象。
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
getBean(dep);
}
}
//5.检查BeanDefinition的scope属性,并执行不同的创建方法,总体大同小异,着重关注单例的创建方法即可。
if (mbd.isSingleton()) {
//6、极为重要的一点,通过getSingleton(String beanName,ObjectFactory objectFactory)创建对象,并且实例化getObject()方法
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);
}
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);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
上面的代码很长,乍一看真的会让初学者头皮发麻,但是没关系,我们将它拆解开来一步一步分析。
- transformedBeanName(String):提取对应Bean的名称。定义在SimpleAliasRegistry中,用于获取bean的真实名称。
- DefaultSingletonBeanRegistry.getSingleton(Stirng,Boolean):尝试从缓存中直接获取bean或者通过ObjectFactory中获取。关于此方法的详解,请点击。
- getObjectForBeanInstance():根据Bean取出我们真正需要的对象(判断指定的bean是否是一个FactoryBean,如果是FactoryBean会判断需求的是本身还是factory的创建对象。)
- isPrototypeCurrentlyInCreation(beanName):判断是否进入了循环依赖的无限循环
- registerDependentBean(dep, beanName):此段代码主要是找出当前Bean的所有依赖对象,并且循环对这些依赖进行注册和创建。
- getSingleton(String,ObjectFactory):针对不同的scope进行各自的初始化操作。
- 做最后的类型转换(还不太懂)
至此,一个bean的完整创建流程就走完了。具体的细节,我们接下来一个一个慢慢的看。
2.2 明辨,找出我们真正的目标
首先,我们进入第一段代码
在transformedBeanName(beanName)中,传入的参数并非真正的beanName,这里的参数可能是别名,也可能是factoryBean的名称,所以要进行一系列的解析,主要的解析分为两步:
- 尝试解析是否是FactoryBean名称,(关于FactoryBean如果不理解,可以访问:Spring之FactoryBean 代码如下:
//解析是否是FactoryBean:BeanFactoryUtils.transformedBeanName(String name)
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
String beanName = name;
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
return beanName;
}
代码很简单,就是判断beanName是否是以“&”开头,然后进行截取。
- 尝试判断该名称是否是某个bean的别名。
//判断别名:SimpleAliasRegistry.canonicalName(String name)
public String canonicalName(String name) {
String canonicalName = name;
String resolvedName;
do {
//从别名集合中循环查找,直到最底层真正的bean名称
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
依然很简单,尝试从实现定义好的别名集合中进行查询,寻找真正的bean。
2.3 尝试从缓存中直接获取对象
接下来是doGetBean中的第三个方法,getSingleton(String beanName, boolean allowEarlyReference)
。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
//1.尝试从单例缓存中直接获取对象
Object singletonObject = this.singletonObjects.get(beanName);
//2.如果单例缓存中无法获取对象,且该对象在正在创建对象标记池里。
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//3.从提前创建对象池中获取该对象
singletonObject = this.earlySingletonObjects.get(beanName);
//4.对象仍然为空且允许循环依赖
if (singletonObject == null && allowEarlyReference) {
//5.尝试从ObjectFactory池中获取对象的ObjectFactory,并创建该对象。
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);
}
public boolean isSingletonCurrentlyInCreation(String beanName) {
return this.singletonsCurrentlyInCreation.contains(beanName);
}
此方法代码其实不难理解,主要的难点是几个概念上的问题。首先观察该方法中用到的该类的几个参数。
- 单例对象缓存池
/** Cache of singleton objects: bean name --> bean instance */ private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
如注解,这是Spring的单例对象池,所有的单例对象创建完毕后都会以beanName ->singletonObject 的形式放入该Map集合中 - 对象预创建标记池
/** Names of beans that are currently in creation */ private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(16));
这是Spring为了解决循环依赖的一个标记集合,具体概念留在后面介绍 - 预创建单例对象缓存池
/** Cache of early singleton objects: bean name --> bean instance */ private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
此集合是保存预创建单例对象的集合 - 预创建单例对象缓存池
/** Cache of singleton factories: bean name --> ObjectFactory */ private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
此集合是保存ObjectFactory的集合,至于何时、何种情况Spring会创建ObjectFactory。且ObjectFactory、BeanFacotry、FactoryBean他们的关系,也在下面会做说明。
小tip:ObjectFactory、BeanFactory、FactoryBean之间的关系和联系
- BeanFactory:这是我们大家非常熟悉的接口,Spirng管理Bean容器最原始接口,我们此次研究的入口getBean()就是在此接口中定义。
- FactoryBean:在上文2.2中我们已经讨论了FactoryBean的情况,作为一个Bean的工厂对象,它也可以作为一个bean对象直接获取,关于BeanFactory和FactoryBean的详细信息,可查看该文章:BeanFactory和FactoryBean
- ObjectFactory:与FactoryBean很相似的是ObjectFactory也是用于创建一个对象的,且它存在的意义主要用于解决循环依赖。例如A、B两个对象,A中有B属性,B中有A属性。那么在创建A时发现需要注入B,这时创建B,在创建B时发现又需要注入A,这就形成了循环依赖。而Spring正是利用ObjectFactory解决了这个问题,其原理就是在创建A时就将一个A的ObjectFactory对象放入了缓存中,那么在B注入A时就用这个ObjectFactory创建的对象注入B中,这样就解决了循环依赖的问题。具体的代码在下面会详细介绍。
2.4根据Bean实例,获取真正需要的对象
getObjectForBeanInstance()是一个非常重要的方法,Spring在获取了每个Bean的对象之后,都要调用该方法完成最后的步骤以取得我们真正想要的Bean。说到很多人肯定会疑惑,什么是“真正需要”,点进该方法,我们就知道了。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
//判断实例不是FactoryBean类型或该实例名称以获取FactoryBean开头 ,满足任何一个条件直接返回实例
//即满足两个条件无非有两个条件1.该对象不是FactoryBean,判断短路直接返回。2.该对象是FactoryBean,且用户想直接获取FactoryBean
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
//通过上述,至此可以完全确定该对象是Factory对象,下方就是通过对象的factory-method创建对象的过程。
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
if (mbd == null && containsBeanDefinition(beanName)) {
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
上述重要就是一个短路判断,如果该对象不是一个FactoryBean或者用户试图直接获取FactoryBean对象,则该对象就已经是我们想要的对象,直接返回即可,否则的话就意味着我们需要通过FactoryBean内部定义好的factory-method来创建我们需要的Bean对象。而我们追入getObjectFromFactoryBean()中,查看如下代码:
//FactoryBeanRegistrySupport.getObjectFromFactoryBean(...)
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory, beanName);
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (object != null && shouldPostProcess) {
try {
//执行后处理器
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
}
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
}
}
return (object != NULL_OBJECT ? object : null);
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (object != null && shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
而遗憾的是我们还是没有看到真正创建对象的方法,但通过前面的阅读,我们已经可以发现Spring在一个方法的真正核心处理部分处,都会以doXXXX开头,而其余都是对这个核心处理的一层层包装与协助。
4.1代码如莲花开放般的优美:处理器BeanPostProcess
在观察核心代码之前,我们先观察后面一个重要的方法。postProcessObjectFromFactoryBean(),在spring的整个架构中给予了用户各种拓展和自定义的权利,这也是Spring被广泛称赞:代码优美的原因之一。而这里的执行后处理器操作就是很重要的一环,进入该方法的子类AbstractAutowireCapableBeanFactory观察Spirng是如何让代码变得如此优美的。
//AbstractAutowireCapableBeanFactory.java
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
return applyBeanPostProcessorsAfterInitialization(object, beanName);
}
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
//BeanPostProcessor.java
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
观察代码,可以知道Spring循环了Bean所注册的所有BeanPostProcess,并在这里依次调用了其postProcessAfterInitialization()
方法,而该方法的实现交由用户来自己实现。于是乎,通过解析我们就能知道:在Spring中:如果想让一个Bean在初始化完成后做一些特殊处理,实现BeanPost.postProcessAfterInitialization()
即可。最后有一个小提醒:我们一定要清晰的认识到,此时我们是在修饰一个FactoryBean创建的Bean对象,而并非正常流程创建的Bean对象哦,例如我们一直讨论的这个FactoryBean,它本身作为一个Bean对象是在什么时候执行了PostPorcess方法了呢?后续我们拭目以待吧
4.2柳暗花明,终于获取最终需要的对象
了解完处理器之后,让我们点入doGetObjectFromFactoryBean(),发现里面的代码就非常简单明了。
//FactoryBeanRegistrySupport.doGetObjectFromFactoryBean(...)
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
//安全校验相关的,先无视掉吧。
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
//调用Factory的getObject方法
return factory.getObject();
}
}, acc);
}catch (PrivilegedActionException pae) {
throw pae.getException();
}
}else {
//调用Factory的getObject方法
object = factory.getObject();
}
}catch (FactoryBeanNotInitializedException ex) {
throw new BeanCurrentlyInCreationException(beanName, ex.toString());
}catch (Throwable ex) {
throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
}
if (object == null && isSingletonCurrentlyInCreation(beanName)){
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
return object;
}
一层一层终于我们到了最里边,在这里我们发现最终对象正是由当初获取的FactoryBean对象的getObject()方法完成。如果读到这里已经有些绕不过来,想不起自己从何处而来的话,往上翻一翻,看清楚自己一路走来之路哦。下面我们就重新回到起源之路上,继续往下探索。但由于真正的Bean的创建流程很长,所以这篇文章先写到这里,下面单开一篇文章来写Bean对象的实例化。
以上是关于Spring源码学习-容器BeanFactory Bean的创建-探寻Bean的新生之路的主要内容,如果未能解决你的问题,请参考以下文章