目录

  • 1.`FactoryBean` 接口简述
  • 2.`FactoryBean` 在 `Spring` 中的应用
    • 2.1.`doGetBean()`
      • 2.1.1.`getObjectForBeanInstance()`
        • 2.1.1.1.`getObjectFromFactoryBean()`
          • 2.1.1.1.1.`doGetObjectFromFactoryBean()`
  • 3.总结
    • 3.1.`FactoryBean` 接口的作用
  • 4.测试验证

1.FactoryBean 接口简述

BeanFactoryFactoryBean 接口,相信很多刚翻看 Spring 源码跟我一样很好奇这俩货怎么长得这么像,分别都是干啥用的。BeanFactorySpringBean 工厂的顶层接口,也是我们常说的 Spring IOC 容器,它定下了 IOC 容器的一些规范和常用方法并管理着 Spring 中所有的 Bean,今天我们不讲它,我们看一下后面那个 FactoryBean

public interface FactoryBean<T> {@NullableT getObject() throws Exception;@NullableClass<?> getObjectType();default boolean isSingleton() {return true;}
}

先说下 FactoryBean 和其作用再开始分析:首先它是一个 Bean,但又不仅仅是一个 Bean。它是一个能生产或修饰对象生成的工厂 Bean,类似于设计模式中的工厂模式和装饰器模式。它能在需要的时候生产一个对象,且不仅仅限于它自身,它能返回任何 Bean 的实例

2.FactoryBeanSpring 中的应用

Spring 中我们的 Bean 都会被 SpringIOC 容器所管理,在 AbstractApplicationContext 中有一个很重要的方法:refresh(),项目启动或重启的时候 refresh() 会调用 getBean() 初始化所有的 Bean,这个 getBean() 最终会指向 AbstractBeanFactory 中的 getBean() 方法。上述方法的调用链过长,我们不过多赘述,详细的 getBean() 源码 在这里

AbstractBeanFactory 抽象类中,不管是根据名称还是根据类型,getBean() 方法最终都会调用 doGetBean() 方法

2.1.doGetBean()

doGetBean() 方法中一开始就获取了名称 beanName 和实例 sharedInstance

@SuppressWarnings("unchecked")
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {final String beanName = transformedBeanName(name);Object bean;// 方法解释如下图Object sharedInstance = getSingleton(beanName);// 如果已经初始化过,直接从缓存中获取if (sharedInstance != null && args == null) {if (logger.isDebugEnabled()) {if (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 + "'");}} // 如果 sharedInstance 是普通的单例 bean,下面的方法会直接返回。但如果// 是 FactoryBean 类型的,则需调用 getObject 工厂方法获取真正的 bean 实例bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}else {// 如果是原型不应该在初始化的时候创建,在这里直接抛出异常if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}BeanFactory parentBeanFactory = getParentBeanFactory();if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {// 将别名解析成真正的beanNameString nameToLookup = originalBeanName(name);// 如果parentBeanFactory存在,并且beanName在当前BeanFactory不存在Bean定义,则尝试从parentBeanFactory中获取bean实例if (parentBeanFactory instanceof AbstractBeanFactory) {return ((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}// 尝试在parentBeanFactory中获取bean对象实例else if (args != null) {return (T) parentBeanFactory.getBean(nameToLookup, args);}else {return parentBeanFactory.getBean(nameToLookup, requiredType);}}if (!typeCheckOnly) {markBeanAsCreated(beanName);}try {// 根据beanName重新获取MergedBeanDefinitionfinal RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);checkMergedBeanDefinition(mbd, beanName, args);String[] dependsOn = mbd.getDependsOn();if (dependsOn != null) {// 遍历当前bean依赖的bean名称集合for (String dep : dependsOn) {// 检查dep是否依赖于beanName,即检查是否存在循环依赖if (isDependent(beanName, dep)) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");}// 将dep和beanName的依赖关系注册到缓存中registerDependentBean(dep, beanName);try {getBean(dep);}catch (NoSuchBeanDefinitionException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName,"'" + beanName + "' depends on missing bean '" + dep + "'", ex);}}}// scope为 singleton 的bean创建if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {// 创建Bean实例return createBean(beanName, mbd, args);}catch (BeansException ex) {destroySingleton(beanName);throw ex;}});// 返回beanName对应的实例对象// 这里主要处理实现了FactoryBean的情况,需要调用重写的getObject()方法来获取实际的Bean实例bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}             // scope为 prototype 的bean创建else if (mbd.isPrototype()) {            Object prototypeInstance = null;try {// 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)beforePrototypeCreation(beanName);// 创建Bean实例prototypeInstance = createBean(beanName, mbd, args);}finally {// 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)afterPrototypeCreation(beanName);}// 返回beanName对应的实例对象// 这里主要处理实现了FactoryBean的情况,需要调用重写的getObject()方法来获取实际的Bean实例bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);}else {// 既不是单例也不是原型的 bean创建,可能是 request之类的// 根据scopeName,从缓存拿到scope实例String scopeName = mbd.getScope();final Scope scope = this.scopes.get(scopeName);if (scope == null) {throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");}try {// 既不是单例也不是原型的bean创建Object scopedInstance = scope.get(beanName, () -> {// 创建实例前的操作(将beanName保存到prototypesCurrentlyInCreation缓存中)beforePrototypeCreation(beanName);try {return createBean(beanName, mbd, args);}finally {// 创建实例后的操作(将创建完的beanName从prototypesCurrentlyInCreation缓存中移除)afterPrototypeCreation(beanName);}});// 返回beanName对应的实例对象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;}}// ...... 省略return (T) bean;
}
  • transformedBeanName() 是为了获取 bean 真正的名称,它会去掉 name 前面的 &
  • getSingleton() 是从父类 DefaultSingletonBeanRegistrygetSingleton() 方法中的 singletonObjects 一级缓存中取的这个 bean 的实例


