1、博客内容均出自于咕泡学院架构师第三期
2、架构师系列内容:架构师学习笔记(持续更新)

在 Spring 中,有两个很容易混淆的类:BeanFactory 和 FactoryBean。
BeanFactory: Bean 工厂,是一个工厂(Factory),我们 Spring IOC 容器的最顶层接口就是这个BeanFactory,它的作用是管理 Bean,即实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
FactoryBean: 工厂 Bean,是一个 Bean,作用是产生其他 bean 实例。通常情况下,这种 Bean 没有什么特别的要求,仅需要提供一个工厂方法,该方法用来返回其他 Bean 实例。通常情况下,Bean 无须自己实现工厂模式,Spring 容器担任工厂角色;但少数情况下,容器中的 Bean 本身就是工厂,其作用是产生其它 Bean 实例。

当用户使用容器本身时,可以使用转义字符”&”来得到 FactoryBean 本身,以区别通过 FactoryBean产生的实例对象和 FactoryBean 对象本身。在 BeanFactory 中通过如下代码定义了该转义字符:String FACTORY_BEAN_PREFIX = “&”;
如果 myJndiObject 是一个 FactoryBean,则使用&myJndiObject 得到的是 myJndiObject 对象,而不是 myJndiObject 产生出来的对象。

1、FactoryBean 源码

