前言

在《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的前世今生的更多相关文章

  1. 一次性讲清楚spring中bean的生命周期之三:bean是如何实例化的

    在前面的两篇博文<一次性讲清楚spring中bean的生命周期之一:getSingleton方法>和<一次性讲清楚spring中bean的生命周期之二:FactoryBean的前世今 ...

  2. 一次性讲清楚spring中bean的生命周期之一:getSingleton方法

    要想讲清楚spring中bean的生命周期,真的是不容易,以AnnotationConfigApplicationContext上下文为基础来讲解bean的生命周期,AnnotationConfigA ...

  3. JAVA面试题:Spring中bean的生命周期

    Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一 ...

  4. 深入理解Spring中bean的生命周期

    [Spring中bean的生命周期] bean的生命周期 1.以ApplocationContext上下文单例模式装配bean为例,深入探讨bean的生命周期: (1).生命周期图: (2).具体事例 ...

  5. Spring中Bean的生命周期及其扩展点

    原创作品,可以转载,但是请标注出处地址http://www.cnblogs.com/V1haoge/p/6106456.html Spring中Bean的管理是其最基本的功能,根据下面的图来了解Spr ...

  6. 简:Spring中Bean的生命周期及代码示例

    (重要:spring bean的生命周期. spring的bean周期,装配.看过spring 源码吗?(把容器启动过程说了一遍,xml解析,bean装载,bean缓存等)) 完整的生命周期概述(牢记 ...

  7. 通过BeanPostProcessor理解Spring中Bean的生命周期

    通过BeanPostProcessor理解Spring中Bean的生命周期及AOP原理 Spring源码解析(十一)Spring扩展接口InstantiationAwareBeanPostProces ...

  8. 一分钟掌握Spring中bean的生命周期!

    Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean 的别名只能维持 ...

  9. Spring中bean的生命周期!

    Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一 ...

随机推荐

  1. Alpha事后分析

    设想和目标 1. 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件的功能主要是让一些基于表单识别的项目(如微软智能表单识别项目)减少在数据生成方面上浪费的 ...

  2. Linux后台执行命令:&和nohup nohup和&后台运行,进程查看及终止

    nohup和&后台运行,进程查看及终止   阅读目录 nohup和&后台运行,进程查看及终止 1.nohup 2.& 3.nohup和&的区别 &:是指在后台运 ...

  3. bashshell删除列

    删除所有空白列cat yum.log | awk '{$1=$2=$3=$4=null;print $0}'>>yum.log7删除文件中的所有空格sed -i s/[[:space:]] ...

  4. /etc/ssh/sshd_config ssh自动断 cent7

    vim /etc/ssh/sshd_config ClientAliveInterval 60ClientAliveCountMax 8630000 ClientAliveInterval 30Cli ...

  5. 微信引流的方式 PC控制手机的方式

    http://www.yunjing100.cn/ 云鲸一百 小萝卜 http://www.xiaoluobei.com/

  6. xxl-job使用遇到的问题(二)

    xxl-job使用遇到的问题(二) 关联阅读 xxl-job使用遇到的问题(一) 1.问题现象 最近有个老定时任务迁移到xxl-job的时候,遇到一个小问题.虽然很快解决,但是还是有必要记录一下~ j ...

  7. C# DeepClone 深拷贝

    常规利用反射进行克隆 public static T CloneModel<T>(T oModel) { var oRes = default(T); var oType = typeof ...

  8. nignx反向代理web服务器的配置与使用

    一.为什么要用nignx反向代理 1.负载均衡 当一台服务器的单位时间内的访问量越大时,服务器压力就越大,大到超过自身承受能力时,服务器就会崩溃.为了避免服务器崩溃,让用户有更好的体验,我们通过负载均 ...

  9. Git如何下载clone指定的tag

    Git如何下载clone指定的tag 如上图,我想下载Tags标签为solution-4 的代码,如何处理呢? 命令如下: git clone --branch solution-4 git@gith ...

  10. Java中如何将函数名作为参数传递

    采用lambda表达式: import java.util.function.Function; class Test { public static void main(String... args ...