回到 doGetBean() 方法中,拿到 sharedInstance 后,后面的一大堆操作做了单例、多例等判断,最终会走到 getObjectForBeanInstance(),关键部分就在这个方法中,进入方法代码

2.1.1.getObjectForBeanInstance()

protected Object getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {// 如果 name 不为空且以 & 开头if (BeanFactoryUtils.isFactoryDereference(name)) {// beanInstance 属于 NullBean 或其子类的实例if (beanInstance instanceof NullBean) {return beanInstance;}if (!(beanInstance instanceof FactoryBean)) {throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());}}// beanInstance 不是属于 FactoryBean 或其子类的实例,或 name 不为空且以 & 开头if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {return beanInstance;}// 只有当 name 不为空且以 & 开头,并且 beanInstance 属于 FactoryBean 或其子类的实例时,才会执行下面Object object = null;if (mbd == null) {object = getCachedObjectForFactoryBean(beanName);}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;
}

2.1.1.1.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);Object alreadyThere = this.factoryBeanObjectCache.get(beanName);if (alreadyThere != null) {object = alreadyThere;}else {if (shouldPostProcess) {if (isSingletonCurrentlyInCreation(beanName)) {                      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);}}if (containsSingleton(beanName)) {this.factoryBeanObjectCache.put(beanName, object);}}}return object;}}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;}
}
2.1.1.1.1.doGetObjectFromFactoryBean()
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 {// 关键代码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);}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;
}
  • 关键代码 object = factory.getObject() 这个 factory 就是我们传入的 beanInstance 实例。绕了这么一大圈,getBean() 方法返回的居然是我们实现 FactoryBean 接口定义的 getObject() 方法

3.总结

3.1.FactoryBean 接口的作用

一般情况下,Spring 通过反射机制利用的 class 属性指定实现类实例化 Bean,在某些情况下,实例化 Bean 过程比较复杂,如果按照传统的方式,则需要在中提供大量的配置信息。配置方式的灵活性是受限的,这时采用编码的方式可能会得到一个简单的方案。 Spring 为此提供了一个 org.springframework.bean.factory.FactoryBean 的工厂类接口,用户可以通过实现该接口定制实例化 Bean 的逻辑。FactoryBean 接口对于 Spring 框架来说占用重要的地位,Spring 自身就提供了 70 多个 FactoryBean 的实现。它们隐藏了实例化一些复杂 Bean 的细节,给上层应用带来了便利

FactoryBean 是一个能生产或修饰对象生成的工厂 Bean。一个 Bean 如果实现了 FactoryBean 接口,那么根据该 Bean 的名称获取到的实际上是 getObject() 返回的对象,而不是这个 Bean 自身实例,如果要获取这个 Bean 自身实例,那么需要在名称前面加上 & 符号

4.测试验证

下面通过代码测试验证上面的流程,先定义一个 Bean 实现 FactoryBean 接口

@Component
public class MyBean implements FactoryBean {private String message;public MyBean() {this.message = "通过构造方法初始化实例";}@Overridepublic Object getObject() throws Exception {MyBean myBean = new MyBean();myBean.message = "通过FactoryBean.getObject()创建实例";// 这里并不一定要返回MyBean自身的实例,可以是其他任何对象的实例return myBean;}@Overridepublic Class<?> getObjectType() {return MyBean.class;}public String getMessage() {return message;}
}

MyBean 实现了 FactoryBean 接口的两个方法,getObject() 是可以返回任何对象的实例的,这里测试就返回 MyBean 自身实例,且返回前给 message 字段赋值。同时在构造方法中也为 message 赋值。然后测试代码中先通过名称获取 Bean 实例,打印 message 的内容,再通过 &+名称 获取实例并打印 message 内容

@RunWith(SpringRunner.class)
@SpringBootTest(classes = TestApplication.class)
public class FactoryBeanTest {@Autowiredprivate ApplicationContext context;@Testpublic void test() {MyBean myBean1 = (MyBean) context.getBean("myBean");System.out.println("myBean1 = " + myBean1.getMessage());MyBean myBean2 = (MyBean) context.getBean("&myBean");System.out.println("myBean2 = " + myBean2.getMessage());System.out.println("myBean1.equals(myBean2) = " + myBean1.equals(myBean2));}
}

结果如下

myBean1 = 通过FactoryBean.getObject()初始化实例
myBean2 = 通过构造方法初始化实例
myBean1.equals(myBean2) = false

Spring源码之FactoryBean接口的作用和实现原理相关推荐

  1. Spring源码解析 - BeanFactory接口体系解读

    不知道为什么看着Spring的源码,感触最深的是Spring对概念的抽象,所以我就先学接口了. BeanFactory是Spring IOC实现的基础,这边定义了一系列的接口,我们通过这些接口的学习, ...

  2. Spring源码:Advice接口

    文章目录 1.Advice接口使用 2.Advice接口源码分析 2.2 AfterReturningAdvice接口 2.3 ThrowsAdvice接口 2.4 MethodInterceptor ...

  3. Spring源码:FactoryBean

    FactoryBean FactoryBean是某个SpringBean的公开的对象的工厂. FactoryBean是一个工厂Bean,可以生成某一个类型Bean实例,它最大的一个作用是:可以让我们自 ...

  4. Spring源码分析番外篇二:事务原理番外篇

    文章目录 1.获取事务 1.1 创建事务实例--doGetTransaction 1.2 处理存在的事务--handleExistingTransaction 1.3 开启新事务 1.3.1 事务开启 ...

  5. Spring源码分析【9】-SpringSecurity密码Remove原理

    很明显代码已经说了认证完成移除credentials和其他某些安全数据 // Authentication is complete. Remove credentials and other secr ...

  6. Spring源码解析 - AbstractBeanFactory 实现接口与父类分析

    2019独角兽企业重金招聘Python工程师标准>>> 我们先来看类图吧: 除了BeanFactory这一支的接口,AbstractBeanFactory主要实现了AliasRegi ...

  7. spring 源码分析(1)-xml文件解析

    我们在最开始接触spring的时候,看到不少书spring入门的例子如下 ApplicationContext atx = new ClassPathXmlApplicationContext(&qu ...

  8. Spring源码分析——汇总全集

    文章目录 一.背景 二.源码分析目录 三.源码番外篇(补充) 更新时间 更新内容 备注 2022-04-01 Spring源码分析目录和计划 2022-04-10 Spring源码分析一:容器篇-re ...

  9. Spring源码分析——资源访问利器Resource之接口和抽象类分析

    从今天开始,一步步走上源码分析的路.刚开始肯定要从简单着手.我们先从Java发展史上最强大的框架--Spring...旗下的资源抽象接口Resource开始吧. 我看了好多分析Spring源码的,每每 ...

  10. Spring源码分析【0】-框架的基础:继承和接口调用链

    Spring源码大量的使用继承和接口调用,现举个例子,不搞清楚这个无法看代码. public class A extends B{public void f1() {System.out.printl ...

最新文章

  1. 我用24小时、8块GPU、400美元在云上完成训练BERT!特拉维夫大学新研究
  2. 国外流行十大PHP框架
  3. 对称加密算法---加密学习笔记(三)
  4. 被LTRIM(RTRIM())害死了,差点
  5. jmete 学习--基础之名词解释
  6. 简单的线性回归实现模型的存储和读取
  7. python开发的类似stardict工具
  8. 生活随笔:师弟,加油
  9. 第四方支付平台程序源码_云计费系统源码
  10. GCDLCM 【米勒_拉宾素数检验 (判断大素数)】
  11. 【实习日报】2019年6月下半月 前端开发实习工作日报汇总
  12. 深度学习(十三) Adversarial Attack 理论部分
  13. “三年拿下全球第一!”7年小米销量冲到全球第二,雷军做对了什么?
  14. 【啃书】《智能优化算法及其MATLAB实例》例6.1基本粒子群算法进行sphere函数寻优
  15. C语言结构体学生基本资料,用结构体定义10个学生基本信息
  16. 安装fabric-2.2.0
  17. 关于log4j日志打印堆栈的记录
  18. Android输入法架构学习总结
  19. 齐岳定制1, 8-萘酰亚胺类荧光化合物,基于萘酰亚胺的fluorogenic荧光探针,双光子、内质网ER靶向双光子荧光探针NI-OPD
  20. 用 Mathematica 生成迷宫

热门文章

  1. 容器技术Docker K8s 28 容器服务ACK基础与进阶-弹性伸缩
  2. 算法:把排好序的链表转换为二叉排序树Convert Sorted List to Binary Search Tree
  3. 区块链环境搭建、环境架构介绍、环境如何用、部署 Chaincode、智能合约的调用
  4. 算法:回溯八 Combinations指定个数组合
  5. 2021-09-08 集成学 习 思想概述
  6. 使用winedt写论文遇到的一些小问题
  7. Pycharm连接远程服务器环境搭建
  8. 多视角子空间学习系列之 CCA 典型相关分析
  9. CONTINUAL LEARNING FOR AUTOMATED AUDIO CAPTIONING USING THE LEARNING WITHOUT FORGETTING APPROACH
  10. cron表达式每一个小时_嵊泗新闻网丨两千小时的热爱——任春华:用志愿服务守护每一个笑容...