//工厂Bean,用于产生其他对象
public interface FactoryBean<T> {//获取容器管理的对象实例@NullableT getObject() throws Exception;//获取Bean工厂创建的对象的类型@NullableClass<?> getObjectType();//Bean工厂创建的对象是否是单态模式,如果是单态模式,则整个容器中只有一个实例//对象,每次请求都返回同一个实例对象default boolean isSingleton() {return true;}}

2、AbstractBeanFactory 的 getBean()方法调用 FactoryBean:

在前面我们分析 Spring IOC 容器实例化 Bean 并进行依赖注入过程的源码时,提到在 getBean()方法触发容器实例化 Bean 的时候会调用 AbstractBeanFactory 的 doGetBean()方法来进行实例化的过程,源码如下:

//真正实现向IOC容器获取Bean的功能,也是触发依赖注入功能的地方
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {//根据指定的名称获取被管理Bean的名称,剥离指定名称中对容器的相关依赖//如果指定的是别名,将别名转换为规范的Bean名称final String beanName = transformedBeanName(name);Object bean;// Eagerly check singleton cache for manually registered singletons.//先从缓存中取是否已经有被创建过的单态类型的Bean//对于单例模式的Bean整个IOC容器中只创建一次,不需要重复创建Object sharedInstance = getSingleton(beanName);//IOC容器创建单例模式Bean实例对象if (sharedInstance != null && args == null) {if (logger.isDebugEnabled()) {//如果指定名称的Bean在容器中已有单例模式的Bean被创建//直接返回已经创建的Beanif (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 + "'");}}//获取给定Bean的实例对象,主要是完成FactoryBean的相关处理//注意:BeanFactory是管理容器中Bean的工厂,而FactoryBean是//创建创建对象的工厂Bean,两者之间有区别bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {// Fail if we're already creating this bean instance:// We're assumably within a circular reference.//缓存没有正在创建的单例模式Bean//缓存中已经有已经创建的原型模式Bean//但是由于循环引用的问题导致实例化对象失败if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// Check if bean definition exists in this factory.//对IOC容器中是否存在指定名称的BeanDefinition进行检查,首先检查是否//能在当前的BeanFactory中获取的所需要的Bean,如果不能则委托当前容器//的父级容器去查找,如果还是找不到则沿着容器的继承体系向父级容器查找BeanFactory parentBeanFactory = getParentBeanFactory();//当前容器的父级容器存在,且当前容器中不存在指定名称的Beanif (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// Not found -> check parent.//解析指定Bean名称的原始名称String nameToLookup = originalBeanName(name);if (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}else if (args != null) {// Delegation to parent with explicit args.//委派父级容器根据指定名称和显式的参数查找return (T) parentBeanFactory.getBean(nameToLookup, args);}else {// No args -> delegate to standard getBean method.//委派父级容器根据指定名称和类型查找return parentBeanFactory.getBean(nameToLookup, requiredType);}}//创建的Bean是否需要进行类型验证,一般不需要if (!typeCheckOnly) {//向容器标记指定的Bean已经被创建markBeanAsCreated(beanName);}try {//根据指定Bean名称获取其父级的Bean定义//主要解决Bean继承时子类合并父类公共属性问题final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);// Guarantee initialization of beans that the current bean depends on.//获取当前Bean所有依赖Bean的名称String[] dependsOn = mbd.getDependsOn();//如果当前Bean有依赖Beanif (dependsOn != null) {for (String dep : dependsOn) {if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}//递归调用getBean方法,获取当前Bean的依赖BeanregisterDependentBean(dep, beanName);//把被依赖Bean注册给当前依赖的BeangetBean(dep);}}// Create bean instance.//创建单例模式Bean的实例对象if (mbd.isSingleton()) {//这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象sharedInstance = getSingleton(beanName, () -> {try {//创建一个指定Bean实例对象,如果有父级继承,则合并子类和父类的定义return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.//显式地从容器单例模式Bean缓存中清除实例对象destroySingleton(beanName);throw ex;}});//获取给定Bean的实例对象bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}//IOC容器创建原型模式Bean实例对象else if (mbd.isPrototype()) {// It's a prototype -> create a new instance.//原型模式(Prototype)是每次都会创建一个新的对象Object prototypeInstance = null;try {//回调beforePrototypeCreation方法,默认的功能是注册当前创建的原型对象beforePrototypeCreation(beanName);//创建指定Bean对象实例prototypeInstance = createBean(beanName, mbd, args);}finally {//回调afterPrototypeCreation方法,默认的功能告诉IOC容器指定Bean的原型对象不再创建afterPrototypeCreation(beanName);}//获取给定Bean的实例对象bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}//要创建的Bean既不是单例模式,也不是原型模式,则根据Bean定义资源中//配置的生命周期范围,选择实例化Bean的合适方法,这种在Web应用程序中//比较常用,如:request、session、application等生命周期else {String scopeName = mbd.getScope();final Scope scope = this.scopes.get(scopeName);//Bean定义资源中没有配置生命周期范围,则Bean定义不合法if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");}try {//这里又使用了一个匿名内部类,获取一个指定生命周期范围的实例Object scopedInstance = scope.get(beanName, () -> {beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);}finally {afterPrototypeCreation(beanName);}});//获取给定Bean的实例对象bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch (IllegalStateException ex) {throw new BeanCreationException(beanName,"Scope '" + scopeName + "' is not active for the current thread; consider " +"defining a scoped proxy for this bean if you intend to refer to it from a singleton",ex);}}}catch (BeansException ex) {cleanupAfterBeanCreationFailure(beanName);throw ex;}}// Check if required type matches the type of the actual bean instance.//对创建的Bean实例对象进行类型检查if (requiredType != null && !requiredType.isInstance(bean)) {try {T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);if (convertedBean == null) {throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}return convertedBean;}catch (TypeMismatchException ex) {if (logger.isDebugEnabled()) {logger.debug("Failed to convert bean '" + name + "' to required type '" +ClassUtils.getQualifiedName(requiredType) + "'", ex);}throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}}return (T) bean;
}//获取给定Bean的实例对象,主要是完成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.//容器已经得到了Bean实例对象,这个实例对象可能是一个普通的Bean,//也可能是一个工厂Bean,如果是一个工厂Bean,则使用它创建一个Bean实例对象,//如果调用本身就想获得一个容器的引用,则指定返回这个工厂Bean实例对象//如果指定的名称是容器的解引用(dereference,即是对象本身而非内存地址),//且Bean实例也不是创建Bean实例对象的工厂Beanif (BeanFactoryUtils.isFactoryDereference(name) && !(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.//如果Bean实例不是工厂Bean,或者指定名称是容器的解引用,//调用者向获取对容器的引用,则直接返回当前的Bean实例if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {return beanInstance;}//处理指定名称不是容器的解引用,或者根据名称获取的Bean实例对象是一个工厂Bean//使用工厂Bean创建一个Bean的实例对象Object object = null;if (mbd == null) {//从Bean工厂缓存中获取给定名称的Bean实例对象object = getCachedObjectForFactoryBean(beanName);}//让Bean工厂生产给定名称的Bean对象实例if (object == null) {// Return bean instance from factory.FactoryBean<?> factory = (FactoryBean<?>) beanInstance;// Caches object obtained from FactoryBean if it is a singleton.//如果从Bean工厂生产的Bean是单态模式的,则缓存if (mbd == null && containsBeanDefinition(beanName)) {//从容器中获取指定名称的Bean定义,如果继承基类,则合并基类相关属性mbd = getMergedLocalBeanDefinition(beanName);}//如果从容器得到Bean定义信息,并且Bean定义信息不是虚构的,//则让工厂Bean生产Bean实例对象boolean synthetic = (mbd != null && mbd.isSynthetic());//调用FactoryBeanRegistrySupport类的getObjectFromFactoryBean方法,//实现工厂Bean生产Bean对象实例的过程object = getObjectFromFactoryBean(factory, beanName, !synthetic);}return object;
}

