假设当前IOC容器已经载入用户定义的Bean信息,开始分析依赖注入的原理。首先,注意到依赖注入的过程是用户第一次向IOC容器索要Bean时触发的,当然也有例外,也就是我们可以在BeanDefinition信息中通过控制lazy-init属性来让容器完成对Bean的预实例化。这个预实例化过程实际上也是一个完成依赖出入的过程,但是它在初始化的过程中完成的(这个部分在这篇文章中就不详细讲述了)。当用户向IOC索要Bean的时,在基本IOC容器接口BeanFactory中,有一个getBean的接口定义,这个接口的实现就是触发依赖注入的地方。下面从DefaultListableBeanFactory的基类AbstractBeanFactory去看getBean的实现,但是并没有关注其中调用的方法。
public Object getBean(String name) throws BeansException {
// getBean 是一个空壳方法,所有的逻辑都封装在 doGetBean 方法中
return doGetBean(name, null, null, false);
}
protected T doGetBean(
final String name, final Class requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
// 1.
/*
* 通过 name 获取 beanName。这里不使用 name 直接作为 beanName 有两点原因:
* 1. name 可能会以 & 字符开头,表明调用者想获取 FactoryBean 本身,而非 FactoryBean
* 实现类所创建的 bean。在 BeanFactory 中,FactoryBean 的实现类和其他的 bean 存储
* 方式是一致的,即 ,beanName 中是没有 & 这个字符的。所以我们需要
* 将 name 的首字符 & 移除,这样才能从缓存里取到 FactoryBean 实例。
* 2. 若 name 是一个别名,则应将别名转换为具体的实例名,也就是 beanName。
*/
final String beanName = transformedBeanName(name);
Object bean;
//2.
/*
* 从缓存中获取单例 bean。Spring 是使用 Map 作为 beanName 和 bean 实例的缓存的,所以这
* 里暂时可以把 getSingleton(beanName) 等价于 beanMap.get(beanName)。当然,实际的
* 逻辑并非如此简单,后面再细说。
*/
Object sharedInstance = getSingleton(beanName);
/*
* 如果 sharedInstance = null,则说明缓存里没有对应的实例,表明这个实例还没创建。
* BeanFactory 并不会在一开始就将所有的单例 bean 实例化好,而是在调用 getBean 获取
* bean 时再实例化,也就是懒加载。
* getBean 方法有很多重载,比如 getBean(String name, Object... args),我们在首次获取
* 某个 bean 时,可以传入用于初始化 bean 的参数数组(args),BeanFactory 会根据这些参数
* 去匹配合适的构造方法构造 bean 实例。当然,如果单例 bean 早已创建好,这里的 args 就没有
* 用了,BeanFactory 不会多次实例化单例 bean。
*/
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 + "'");
}
}
//3.
/*
* 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。但如果
* sharedInstance 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的
* bean 实例。如果用户想获取 FactoryBean 本身,这里也不会做特别的处理,直接返回
* 即可。毕竟 FactoryBean 的实现类本身也是一种 bean,只不过具有一点特殊的功能而已。
*/
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
//4.
/*
* 如果上面的条件不满足,则表明 sharedInstance 可能为空,此时 beanName 对应的 bean
* 实例可能还未创建。这里还存在另一种可能,如果当前容器有父容器,beanName 对应的 bean 实例
* 可能是在父容器中被创建了,所以在创建实例前,需要先去父容器里检查一下。
*/
else {
// BeanFactory 不缓存 Prototype 类型的 bean,无法处理该类型 bean 的循环依赖问题
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
//5.
// 如果 sharedInstance = null,则到父容器中查找 bean 实例
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 获取 name 对应的 beanName,如果 name 是以 & 字符开头,则返回 & + beanName
String nameToLookup = originalBeanName(name);
// 根据 args 是否为空,以决定调用父容器哪个方法获取 bean
if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
//6.
// 合并父 BeanDefinition 与子 BeanDefinition,后面会单独分析这个方法
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
//7.
// 检查是否有 dependsOn 依赖,如果有则先初始化所依赖的 bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
/*
* 检测是否存在 depends-on 循环依赖,若存在则抛异常。比如 A 依赖 B,
* B 又依赖 A,他们的配置如下:
*
*
*
* beanA 要求 beanB 在其之前被创建,但 beanB 又要求 beanA 先于它
* 创建。这个时候形成了循环,对于 depends-on 循环,Spring 会直接
* 抛出异常
*/
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
// 注册依赖记录
registerDependentBean(dep, beanName);
try {
// 加载 depends-on 依赖
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
//8.
// 创建 bean 实例
if (mbd.isSingleton()) {
/*
* 这里并没有直接调用 createBean 方法创建 bean 实例,而是通过
* getSingleton(String, ObjectFactory) 方法获取 bean 实例。
* getSingleton(String, ObjectFactory) 方法会在内部调用
* ObjectFactory 的 getObject() 方法创建 bean,并会在创建完成后,
* 将 bean 放入缓存中。关于 getSingleton 方法的分析,本文先不展开,我会在
* 后面的文章中进行分析
*/
sharedInstance = getSingleton(beanName, new ObjectFactory
doGetBean的工作流程如下:
1.转换对应的beanName。
2.尝试从缓存中加载单例。单例在Spring的同一个容器中只会被创建一次,后续在获取单例,就直接从单例缓存中获取。当然这里的也只是尝试加载,首先尝试从缓存中加载,如果加载不成功则再次从singletonFactories中加载。因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,在Spring创建bean的原则是不等bean创建完成后就会将创建bean的ObjectFactory提前曝光加入到缓存中,一旦下一个bean创建的时候需要依赖上一个bean则直接使用ObjectFactory(后面会详细讲解循环依赖)。
3.bean的实例化。如果从缓存中得到了bean的原始状态,则需要对bean进行实例化。缓存中记录的只是最原始的bean的状态,并不一定使我们最终想要的bean。举个例子,假如我们需要对工厂bean进行处理,那么这里得到的其实就是工厂bean的初始状态,但实际需要的是工厂bean中定义的factory-method方法中返回的bean,而getObjectForBeanInstance就是完成这个工作的,后面会详细讲解。
4.原型模式的依赖检查。只有单例情况下才会尝试解决循环依赖,如果存在A中有B的属性,B中有A的属性,那么当依赖注入的时候,就会产生当A还未创建完的时候因为对B的创建再次返回创建A,造成循环依赖,也就是情况:isPrototypeCurrentInCreation(beanName)判断为true。
5.检测parentBeanFactory。
6.将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition。因为从XML配置文件读取的Bean信息存储在GernericBeanDefinition,但是所有Bean后续处理都是针对于RootBeanDefinition的,所以这里需要进行一个转换,转换的同时,如果父类bean不为空的话,则会一并合并父类的属性。
7.寻找依赖。
8.针对不同的scope进行bean的创建。
9.类型转换。
以上步骤对应的流程图如下:
在获取bean实例之前,String第一件要做的事情就是对参数name进行转换。转换的目的主要是为了解决两个问题,第一个问题是处理字符&开头的name,防止BeanFactory无法找到与name对应的bean实例。第二个是处理别名问题,Spring不会存储<别名,bean实例>这种映射,仅会存储
protected String transformedBeanName(String name) {
// 这里调用了两个方法:BeanFactoryUtils.transformedBeanName(name) 和 canonicalName
return canonicalName(BeanFactoryUtils.transformedBeanName(name));
}
/** 该方法用于处理 & 字符 */
public static String transformedBeanName(String name) {
Assert.notNull(name, "'name' must not be null");
String beanName = name;
// 循环处理 & 字符。比如 name = "&&&&&helloService",最终会被转成 helloService
while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
}
return beanName;
}
/** 该方法用于转换别名 */
public String canonicalName(String name) {
String canonicalName = name;
String resolvedName;
/*
* 这里使用 while 循环进行处理,原因是:可能会存在多重别名的问题,即别名指向别名。比如下面
* 的配置:
*
*
*
*
* 上面的别名指向关系为 aliasB -> aliasA -> hello,对于上面的别名配置,aliasMap 中数据
* 视图为:aliasMap = [, ]。通过下面的循环解析别名
* aliasB 最终指向的 beanName
*/
do {
resolvedName = this.aliasMap.get(canonicalName);
if (resolvedName != null) {
canonicalName = resolvedName;
}
}
while (resolvedName != null);
return canonicalName;
}
对于单例bean,Spring容器只会实例化一次。后面再次获取时,只需要从缓存里获取即可,无需且不能再次实例化。从缓存取bean实例的方法是getSingleton(String),下来对这个方法进行分析:
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
/**
* 这里解释一下 allowEarlyReference 参数,allowEarlyReference 表示是否允许其他 bean 引用
* 正在创建中的 bean,用于处理循环引用的问题。关于循环引用,这里先简单介绍一下。先看下面的配置:
*
*
*
*
*
*
*
*
* 如上所示,hello 依赖 world,world 又依赖于 hello,他们之间形成了循环依赖。Spring 在构建
* hello 这个 bean 时,会检测到它依赖于 world,于是先去实例化 world。实例化 world 时,发现
* world 依赖 hello。这个时候容器又要去初始化 hello。由于 hello 已经在初始化进程中了,为了让
* world 能完成初始化,这里先让 world 引用正在初始化中的 hello。world 初始化完成后,hello
* 就可引用到 world 实例,这样 hello 也就能完成初始了。关于循环依赖,我后面会专门写一篇文章讲
* 解,这里先说这么多。
*/
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 从 singletonObjects 获取实例,singletonObjects 中缓存的实例都是完全实例化好的 bean,可以直接使用
Object singletonObject = this.singletonObjects.get(beanName);
/*
* 如果 singletonObject = null,表明还没创建,或者还没完全创建好。
* 这里判断 beanName 对应的 bean 是否正在创建中
*/
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 从 earlySingletonObjects 中获取提前曝光的 bean,用于处理循环引用
singletonObject = this.earlySingletonObjects.get(beanName);
// 如果如果 singletonObject = null,且允许提前曝光 bean 实例,则从相应的 ObjectFactory 获取一个原始的(raw)bean(尚未填充属性)
if (singletonObject == null && allowEarlyReference) {
// 获取相应的工厂类
ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 提前曝光 bean 实例,用于解决循环依赖
singletonObject = singletonFactory.getObject();
// 放入缓存中,如果还有其他 bean 依赖当前 bean,其他 bean 可以直接从 earlySingletonObjects 取结果
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
这个方法首先尝试从singletonObjects里面获取实例,如果获取不到再从earlySingletonObjects里面获取,如果还获取不到,再尝试从singletonFactories里面获取beanName对应的ObjectFactory,然后调用这个ObjectFactory的getObject来创建bean,并放到earlySingletonObjects里面去,并且从singletonFactories里面remove掉这个ObjectFactory,对于后续的所有内存操作都只是为了循环依赖检测时候使用,也就是allowEarlyReference为true的情况下使用。(这个后面解决循环依赖的时候会讲到)
这里涉及用于存储bean的不同的map,简单解释下:
我们知道,Spring支持配置继承,在标签中可以使用parent属性配置父类bean。这样子类bean可以继承父类bean的配置信息,同时也可以覆盖父类中的配置。
源码分析如下:
protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
// 检查缓存中是否存在“已合并的 BeanDefinition”,若有直接返回即可
RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
if (mbd != null) {
return mbd;
}
// 调用重载方法
return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
}
protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
throws BeanDefinitionStoreException {
// 继续调用重载方法
return getMergedBeanDefinition(beanName, bd, null);
}
protected RootBeanDefinition getMergedBeanDefinition(
String beanName, BeanDefinition bd, BeanDefinition containingBd)
throws BeanDefinitionStoreException {
synchronized (this.mergedBeanDefinitions) {
RootBeanDefinition mbd = null;
if (containingBd == null) {
mbd = this.mergedBeanDefinitions.get(beanName);
}
if (mbd == null) {
// bd.getParentName() == null,表明无父配置,这时直接将当前的 BeanDefinition 升级为 RootBeanDefinition
if (bd.getParentName() == null) {
if (bd instanceof RootBeanDefinition) {
mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
}
else {
mbd = new RootBeanDefinition(bd);
}
}
else {
BeanDefinition pbd;
try {
String parentBeanName = transformedBeanName(bd.getParentName());
/*
* 判断父类 beanName 与子类 beanName 名称是否相同。若相同,则父类 bean 一定
* 在父容器中。原因也很简单,容器底层是用 Map 缓存 键值对
* 的。同一个容器下,使用同一个 beanName 映射两个 bean 实例显然是不合适的。
* 有的朋友可能会觉得可以这样存储: ,似乎解决了
* 一对多的问题。但是也有问题,调用 getName(beanName) 时,到底返回哪个 bean
* 实例好呢?
*/
if (!beanName.equals(parentBeanName)) {
/*
* 这里再次调用 getMergedBeanDefinition,只不过参数值变为了
* parentBeanName,用于合并父 BeanDefinition 和爷爷辈的
* BeanDefinition。如果爷爷辈的 BeanDefinition 仍有父
* BeanDefinition,则继续合并
*/
pbd = getMergedBeanDefinition(parentBeanName);
}
else {
// 获取父容器,并判断,父容器的类型,若不是 ConfigurableBeanFactory 则判抛出异常
BeanFactory parent = getParentBeanFactory();
if (parent instanceof ConfigurableBeanFactory) {
pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
}
else {
throw new NoSuchBeanDefinitionException(parentBeanName,
"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
"': cannot be resolved without an AbstractBeanFactory parent");
}
}
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
}
// 以父 BeanDefinition 的配置信息为蓝本创建 RootBeanDefinition,也就是“已合并的 BeanDefinition”
mbd = new RootBeanDefinition(pbd);
// 用子 BeanDefinition 中的属性覆盖父 BeanDefinition 中的属性
mbd.overrideFrom(bd);
}
// 如果用户未配置 scope 属性,则默认将该属性配置为 singleton
if (!StringUtils.hasLength(mbd.getScope())) {
mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
}
if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
mbd.setScope(containingBd.getScope());
}
if (containingBd == null && isCacheBeanMetadata()) {
// 缓存合并后的 BeanDefinition
this.mergedBeanDefinitions.put(beanName, mbd);
}
}
return mbd;
}
}
上面的getSingleton方法是从缓存中获取单例的过程,那么如果缓存中不存在已经加载的单例bean,就需要从头开始bean的加载过程了,而Spring中使用getSingleton的重载方法实现bean的加载过程。
public Object getSingleton(String beanName, ObjectFactory> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// Has the singleton object implicitly appeared in the meantime ->
// if yes, proceed with it since the exception indicates that state.
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
上述的代码其实使用了回调方法,使得程序可以在单例创建前后可以做一些准备以及处理操作,而真正的获取单例bean的方法其实不是在此方法中实现的,其实现逻辑实在ObjectFactory类型的实例singletonFactory中实现的。而这些准备及处理操作包含以下内容:
1.检查缓存是否已经加载过
2.若没有加载,则记录该beanName的正在加载状态
3.加载单例前记录加载状态,也就是通过beforeSingletonCreation(beanName)方法记录加载状态
4.通过调用参数传入的ObjectFactory的个体Object方法实例化bean
5.加载单例后的处理方法调用,通过afterSingletonCreation(beanName)方法移除缓存中对该bean的正在加载状态的记录
6.通过 addSingleton(beanName, singletonObject)将结果记录至缓存并删除加载bean过程中所记录的各种辅助状态。
7.返回处理结果
在getBean方法中,getObjectForBeanInstance是一个高频率使用的方法,无论是从缓存中获得bean还是根据不同的scope策略加载bean。总之,我们得到的bean实例后要做的第一步就是调用这个方法检测一下正确性,其实就是检测当前的bean是否是FactoryBean类型的bean,如果是,那么需要调用该bean对应的FactoryBean实例中getObject()作为返回值。
无论从缓存中获得到的bean还是通过不同scope策略加载的bean都只是最原始的bean状态,并不是我们最终想要的那个bean。举个例子,假设我们需要对工厂bean进行处理,那么这里得到的其实是bean的初始状态,但是我们真正需要的是工厂bean中定义的factory-method方法中返回的bean,而getObjectForBeanInstance方法就是完成这个工作的。
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// 如果 name 以 & 开头,但 beanInstance 却不是 FactoryBean,则认为有问题。
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
}
/*
* 如果上面的判断通过了,表明 beanInstance 可能是一个普通的 bean,也可能是一个
* FactoryBean。如果是一个普通的 bean,这里直接返回 beanInstance 即可。如果是
* FactoryBean,则要调用工厂方法生成一个 bean 实例。
*/
if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
Object object = null;
if (mbd == null) {
/*
* 如果 mbd 为空,则从缓存中加载 bean。FactoryBean 生成的单例 bean 会被缓存
* 在 factoryBeanObjectCache 集合中,不用每次都创建
*/
object = getCachedObjectForFactoryBean(beanName);
}
if (object == null) {
// 经过前面的判断,到这里可以保证 beanInstance 是 FactoryBean 类型的,所以可以进行类型转换
FactoryBean> factory = (FactoryBean>) beanInstance;
// 如果 mbd 为空,则判断是否存在名字为 beanName 的 BeanDefinition
if (mbd == null && containsBeanDefinition(beanName)) {
// 合并 BeanDefinition
mbd = getMergedLocalBeanDefinition(beanName);
}
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 调用 getObjectFromFactoryBean 方法继续获取实例
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
return object;
}
getObjectForBeanInstance中要做的工作:
1.对FactoryBean正确性的验证。
2.对非FactoryBean不做任何处理。
3.对bean进行转换。
4.将从Factory中解析bean的工作委托给getObjectFormFactoryBean。
getObjectFormFactoryBean源码如下:
protected Object getObjectFromFactoryBean(FactoryBean> factory, String beanName, boolean shouldPostProcess) {
/*
* FactoryBean 也有单例和非单例之分,针对不同类型的 FactoryBean,这里有两种处理方式:
* 1. 单例 FactoryBean 生成的 bean 实例也认为是单例类型。需放入缓存中,供后续重复使用
* 2. 非单例 FactoryBean 生成的 bean 实例则不会被放入缓存中,每次都会创建新的实例
*/
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
// 从缓存中取 bean 实例,避免多次创建 bean 实例
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 {
// shouldPostProcess 等价于上一个方法中的 !synthetic,用于表示是否应用后置处理
if (object != null && shouldPostProcess) {
if (isSingletonCurrentlyInCreation(beanName)) {
return object;
}
beforeSingletonCreation(beanName);
try {
// 应用后置处理
object = postProcessObjectFromFactoryBean(object, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Post-processing of FactoryBean's singleton object failed", ex);
}
finally {
afterSingletonCreation(beanName);
}
}
// 这里的 beanName 对应于 FactoryBean 的实现类, FactoryBean 的实现类也会被实例化,并被缓存在 singletonObjects 中
if (containsSingleton(beanName)) {
// FactoryBean 所创建的实例会被缓存在 factoryBeanObjectCache 中,供后续调用使用
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;
}
}
在这个方法里只做了一件事情,就是返回的bean如果是单例的,那就必须保证全局唯一,同时,也因为是单例的,所以不必重复创建,可以使用缓存来提高性能,也就是说已经加载过就要就要记录下来以便下次复用,否则的话,直接获取了。
doGetObjectFromFactoryBean方法解析:
private Object doGetObjectFromFactoryBean(final FactoryBean> factory, final String beanName)
throws BeanCreationException {
Object object;
try {
// if 分支的逻辑是 Java 安全方面的代码,可以忽略,直接看 else 分支的代码
if (System.getSecurityManager() != null) {
AccessControlContext acc = getAccessControlContext();
try {
object = AccessController.doPrivileged(new PrivilegedExceptionAction() {
@Override
public Object run() throws Exception {
return factory.getObject();
}
}, acc);
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 调用工厂方法生成 bean 实例
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;
}
如果bean声明为FactoryBean类型,则当提取bean时提取的不是FactoryBean,而是FactoryBean对应的getObject方法返回的bean,而doGetObjectFromFactoryBean正是实现这个功能的。
得到了返回结果并没有直接返回,又做了后处理的操作,这个在后面会解析到。
getObjectForBeanInstance及它所调用的方法主要做了如下几件事情:
1.检测参数beanInstance的类型,如果是非FactoryBean类型的bean,直接返回
2.检测FactoryBean实现类是否单例类型,针对单例和非单例进行不同处理
3.对于单例FactoryBean,先从缓存中获取FactoryBean生成的实例
4.若缓存未命中,则调用FactoryBean.getObject()方法生成实例,并放入缓存中
5.对于非单例的FactoryBean,每次直接创建新的实例,无需缓存
6.如果shouldPostProcess=true,不管是单例还是非单例FactoryBean生成的实例,都要进行后置处理。
本文参考:Spring IOC 容器源码分析 - 获取单例 bean
《Spring源码深度解析》