文章目录
- 一、简介
- 二、FactoryBean 接口的方法
- 三、FactoryBean 与 BeanFactory 的区别
- 四、源码解析
- 五、实际应用
一、简介
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()
方法上打上断点,启动服务,看看具体的方法调用栈,可以更好的帮助学习源码。