在上面获取给定 Bean 的实例对象的 getObjectForBeanInstance() 方法中 , 会调用FactoryBeanRegistrySupport 类的 getObjectFromFactoryBean()方法,该方法实现了 Bean 工厂生产 Bean 实例对象。
Dereference(解引用):一个在 C/C++中应用比较多的术语,在 C++中,”*”是解引用符号,而”&”是引用符号,解引用是指变量指向的是所引用对象的本身数据,而不是引用对象的内存地址。

3、AbstractBeanFactory 生产 Bean 实例对象

AbstractBeanFactory 类中生产 Bean 实例对象的主要源码如下:
方法实现在这个类里FactoryBeanRegistrySupport

//Bean工厂生产Bean实例对象
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {//Bean工厂是单态模式,并且Bean工厂缓存中存在指定名称的Bean实例对象if (factory.isSingleton() && containsSingleton(beanName)) {//多线程同步,以防止数据不一致synchronized (getSingletonMutex()) {//直接从Bean工厂缓存中获取指定名称的Bean实例对象Object object = this.factoryBeanObjectCache.get(beanName);//Bean工厂缓存中没有指定名称的实例对象,则生产该实例对象if (object == null) {//调用Bean工厂的getObject方法生产指定Bean的实例对象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) {try {object = postProcessObjectFromFactoryBean(object, beanName);}catch (Throwable ex) {throw new BeanCreationException(beanName,"Post-processing of FactoryBean's singleton object failed", ex);}}//将生产的实例对象添加到Bean工厂缓存中this.factoryBeanObjectCache.put(beanName, object);}}return object;}}//调用Bean工厂的getObject方法生产指定Bean的实例对象else {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;}
}//调用Bean工厂的getObject方法生产指定Bean的实例对象
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)throws BeanCreationException {Object object;try {if (System.getSecurityManager() != null) {AccessControlContext acc = getAccessControlContext();try {//实现PrivilegedExceptionAction接口的匿名内置类//根据JVM检查权限,然后决定BeanFactory创建实例对象object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->factory.getObject(), acc);}catch (PrivilegedActionException pae) {throw pae.getException();}}else {//调用BeanFactory接口实现类的创建对象方法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.//创建出来的实例对象为null,或者因为单态对象正在创建而返回nullif (object == null) {if (isSingletonCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName, "FactoryBean which is currently in creation returned null from getObject");}object = new NullBean();}return object;
}

从上面的源码分析中,我们可以看出,BeanFactory 接口调用其实现类的 getObject 方法来实现创建Bean 实例对象的功能。

4、工厂 Bean 的实现类 getObject 方法创建 Bean 实例对象

FactoryBean 的实现类有非常多,比如:Proxy、RMI、JNDI、ServletContextFactoryBean 等等,FactoryBean 接口为 Spring 容器提供了一个很好的封装机制,具体的 getObject()有不同的实现类根据不同的实现策略来具体提供,我们分析一个最简单的 AnnotationTestFactoryBean 的实现源码:

public class AnnotationTestBeanFactory implements FactoryBean<FactoryCreatedAnnotationTestBean> {private final FactoryCreatedAnnotationTestBean instance = new FactoryCreatedAnnotationTestBean();public AnnotationTestBeanFactory() {this.instance.setName("FACTORY");} @Overridepublic FactoryCreatedAnnotationTestBean getObject() throws Exception {return this.instance;} //AnnotationTestBeanFactory 产生 Bean 实例对象的实现@Overridepublic Class<? extends IJmxTestBean> getObjectType() {return FactoryCreatedAnnotationTestBean.class;} @Overridepublic boolean isSingleton() {return true;}
}

其他的 Proxy,RMI,JNDI 等等,都是根据相应的策略提供 getObject()的实现。这里不做一一分析,这已经不是 Spring 的核心功能,感兴趣的可以再去深入研究。

IOC 容器中那些鲜为人知的细节(关于 FactoryBean 和 BeanFactory)相关推荐

  1. IOC 容器中那些鲜为人知的细节

    通过前面章节中对Spring IOC 容器的源码分析,我们已经基本上了解了Spring IOC 容器对Bean 定义资源的定位.载入和注册过程,同时也清楚了当用户通过getBean()方法向IOC 容 ...

  2. IOC 容器中那些鲜为人知的细节(关于 延时加载)

    1.博客内容均出自于咕泡学院架构师第三期 2.架构师系列内容:架构师学习笔记(持续更新)) 通过前面我们对 IOC 容器的实现和工作原理分析,我们已经知道 IOC 容器的初始化过程就是对 Bean定义 ...

  3. IOC 容器中那些鲜为人知的细节(关于 autowiring)

    1.博客内容均出自于咕泡学院架构师第三期 2.架构师系列内容:架构师学习笔记(持续更新) Spring IOC 容器提供了两种管理 Bean 依赖关系的方式: 1).显式管理:通过 BeanDefin ...

  4. java 从一个容器获取对象,如何从 Spring IoC 容器中获取对象?

    前面几篇文章主要分析了 Spring IoC 容器如何初始化,以及解析和注册我们定义的 bean 信息. 其中,「Spring 中的 IoC 容器」对 Spring 中的容器做了一个概述,「Sprin ...

  5. IOC容器中bean的生命周期,iocbean生命周期

    原文地址:http://www.bkjia.com/Javabc/1149957.html IOC容器中bean的生命周期,iocbean生命周期 一.Bean的生命周期 Spring IOC容器可以 ...

  6. IOC容器中bean的生命周期

    一.Bean的生命周期 Spring IOC容器可以管理Bean的生命周期,允许在Bean生命周期的特定点执行定制的任务. Spring IOC容器对Bean的生命周期进行管理的过程如下: (1).通 ...

  7. 头条一面:Spring IOC容器中只存放单例Bean吗?

    最近,很多小伙伴出去面试,感觉自己面的不是很理想,回来后,不少小伙伴把面试题做了记录发给我,让我给大家解析下,然后发出来.当我看到这些面试题时,快速在脑海中构建起了整个知识体系,从基础到框架.从分布式 ...

  8. Spring5 - 向IOC容器中添加组件的4种方式

    文章目录 概述 方式一: @CompentScan 适用场景 Code 方式二: @Bean 适用场景 Code 方式三: @Import 适用场景 Code Demo1 Code Demo2 + 实 ...

  9. 六、spring之通过FactoryBean为ioc容器中添加组件

    前面我们已经介绍了几种为容器中添加组件的方法,今天一起学习通过FactoryBean添加组件的方法. 首先我们准备一个类,也就是我们需要注册进spring的ioc容器中的类 类Color: // 不必 ...

最新文章

  1. sqoop mysql parquet_sqoop一些语法的使用
  2. 2018专业创业赛事服务平台
  3. org.apache.http.client.CircularRedirectException: Circular redirect to http://xxx问题解决
  4. java如何计算html高度,如何检索HTML元素的实际宽度和高度?
  5. 1.20 实例:数字转人民币读法
  6. SAP里会话结束方法(杀死进程)
  7. 【专题】多角度深入解析开放原子开源基金会
  8. VOC和COCO数据集标注格式的介绍
  9. 【numpy】使用numpy/pytorch创建数组时的一点疑问
  10. 2019年第二届全国大学生大数据技能竞赛通知
  11. 无法完成您的itunes store的请求_iTunes 谢幕,盘点它的这 18 年
  12. oracle——expdp与impdp备份使用方法
  13. Ubuntu环境下导入tensorflow弹出FutureWarning: Passing (type, 1)的解决办法
  14. 【线性代数的本质|笔记】抽象几何空间、克莱姆法则及其几何解释
  15. 水果店水果保鲜期延长方法,水果店经营保鲜方法
  16. CSS3窗外闪电下雨动画js特效
  17. VMware桥连接连接网络
  18. 计算机面试专业英语词汇,面试常用英语,英语面试常用词汇?
  19. [Luogu P3960] [UOJ 334] [NOIP 2017 tg]列队
  20. Direct3D 10

热门文章

  1. 使用ViewSwitcher模拟手机屏幕应用分屏和切换
  2. QEMU, KVM, QEMU-KVM 和 Goldfish
  3. 「一道面试题」ArrayList和LinkedList有什么区别及使用场景
  4. hibernate 执行存储过程 方法
  5. svn图形化控制(svnmanager)
  6. Netty4 学习笔记之一:客户端与服务端通信 demo
  7. 那一天,那一月,那一年,那一世,那一瞬
  8. FileStream对象的使用
  9. PDFtoDXF or other Vector Graphics (PDF转 Autocad 的DXF及其他格式矢量图形):pstoedit+Ghostscript...
  10. 人设倒了扶起来:Lazarus 组织利用含木马的IDA Pro 攻击研究员