【spring源码-8】bean的实例化(5)FactoryBean接口

876 阅读2分钟

上一篇【spring源码-7】bean的实例化(4)后置处理

应用示例:

定义类实现 FactoryBean 接口: image.png

测试结果: image.png image.png

现象:

  1. 通过 “myFactoryBean” 获取到的并非是 MyFactoryBean 实例,而是 Student 实例。
  2. 通过 “&myFactoryBean” 获取到了 MyFactoryBean 实例。
  3. spring容器加载完成后,实例化了 MyFactoryBean,没有实例化 Student,获取的时候才完成了实例化。

源码解析

image.png 877 行:实例化bean时会先判断当前bean是否实现了 FactoryBean 接口。
878 行:FactoryBean 的 getBean();

getBean(FACTORY_BEAN_PREFIX + beanName)

image.png 246 行:转换 beanName。调用到本类方法如下:

1. 转换 beanName

image.png

说白了就是 “&beanName” 的 “&” 去掉,返回beanName。

2. 从一级缓存中获取

250 行:先从一级缓存中获取实例。

前提条件:此时上下文对象已经初始化完成,一级缓存中是存在 “MyFactoryBean” 实例的。 beanName 又是转换过后的名称,肯定没有 “&”,此时都能获取到 MyFactoryBean 实例。

  1. applicationContext.getBean("myFactoryBean");
    可以拿到 MyFactoryBean 实例。sharedInstance 就是 MyFactoryBean 的实例。
  2. applicationContext.getBean("&myFactoryBean");
    可以拿到实例,sharedInstance 也是 MyFactoryBean 的实例。

3. getObjectForBeanInstance(sharedInstance, name, beanName, null)

image.png

此时:name 可能有 “&”,beanName 一定没有“&”(前面已经去掉了)。

  1. applicationContext.getBean("myFactoryBean");
    入参:sharedInstance 是 MyFactoryBean 的实例,name = "myFactoryBean",beanName = "myFactoryBean",mbd = null
  2. applicationContext.getBean("&myFactoryBean");
    入参:sharedInstance 是 MyFactoryBean 的实例,name = "&myFactoryBean",beanName = "myFactoryBean",mbd = null

1792 行:如下图所示:判断当前bean是否是“&”,如果有就说明当前获取bean时传的是 "&myFactoryBean"。 image.png
1796 行:再检查下当前bean是否实现了 FactoryBean 接口,如果没有就抛出异常,因为当前就是 FactoryBean 的逻辑。
1802 行:直接返回 MyFactoryBean 实例。

总结:
1792 - 1803 行:applicationContext.getBean("&myFactoryBean")进入 if 判断,最终返回从一级缓存中获取到的 MyFactoryBean 实例


方法走下来,是 applicationContext.getBean("myFactoryBean")的逻辑。

1808 - 1810 行:如果 beanInstance(刚才从一级缓存中获取到实例) 不是 FactoryBean 类型的,就返回。
1817 行:从 factoryBeanObjectCache 缓存中获取实例。

注意:此时的缓存并非是spring容器的一级缓存。
factoryBeanObjectCache 缓存是存储 FactoryBean 类的 getObject() 返回的实例。

1827 行:缓存拿不到就创建。

image.png image.png 169 行:调用到 FactoryBean 的 getObject();创建Student对象并添加到factoryBeanObjectCache 缓存中。

总结:

  1. applicationContext.getBean("")时,传 "&factoryBean" 获取 FactoryBean 实例,传 "factoryBean" 获取 getObject() 返回的对象。
  2. FactoryBean 类会随着IOC容器的创建 完成实例化,但是 getObject() 中的对象不会,只有当获取时才会完成实例化。
  3. getObject() 中的对象也是由IOC完成创建的,但是并没有放在一级缓存中管理,而是放在了factoryBeanObjectCache 缓存中。

注:本文通过源码 + 行说明的方式进行描述,若不好理解可留言。本文仅为个人学习记录,有错误的地方,请大佬们指正。

下一篇【spring源码-9】bean的实例化(6)循环依赖