FactoryBean源码解析

文章目录

一、简介

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

二、FactoryBean 接口的方法

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

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

三、FactoryBean 与 BeanFactory 的区别

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

四、源码解析

首先我们先找到 Spring 启动时,初始化 Bean 的核心方法,位于 AbstractApplicationContext 类 refresh 方法里的 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,就返回其实例本身,这就是我们上面说的,如果 FactoryBean 的 beanName 前面带了 & 符号,就返回 FactoryBean 本身。

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

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

我们可以看到,最终调用了 FactoryBean 的 getObject 方法

五、实际应用

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

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

相关推荐
Sarvartha6 小时前
final 关键字
java·开发语言
2601_952047796 小时前
单一策略深度教程:用轻易云把集成任务的报错实时推送到钉钉机器人
java·机器人·钉钉
Joy T7 小时前
Spring AI 项目中的 pom.xml、application.yml 与 Nacos:从依赖管理到运行配置
spring·nacos·pom.xml·profile·参数配置·application.yml
数据狐(Datafox)7 小时前
淘宝图片搜索 API 落地实战:基于以图搜货搭建跨境电商选品系统
java·大数据·微服务
李日华大战鸡红9 小时前
FOC状态空间方程模型推导(学习记录)
python·学习·线性代数
Escalating_xu9 小时前
【C 语言】数据在内存中的存储:补码、大小端、整型陷阱与 IEEE 754 全解析
java·c语言·网络
灯澜忆梦9 小时前
【面向对象编程C++】| 基础语法
java·c++·算法
一个风轻云淡9 小时前
GCC 和 GDB命令简单解读
java·linux·前端