上一篇,我们分析了Spring是如果通过多级缓存来解决循环依赖的,其实思路还挺简单的,就是将还未完全创建好的bean先暴露在缓存中,这样的话,当其他的bean实例化需要依赖bean时,可以提前从缓存中获取还未实例化好的bean,从而解决循环依赖的问题。接下来我们继续接着doGetBean方法的主流程分析下后面的逻辑。
如果一个单例bean实例化好了,或者在实例化过程中提前暴露在对象工厂缓存中了,我们可以通过方法getSingleton,从缓存中获取单例对象。我们假设我们可以从缓存中获取到单例bean,也就是bean已经实例化了,使用sharedInstance不为空,且参数args在doGetBean方法传进来时默认就是为空的,所以接下来就会调用方法getObjectForBeanInstance,进一步处理单例sharedInstance。大家需要注意的是,在方法getObjectForBeanInstance传入的参数中,name是在调用getBean方法时传入的。是最原始的bean名称,而beanName是name转换后的bean名称,并且mbd默认值为null。我们了解这些参数有助于分析下面的逻辑。我们进入到方法getObjectForBeanInstance 中看下:
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
// 判断参数传入进来的name,是否以&为前缀
if (BeanFactoryUtils.isFactoryDereference(name)) {
if (beanInstance instanceof NullBean) {
return beanInstance;
}
// 如果name 以 & 为前缀,那必须得要是FactoryBean的实例,否则就抛出异常
if (!(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
}
if (mbd != null) {
// 通过BeanDefinition中的属性isFactoryBean来标记BeanDefinition对应的是FactoryBean类型的Bean
mbd.isFactoryBean = true;
}
// 直接返回FactoryBean的实例
return beanInstance;
}
// Now we have the bean instance, which may be a normal bean or a FactoryBean.
// If it's a FactoryBean, we use it to create a bean instance, unless the
// caller actually wants a reference to the factory.
// 如果单例Bean 的beanInstance的名称name,既不是以&为前缀的并且 beanInstance 也不是FactoryBean的实例,直接返回单例bean
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}
/**
* 下面是对name不是以&为前缀,且beanInstance为FactoryBean的实例的处理情况,
* 如果beanInstance 为FactoryBean的实例,会通过FactoryBean来实例化一个bean
*
*/
Object object = null;
if (mbd != null) {
// 通过BeanDefinition中的属性isFactoryBean来标记BeanDefinition对应的是FactoryBean类型的Bean
mbd.isFactoryBean = true;
}
else {
// 从缓存中,获取FactoryBean实例化好的bean
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// Return bean instance from factory.
// 强制转换为FactoryBean
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
// 获取BeanDefinition,并封装为RootBeanDefinition
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 通过FactoryBean来实例化bean
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
首先会调用BeanFactoryUtils的方法isFactoryDereference,对bean原始的名称name进行判断,我们进去看下:
这个里面的逻辑也是判断name是否以符号&为前缀的,要是我们通过调用genBean方法传进来的name,如果是以符号&为前缀会怎么样呢?我们通过这个注解可以知道,getBean方法传入的name如果以符号&为前缀,就是为了获取一个工厂的引用也就是获取一个工厂bean,那什么是工厂bean呢?提到这个工厂bean,我们就要知道Spring中比较重要的一个接口FactoryBean,我们可以通过实现FactoryBean接口中的getObject方法,在getObject方法中定义如何创建一个对象,而实现FactoryBean接口的实现类,就是这里的工厂bean。前面将的bena的后处理器BeanPostProccessor是通过实现BeanPostProcessor接口中的方法,来实现对bean实例化的过程的控制,这个控制只是初步介入了bean的实例化过程,而FactoryBean就是全盘操办bean的实例化。我们先了解下FactoryBean的接口:
可以看到,FactoryBean接口中的东西并不多,主要提供可几个比较简单的方法,并且FactoryBean是支持泛型的。其中,isSingleton方法是用来判断实例化是否为单例类型,getObjectType用来获取bean的类型,而getObeject方法,就是专门用来定义bean实例化逻辑的,我们到FactoryBean接口中看下:
可以看到isSingleton的返回值,默认为true,也就是说FactoryBean默认是实例化单例类型的bean。
我们通过案例简单的了解下FactoryBean:
先创建一个User类
注意,此时我们不用在xml配置User对象,我们通过FactoryBean来实例化对象User。
可以看到UserFactoryBean实现接口FactoryBean,同时UserFactoryBean实现了getObject方法以及getObjectType方法,其中,getObjectType方法返回的是bean类型也就是User.class,而getObject方法则包含可创建User对象的核心逻辑。在getObject方法中,我直接new 了一个User对象。
我们在xml配置 UserFactoryBean。
最后,我们测试一下:
我们直接从容器中获取bean即可,我们这里不仅可以通过user来获取bean,同时,我们还手动在名称user前面添加了符号&
执行结果:
可以看到通过名称user,Spring内部就会通过UserFactoryBean的getObject方法,为我们创建一个对象,也就是User对象,而这个User对象的创建逻辑,完全是由我们自己自定义的。而在我们的名称user前添加了符号&之后,直接就获取到了创建User对象的工厂bean,也就是UserFactoryBean对象。
了解完FactoryBean以及如果通过FactoryBean实例化bean之后,我们在回到刚才的方法:
刚才已经看到了,这个逻辑中的判断,其实就是判断name是否以符号&为前缀,首先,我们假设name就是以符号&为前缀的,比如name为&user,根据我们刚才的案例,现在就是要获取创建bean的工厂bean,也就是实现了FactoryBean接口的对象。看下Spring具体是怎么处理的:
如果获取到的单例beanInstance是nullBean的实例就直接返回,接着会判断,如果beanInstance不是FactoryBean的实现类,此时就会抛出异常。从这里可以看出,如果一个bean的名称以&为前缀,那它必须是FactoryBean接口的实现类。接下来,我们可以看到如果name以&为前缀,且同时是FactoryBean接口实例,此时就会将单例beanInstance返回了,就是直接返回FactoryBean的实现类了。
我们知道我们需要通过FactoryBean来实例化一个bean,就要剔除bean名称name的前缀符号&,同时,如果这个name对应的bean实现了BeanFactory接口,就会通过getObject方法实例化一个bean,我们也来看下spring是如何处理的:
可以看到,如果bean的名称name不是以&为前缀的,此时就会走到这段代码,这里判断如果beanInstance不是FactoryBean的实例,直接就将beanInstance返回了。也就是说,一个bean的名称既不是以&为前缀,同时也不是接口FactoryBean的实现类,此时Spring就会认为这个bean没有定义相关的FactoryBean来自定义实例化的bean,这个bean就是一个非常普通的bean,就会将bean实例返回了。也就是说,在默认的情况下,我们是不需要根据FactoryBean来实例化bean的,只有当我们需要全权控制bean的实例化时,才需要自定义FactoryBean的实现类,并且在getObject方法中定义好bean的实例化逻辑。
我们案例中的bean已经实现了FactoryBean,我们看下Spring会如何处理:
接下来就会标记当前mbd的类型,也就是将BeanDefinition的属性isFactoryBean值设置为true,表示当前BeanDefinition为工厂bean了。前面我们看到了参数mbd的值为null,所以mbd.isFactoryBean = true的这行代码,在本次逻辑中是不会只执行的,而是执行方法getCachedObjectForFactoryBean。通过方法名称我们知道,这里应该是尝试先从缓存中获取FactoryBena实例化好的bean实例,我们进去看下:
这里就是通过beanName缓存FactoryBeanObjectCache中获取单例,第一次获取,缓存中也是没有的,所以返回空。我们继续往下看:
从缓存获取不到bean时,此时object为空,就会走到上图中的分支。接下来将beanInstance强转为FactoryBean了,刚才我们已经知道参数mbd传进来的时候是空的,而方法containsBeanDefinition则是判断Spring容器中,是否存在beanName对应的BeanDefinition。其实beanName对应BeanDefinition,其实就是FactoryBean实现类对应的BeanDefinition,我们在xml文件中已经配置好了FactoryBean对应的实现类了,所以在Spring容器初始时,就会解析并将FactoryBean对应的BeanDefinition注册到Spring容器中。所以方法containsBeanDefinition的返回结果为true,接着就会调用方法getMergedLocalBeanDefinition获取FactoryBean对应的BeanDefinition,接着会调用方法getObjectFromFactoryBean。为了方便我们分析getObjectFromFactoryBean方法中的逻辑,我们有必要了解这些参数的值,对于boolean类型的synthetic,因为mbd此时不为空,且在RootBeanDefinition中方法synthetic的返回值默认为false,所以传递到方法getObjectFromFactoryBean中的!synthetic值为true。
我们现在已经获取到了FactoryBean的实现类了,我们其实就可以知道getObjectFromFactoryBean方法中,其实就是通过FactoryBean中的getObject方法来实例化bean的。我们到方法getObjectFromFactoryBean中看下:
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
// 如果FactoryBean默认是单例,并且单例缓存中存在beanName对应的单例
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
// 第一次来创建时,缓存中肯定找不到
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
// 通过调用FactoryBean的getObject方法,创建bean实例
object = doGetObjectFromFactoryBean(factory, beanName);
// Only post-process and store if not put there already during getObject() call above
// (e.g. because of circular reference processing triggered by custom getBean calls)
Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
if (alreadyThere != null) {
object = alreadyThere;
}
else {
if (shouldPostProcess) {
// beanName对应的单例bean,是否正在实例化
if (isSingletonCurrentlyInCreation(beanName)) {
// Temporarily return non-post-processed object, not storing it yet..
// 如果正在实例化的话,直接返回通过FactoryBean.getObject方式得到的bean
return object;
}
// bean开始创建之前
beforeSingletonCreation(beanName);
try {
// 在FactoryBean创建实例bean之后,进行一些后处理操作,默认什么也没有做
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
// 移除bean正在创建的标记
afterSingletonCreation(beanName);
}
}
// 如果beanName对应的单例bean,也就是FactoryBean存在,此时就把FactoryBean创建出来的bean实例添加到缓存中
if (containsSingleton(beanName)) {
this.factoryBeanObjectCache.put(beanName, object);
}
}
}
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
}
}
return object;
}
}
我们知道FactoryBean中的isSingleton方法返回值默认为true,并且在单例缓存中是存在beanName对应的单例bean的,所以会进入到上图这个分支,接着我们到doGetObjectFromFactoryBean方法中看下:
我们终于看到了我们想要看到的代码,也就是调用FactoryBean的getObject方法实例化bean。
我们回退到上一步看下还有哪些东西:
我们这个FactoryBean是第一次创建实例,所以FactoryBean的实例缓存中是没有数据的,所以会进入到上图这个分支,我们之前看过了这个shouldPostProcess参数它的值为true,所以会进入到方法isSingletonCurrentlyInCreation 进行判断当前是否有名称beanName的bean正在实例化,现在这里暂时是没有的。
我们继续向下看:
我们看下beforeSingletonCreation和afterSingletonCreation的逻辑:
bean开始实例化时,先将beanName记录到集合inCreationCheckExclusion和集合singletonsCurrentlyInCreation中。其中,一旦bean开始实例化,就会将bean的名称添加到集合inCreationCheckExclusion中,很明显这个集合是用来去重的,避免同一个bean重复被实例化,而集合singletonsCurrentlyInCreation,则是用来存放当前正在创建的bean名称,用来检测bean是否处于正在创建的状态。
在afterSingletonCreation方法中相应的就会将beanName。从集合singletonsCurrentlyInCreation中移除,表示这个bean已经实例化好了。
最后,我们再来看下,这个postProcessObjectFromFactoryBean方法:
可以看到,方法postProcessObjectFromFactoryBean默认就将对象object返回了。
我们在来看最后的一些逻辑:
可以看到,最后会把FactoryBean创建好的实例bean,存放在FactoryBean的实例缓存factoryBeanObjectCache中,然后直接就返回了。
最后,我们梳理一下流程图: