FactoryBean源码解析

文章目录

一、简介

FactoryBean 是 Spring 框架中的一个接口,用来创建特定类型的 Bean 对象。实现FactoryBean 接口就可以自定义 Bean 对象的创建过程。FactoryBean 本身也是 Bean,会在 Spring 中经历 Bean 的生命周期,而由 FactoryBean 创建的 Bean 不经历 Bean 的生命周期。

二、FactoryBean 接口的方法

FactoryBean 内部包含了一下三个方法:

  • getObject()FactoryBean 最重要的方法,用于返回被管理的Bean对象的实例。
  • getObjectType():返回的 Bean 对象的类型。
  • isSingleton():用于指示返回的 Bean 对象是否为单例。

三、FactoryBean 与 BeanFactory 的区别

有的人分不清 FactoryBeanBeanFactory ,其实只要是粗略看过 Spring 源码的人,都会知道,BeanFactory 是 Spring 容器的顶层接口,这个接口定义了 Spring 容器最基本的功能,如从容器中获取 Bean,判断 Bean 是不是单例等,归根结底它是一个工厂,或者是一个容器,用来创建和管理 Bean 的,而 FactoryBean 是一种特殊的 Bean,注意它是个 Bean,只不过它让我们可以自定义创建 Bean 的过程。

四、源码解析

首先我们先找到 Spring 启动时,初始化 Bean 的核心方法,位于 AbstractApplicationContextrefresh 方法里的 finishBeanFactoryInitialization(beanFactory),在这个方法里,找到最后一行最核心的方法 beanFactory.preInstantiateSingletons() ,在这个方法里,找到下面这段代码。

这段代码是从 Spring 容器里获取所有的非抽象的单例的非懒加载 的 Bean,然后判断是不是 FactoryBean,如果不是,就直接调用 getBean 方法完成初始化,如果是,就判断是不是需要紧急初始化。

这里需要注意,FactoryBean 也是做为一个 Bean 放在 Spring 容器里的,从容器里获取这个 FactoryBean 实例,需要在名称前加上 & 符号,如果不加的话,获取的是 FactoryBean 创建出来的 Bean 实例,所以这里通过 Object bean = getBean(FACTORY_BEAN_PREFIX + beanName); 这样获取,这个 FACTORY_BEAN_PREFIX 就是 & 符号。

另外这里出现了 SmartFactoryBean 这个接口,这个接口是 FactoryBean 的子接口,其内部通过 isEagerInit 方法来控制是否紧急初始化,所以这里代码的意思就是,如果是 SmartFactoryBean 类型的 FactoryBean 并且 isEagerInit 是 true 的,才会立即调用 getBean 方法完成初始化。

我们继续跟着 getBean 方法往里看

继续跟进 doGetBean,找到创建 Bean 实例的核心代码

在调用完 getSingleton 方法后,会将 FactoryBean 实例放到 Spring 容器里,再调用 getObjectForBeanInstance 方法获取 Bean 实例,我们跟进去看看

继续跟进

第一个if判断,用处是防止那种不是 FactoryBean,但是前面带了 & 符号进来的。

第二个if判断,就是如果是普通的 bean 或者是 FactoryBean,就返回其实例本身,这就是我们上面说的,如果 FactoryBeanbeanName 前面带了 & 符号,就返回 FactoryBean 本身。

能继续往下走,就说明一定是 FactoryBean 了,所以类型强转后,调用 getObjectFromFactoryBean 方法,我们继续跟进

这里用了一些缓存的机制,我们不用管,继续跟进 doGetObjectFromFactoryBean 方法

我们可以看到,最终调用了 FactoryBeangetObject 方法

五、实际应用

FactoryBean 的实际应用场景有很多,例如 SpringAop 的 ProxyFactoryBean 用来创建 AOP 代理,Mybatis 的 MapperFactoryBean 用来创建 Mapper 的代理对象,Fegin 的 FeignClientFactoryBean 用来创建远程服务代理。

有兴趣的小伙伴,可以在任意一个 FactoryBeangetObject() 方法上打上断点,启动服务,看看具体的方法调用栈,可以更好的帮助学习源码。

相关推荐
你不是我我8 分钟前
【Java 开发日记】SQL 语句左连接右连接内连接如何使用,区别是什么?
java·javascript·数据库
七夜zippoe26 分钟前
Java性能调优工具篇:JMH基准测试与Profiler(JProfiler/Async-Profiler)使用指南
java·开发语言·jprofiler·jmh·async-profiler
從南走到北31 分钟前
JAVA国际版二手车交易二手车市场系统源码支持Android+IOS+H5+APP
android·java·ios
Kuo-Teng40 分钟前
LeetCode 19: Remove Nth Node From End of List
java·数据结构·算法·leetcode·链表·职场和发展·list
北i42 分钟前
TiDB 关联子查询去关联优化实战案例与原理深度解析
java·数据库·sql·tidb
Kuo-Teng43 分钟前
LeetCode 21: Merge Two Sorted Lists
java·算法·leetcode·链表·职场和发展
我命由我123451 小时前
Java 开发 - 粘包处理器 - 基于消息头 + 消息体(魔数验证、长度验证)
java·网络·后端·网络协议·java-ee·intellij-idea·intellij idea
代码AC不AC1 小时前
【C++】异常
c++·学习·异常
2301_800399721 小时前
stm32 printf重定向到USART
java·stm32·算法
bagadesu1 小时前
15.<Spring Boot 日志>
java·后端