一次性讲清楚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的别名只能维持一 ...
随机推荐
- 安装centos7提示 please make your choice from above
分别输入"1" "2" "q" "yes",如上图 释义如下:
- Yarn 集群环境 HA 搭建
环境准备 确保主机搭建 HDFS HA 运行环境 步骤一:修改 mapred-site.xml 配置文件 [root@node-01 ~]# cd /root/apps/hadoop-3.2.1/et ...
- shell基础之后台运行脚本
使shell脚本后台执行,基本的方法有两种,第一种为在脚本后面追加&符号,第二种为在脚本前面使用nohup命令,结尾再追加&符号 一.后台运行脚本1 1.执行脚本test.sh:./t ...
- 10.15 wget:命令行下载工具
wget命令 用于从网络上下载某些资料,该命令对于能够连接到互联网的Linux系统的作用非常大,可以直接从网络上下载自己所需要的文件. wget的特点如下: 支持断点下载功能. 支持FTP和HTT ...
- python实现给字典添加条目的方法
具体实现方法如下: def addWord(theIndex,word,pagenumber): theIndex.setdefault(word, [ ]).append(pagenumber)#存 ...
- Go语言流程控制02--选择结构之switch
package main import "fmt" /* @星座诊所2(switch) 根据用户输入的出生月份猜测其星座: ·白羊(4) 金牛(5) 双子(6) 巨蟹(7) 狮子( ...
- Jmeter- 笔记10 - 在GUI生成html报告
步骤1.在聚合报告,浏览一个存放jtl文件的路径,输入不存在的jtl文件,确定后会出现如下图弹窗,不用理会,关掉 步骤2.运行脚本 步骤3.打开工具 -> Generate HTML repor ...
- 用python调试Appium和雷电模拟器连接时出现Original error: Could not find 'adb.exe' in PATH
用python调试Appium和雷电模拟器连接时出现Original error: Could not find 'adb.exe' in PATH 确定环境变量没错,用管理员启动Appium就不会出 ...
- 嵌入式Linux设备驱动程序:发现硬件配置
嵌入式Linux设备驱动程序:发现硬件配置 Embedded Linux device drivers: Discovering the hardware configuration Interfac ...
- Django(59)验证和授权
验证和授权概述 Django有一个内置的授权系统.他用来处理用户.分组.权限以及基于cookie的会话系统.Django的授权系统包括验证和授权两个部分.验证是验证这个用户是否是他声称的人(比如用 ...