在常规的 Spring 应用开发中,我们习惯使用 @Component、@Service 或 @Configuration 配合 @Bean 来声明 Bean。对于大多数简单对象(如 Service、Controller),这种方式直观高效。
然而,当需要创建一个初始化过程极为复杂的对象时——例如需要解析繁琐配置、连接外部服务或生成动态代理——若将所有构建逻辑都塞进一个 @Bean 方法中,代码将变得臃肿且难以复用。
此时,Spring 框架提供了一个强大的扩展接口:FactoryBean。它允许我们将复杂对象的创建逻辑封装在一个专门的工厂 Bean 中,从而提升代码的模块化和清晰度。

理解 FactoryBean 的本质
FactoryBean 是 Spring IoC 容器中的一个特殊接口。
- 普通 Bean:容器通过反射直接调用其构造器实例化的对象。
- FactoryBean:它本身也是一个 Bean,但更是一个“生产 Bean 的工厂”。当你向容器请求以它命名的 Bean 时,Spring 并不会返回这个工厂本身,而是会调用其
getObject() 方法,将工厂“生产”出的目标对象交给你。
简而言之,FactoryBean 如同工厂里的“特种生产线”。Spring 容器(主工厂)引入它,并非为了将其作为标准零件,而是为了让它专门负责制造某种工艺复杂的特定产品。
核心接口定义
FactoryBean 的源码非常精炼,仅包含三个核心方法:
public interface FactoryBean<T> {
// 1. 返回工厂生产的对象实例(核心逻辑所在)
@Nullable
T getObject() throws Exception;
// 2. 返回所生产对象的类型
@Nullable
Class<?> getObjectType();
// 3. 标识所生产对象是否为单例(默认true)
default boolean isSingleton() {
return true;
}
}
实战:封装复杂连接的创建
假设我们需要创建一个 MyConnection 对象,其初始化过程包含 URL 拼接、驱动加载等模拟的复杂步骤。
1. 定义目标对象
这是一个普通的 POJO 类。
public class MyConnection {
private String connectionInfo;
public void connect() {
System.out.println("连接成功,信息:" + connectionInfo);
}
public void setConnectionInfo(String connectionInfo) {
this.connectionInfo = connectionInfo;
}
// 省略 getter
}
2. 实现 FactoryBean
创建一个专门的工厂 Bean 来生产 MyConnection。
import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;
@Component // 此 Bean 在容器中的名字默认为 “myConnectionFactoryBean”
public class MyConnectionFactoryBean implements FactoryBean<MyConnection> {
@Override
public MyConnection getObject() throws Exception {
// 在此处封装所有复杂的初始化逻辑
System.out.println(">>> FactoryBean 正在执行复杂的构建流程...");
MyConnection conn = new MyConnection();
// 模拟从复杂配置中解析信息
String config = "jdbc:mysql://localhost:3306/mydb";
conn.setConnectionInfo("解析后的配置: " + config);
return conn;
}
@Override
public Class<?> getObjectType() {
return MyConnection.class;
}
@Override
public boolean isSingleton() {
return true; // 通常此类工厂生产的对象是单例
}
}
3. 测试与获取
关键在于,通过工厂 Bean 的名称获取到的,是其生产的产品,而非工厂本身。
@SpringBootTest
class FactoryBeanTest {
@Autowired
private ApplicationContext applicationContext;
@Test
void testGetBean() {
// 通过工厂Bean的名称,获取其生产的对象
Object bean = applicationContext.getBean("myConnectionFactoryBean");
System.out.println("获取到的对象类型: " + bean.getClass());
if (bean instanceof MyConnection) {
((MyConnection) bean).connect();
}
}
}
执行测试,输出如下:
>>> FactoryBean 正在执行复杂的构建流程...
获取到的对象类型: class com.example.demo.MyConnection
连接成功,信息:解析后的配置: jdbc:mysql://localhost:3306/mydb
进阶:如何获取 FactoryBean 本身?
在某些场景下,我们可能需要直接操作“工厂生产线”(FactoryBean 实例),而非其产品。Spring 提供了一个特殊的语法:在 Bean 名称前添加 & 前缀。
@Test
void testGetFactorySelf() {
// 添加 & 前缀,获取 FactoryBean 本身
Object factoryBean = applicationContext.getBean("&myConnectionFactoryBean");
System.out.println("获取到的对象类型: " + factoryBean.getClass());
// 输出: class com.example.demo.MyConnectionFactoryBean
}
核心辨析:BeanFactory 与 FactoryBean
这是 Spring 面试中的经典问题,清楚区分两者至关重要。
| 特性 |
BeanFactory |
FactoryBean |
| 本质 |
容器 (Container) |
Bean |
| 角色 |
Spring IoC 容器的顶层接口,是管理所有 Bean 的“工厂本体”。 |
Spring 容器内的一种特殊 Bean,是能够生产对象的“工厂零件”。 |
| 职责 |
负责 Bean 的实例化、定位、配置及依赖注入等生命周期管理。 |
由用户实现,专门用于封装和介入复杂 Bean 的创建过程。 |
| 使用 |
applicationContext.getBean() 即是在调用 BeanFactory 的方法。 |
需自定义实现,用以定制化 Bean 的生成逻辑。 |
一句话总结:
- BeanFactory 是承载整个 Spring 应用的心脏(大工厂)。
- FactoryBean 是心脏内一个功能特殊的生产线(小工厂)。
在主流框架中的应用
FactoryBean 设计模式在众多开源框架中得到了广泛应用,彰显了其强大的实用性:
- MyBatis 整合:
SqlSessionFactoryBean。MyBatis 通过此 FactoryBean 在 Spring 中创建 SqlSessionFactory,它封装了数据源配置、Mapper 映射文件加载等复杂初始化过程。
- OpenFeign:在生成声明式 HTTP 客户端接口的动态代理时,也利用了类似的 FactoryBean 机制。
- Spring AOP:经典的
ProxyFactoryBean,用于按需创建 AOP 代理对象。
总结与适用场景
掌握 FactoryBean 有助于深入理解 Spring 框架的扩展机制及第三方库的整合原理。当你面临以下情况时,应考虑使用 FactoryBean:
- 对象的构造逻辑异常复杂,使用 XML 或
@Bean 注解会导致配置冗长混乱。
- 需要将第三方库(无法修改源码)的类实例托管给 Spring 容器。
- 需要动态生成(如通过代理)某个接口的实现类并将其注入容器。
通过封装复杂创建逻辑,FactoryBean 能够显著提升代码的清晰度、可维护性和复用性。

