一次性讲清楚spring中bean的生命周期之二:FactoryBean的前世今生
前言
在《spring中FactoryBean是什么bean》一文中,带着小伙伴学习了spring中的FactoryBean,了解了到了FactoryBean其实是一种生产Bean的bean,也就是FactroyBean的前世是Bean,今生还是Bean,小伙伴要疑惑了都是Bean,但是此Bean非彼Bean。今天带着小伙伴从源码的角度来分析下FactoryBean,重点是getObjectForBeanInstance方法的分析。
前世
在前面说到FactoryBean的前世是一个Bean,是指是一个FactoryBean的实例。先来看下getObjectForBeanInstance方法,
- /**
- * Get the object for the given bean instance, either the bean
- * instance itself or its created object in case of a FactoryBean.
- */
- 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.
//1、判断name是否以&开头- if (BeanFactoryUtils.isFactoryDereference(name)) {
- if (beanInstance instanceof NullBean) {
- return beanInstance;
- }
- if (!(beanInstance instanceof FactoryBean)) {
- throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
- }
- }
- // 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.
//beanInstance不是FactoryBean的实例或name以&开头- if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
- return beanInstance;
- }
- Object object = null;
//mbd即beanDefinition为空,从缓存中取- if (mbd == null) {
- object = getCachedObjectForFactoryBean(beanName);
- }
//缓存中没有,则调用FactoryBean的getObject方法,返回其对象- if (object == null) {
- // Return bean instance from factory.
- FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
- // Caches object obtained from FactoryBean if it is a singleton.
- if (mbd == null && containsBeanDefinition(beanName)) {
- mbd = getMergedLocalBeanDefinition(beanName);
- }
- boolean synthetic = (mbd != null && mbd.isSynthetic());
- object = getObjectFromFactoryBean(factory, beanName, !synthetic);
- }
- return object;
- }
看该方法上的注释,
Get the object for the given bean instance, either the bean instance itself or its created object in case of a FactoryBean.
用我蹩脚的英语翻译过来大概是这个意思,
返回给定的bean Instance的一个对象,该对象可能是bean instance或者是由bean instance(是一个FactoryBean)创建的一个对象。
意思很明白了,该方法有可能返回的是一个FactoryBean的实例,也可能是由FactroyBean生产的实例,关键看方法参数中的前两个,
Object beanInstance spring容器中的一个bean
String name 可能含有&前缀的名称
String beanName bean的规范名称
RootBeanDefintion mbd BeanDefinition
看下面的表格更容易理解该方法在各种情况下的返回值,
beanInstance | name | 返回值 |
FactoryBean的实例 | 带有& | beanInstance |
不是FactoryBean的实例 | 带有& | beanInstance |
FactoryBean的实例 | 不带& | beanInstance生产的对象 |
不是FactoryBean的实例 | 不带& | beanInstance |
通过上面得表格再结合代码就很容易理解,只要是返回beanInstance对象,那么就是FactroyBean的前世,下面看FactoryBean的今生。
今生
这里有两个方法需要分析,分别是getCachedObjectForFactoryBean和getObjectFromFactoryBean。第一个方法是从缓存中获取,也就是说使用FactoryBean生产的bean会单独放在缓存中,非singletonObjects中,这点务必要注意。
getCachedObjectForFactoryBean
先看下该方法的定义,
- @Nullable
- protected Object getCachedObjectForFactoryBean(String beanName) {
- return this.factoryBeanObjectCache.get(beanName);
- }
可以看到很简单就是通过名称从factoryBeanObjectCache中取对象。factoryBeanObjectCache肯定是个map了
- /** Cache of singleton objects created by FactoryBeans: FactoryBean name to object. */
- private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);
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);
- // 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) {
- if (isSingletonCurrentlyInCreation(beanName)) {
- // Temporarily return non-post-processed object, not storing it yet..
- 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);
- }
- }
//把生产的实例对象放到factoryBeanObjectCache缓存中- if (containsSingleton(beanName)) {
- this.factoryBeanObjectCache.put(beanName, object);
- }
- }
- }
- return object;
- }
- }
- else {
//调用getObject方法- 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;
- }
- }
该方法就比较复杂了,主要有doGetObjectFromFactoryBean、beforeSingletonCreation、postProcessObjectFromFactoryBean、afterSingletonCreation方法,重要的一个是doGetFromFactroyBean,也就是真正干活生产bean的方法。其定义如下,其余方法可自行查看
- 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((PrivilegedExceptionAction<Object>) factory::getObject, acc);
- }
- catch (PrivilegedActionException pae) {
- throw pae.getException();
- }
- }
- else {
//调用FactoryBean中的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);
- }
- // Do not accept a null value for a FactoryBean that's not fully
- // initialized yet: Many FactoryBeans just return null then.
- if (object == null) {
- if (isSingletonCurrentlyInCreation(beanName)) {
- throw new BeanCurrentlyInCreationException(
- beanName, "FactoryBean which is currently in creation returned null from getObject");
- }
- object = new NullBean();
- }
- return object;
- }
在上文中的注释部分已经看到最终调用了getObject方法,也就是返回的是FactoryBean中getObject方法的返回值。
总结
主要分析了FactoryBean的底层源码,判断是返回FactoryBean的实例还是返回其生产的实例,主要看bean的类型是否为FactoryBean和名称中是否带&。
推荐:《spring中FactoryBean是什么bean》
《一次性讲清楚spring中bean的生命周期之一:getSingleton方法 》
一次性讲清楚spring中bean的生命周期之二:FactoryBean的前世今生的更多相关文章
- 一次性讲清楚spring中bean的生命周期之三:bean是如何实例化的
在前面的两篇博文<一次性讲清楚spring中bean的生命周期之一:getSingleton方法>和<一次性讲清楚spring中bean的生命周期之二:FactoryBean的前世今 ...
- 一次性讲清楚spring中bean的生命周期之一:getSingleton方法
要想讲清楚spring中bean的生命周期,真的是不容易,以AnnotationConfigApplicationContext上下文为基础来讲解bean的生命周期,AnnotationConfigA ...
- JAVA面试题:Spring中bean的生命周期
Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一 ...
- 深入理解Spring中bean的生命周期
[Spring中bean的生命周期] bean的生命周期 1.以ApplocationContext上下文单例模式装配bean为例,深入探讨bean的生命周期: (1).生命周期图: (2).具体事例 ...
- Spring中Bean的生命周期及其扩展点
原创作品,可以转载,但是请标注出处地址http://www.cnblogs.com/V1haoge/p/6106456.html Spring中Bean的管理是其最基本的功能,根据下面的图来了解Spr ...
- 简:Spring中Bean的生命周期及代码示例
(重要:spring bean的生命周期. spring的bean周期,装配.看过spring 源码吗?(把容器启动过程说了一遍,xml解析,bean装载,bean缓存等)) 完整的生命周期概述(牢记 ...
- 通过BeanPostProcessor理解Spring中Bean的生命周期
通过BeanPostProcessor理解Spring中Bean的生命周期及AOP原理 Spring源码解析(十一)Spring扩展接口InstantiationAwareBeanPostProces ...
- 一分钟掌握Spring中bean的生命周期!
Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean 的别名只能维持 ...
- Spring中bean的生命周期!
Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一 ...
随机推荐
- Redis数据持久化—RDB持久化与AOF持久化
目录 Redis数据持久化-RDB持久化与AOF持久化 RDB持久化 RDB文件的创建 RDB文件的载入 自动间隔性保存 检查保存条件是否满足 AOF持久化 AOF持久化的实现 AOF文件的载入与数据 ...
- slickgrid ( nsunleo-slickgrid ) 8 区域选择与复制粘贴
区域选择 区域选择是通过插件CellRangeSelector实现的,默认不支持跨冻结列进行选择,修正了选择,支持跨冻结列,代码如下,通过判断选择的起点和终点所落在的冻结范围进行计算,如从左往右进行复 ...
- 1.7 Systemd初始化进程
1.7 Systemd初始化进程 Linux操作系统的开机过程是这样的,即从BIOS开始,然后进入Boot Loader,再加载系统内核,然后内核进行初始化,最后启动初始化进程.初始化进程作为Linu ...
- Java 程序流程控制语句
顺序语句 语句:使用分号分隔的代码称作为一个语句 注意:没有写任何代码只是一个分号的时候,也是一条语句,称作空语句 顺序语句就是按照从上往下的顺序执行的语句 Scanner scanner = new ...
- STM32串口编程易错点
注意 串口发送函数 使用STM官方的LIB 中的库函数发送之后 加一点延时 否则会错误 接收数据不正常 正确做法是 加上等待发送完成
- STM32 KEIL 下的 printf 函数
1 //加入以下代码,支持printf函数,而不需要选择use MicroLIB 2 #if 1 3 #pragma import(__use_no_semihosting) 4 //标准库需要的支持 ...
- python 交换变量值为何不需要中间变量
python 元组解包unpacking,同一语句中多重赋值 cpython 认为几种变量的交换是比较常见的,提供了专门的优化指令,像[-5,256]预先放到了整数池中一样,
- 第6讲 | 交换机与VLAN:办公室太复杂,我要回学校
第6讲 | 交换机与VLAN:办公室太复杂,我要回学校 拓扑结构是怎么形成的? 一个交换机肯定不够用,需要多台交换机,交换机之间连接起来,就形成一个稍微复杂的拓扑结构. 如何解决常见的环路问题? 包转 ...
- Linux将一个文件夹或文件夹下的所有内容复制到另一个文件夹
Linux将一个文件夹或文件夹下的所有内容复制到另一个文件夹 1.将一个文件夹下的所有内容复制到另一个文件夹下 cp -r /home/packageA/* /home/cp/packageB ...
- celery 简单示例
目录结构 第一步 celery_task 里面的celery文件 import time from celery import Celery # celery from celery.schedul ...