Spring FactoryBean 和工厂方法模式有什么区别?
简化版
FactoryBean 是 Spring 提供的扩展接口,用来让某个 Bean 负责生产另一个 Bean;工厂方法模式是通用设计模式,用抽象工厂方法延迟具体产品创建。FactoryBean 可以体现工厂思想,但它是容器机制的一部分,不等同于 GoF 工厂方法模式。
详细版
Spring 中容易混淆三个概念:BeanFactory、FactoryBean 和工厂方法模式。BeanFactory 是 Spring 容器的基础接口,负责管理 Bean;FactoryBean<T> 是一种特殊 Bean,容器调用它的 getObject() 获得真正暴露给业务的对象;工厂方法模式则是一种面向对象创建型模式。
FactoryBean 常用于复杂对象创建,比如代理对象、连接客户端、Mapper、框架适配对象。它的重点不是让子类覆盖创建方法,而是把复杂创建逻辑接入 Spring 生命周期、依赖注入和作用域管理。
面试回答可以抓住:
| 概念 | 角色 |
|---|---|
| BeanFactory | 容器本身 |
| FactoryBean | 生产 Bean 的特殊 Bean |
| 工厂方法模式 | 解耦产品创建的设计模式 |
所以 FactoryBean 可以是工厂模式在 Spring 中的工程化落地,但不能简单说它就是工厂方法模式。
完整版教学
一、先区分 BeanFactory 和 FactoryBean
BeanFactory 是 Spring 容器接口,负责根据 Bean 定义创建、装配、缓存和返回 Bean。FactoryBean 则是用户实现的一个特殊 Bean,它本身被容器管理,但它生产的对象才是普通 getBean() 返回的主要对象。
BeanFactory:Spring 容器
FactoryBean:容器里的一个特殊工厂 Bean
getObject():生产真正业务对象
名字相近是这题的主要陷阱。面试里如果把 BeanFactory 和 FactoryBean 说反,基本说明对 Spring 容器机制不熟。
二、FactoryBean 的基本工作方式
一个 FactoryBean<T> 通常实现三个方法:getObject() 返回产品对象,getObjectType() 返回产品类型,isSingleton() 告诉容器产品是否按单例语义缓存。
public class ClientFactoryBean implements FactoryBean<Client> {
@Override
public Client getObject() {
return new Client("https://api.example.com");
}
@Override
public Class<?> getObjectType() {
return Client.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
如果注册 Bean 名为 client,通常 getBean("client") 返回的是 Client,而不是 ClientFactoryBean 本身。要拿工厂本身,需要使用特殊前缀 &client。
三、它和工厂方法模式相似在哪里
相似点在于都把对象创建封装起来,调用方不直接 new 复杂对象。业务代码只依赖最终产品,比如 Client 接口,而不用知道它是否由代理、反射、配置文件或网络元数据创建。
例如 MyBatis 的 Mapper 代理、AOP 代理、某些客户端 SDK 都可能需要复杂创建过程。用 FactoryBean 后,复杂过程被封装在 getObject() 中,容器仍能完成依赖注入和生命周期管理。
业务类 -> 注入 Client
Spring -> 调用 FactoryBean.getObject()
FactoryBean -> 创建代理/客户端/适配对象
这种思想符合工厂封装创建的精神,但实现方式是 Spring 容器协议,不是标准 GoF 角色结构。
四、它和 GoF 工厂方法模式不同在哪里
GoF 工厂方法模式强调“抽象 Creator 声明工厂方法,具体 Creator 决定创建哪种 Product”。FactoryBean 更强调“让容器通过统一协议取得某个复杂 Bean”。它不要求有一组具体工厂子类,也不要求客户端持有工厂抽象。
| 维度 | FactoryBean | 工厂方法模式 |
|---|---|---|
| 所属领域 | Spring 容器扩展点 | 通用设计模式 |
| 创建入口 | getObject() | 抽象工厂方法 |
| 生命周期 | 由 Spring 管理 | 由代码设计决定 |
| 调用方 | 通常直接注入产品 | 可能依赖工厂抽象 |
| 典型目的 | 接入复杂 Bean 创建 | 多态扩展产品创建 |
所以更准确的表述是:FactoryBean 是 Spring 用来定制 Bean 创建的机制,内部可以运用工厂方法思想。
五、& 前缀为什么是高频追问
因为 FactoryBean 本身也是一个 Bean,但默认名字返回的是它生产的对象。Spring 用 & 前缀区分“我要产品”还是“我要工厂本身”。
getBean("client") -> ClientFactoryBean.getObject() 的结果
getBean("&client") -> ClientFactoryBean 实例本身
假设 client 的产品对象是 1 个代理客户端,工厂对象也是 1 个 Bean。如果你调试时发现类型对不上,首先要检查是否混淆了这两个层级。这也是很多 Spring 面试会问 FactoryBean 的原因。
记忆钩子:BeanFactory 是容器,FactoryBean 是容器里的工厂,
&name拿工厂本身,name拿产品。
六、FactoryBean 的单例语义要谨慎理解
isSingleton() 描述的是 FactoryBean 生产的对象是否按单例语义处理,不是说工厂类本身是否只有一个。工厂 Bean 本身也受 Spring Bean scope 影响。
一个数字例子:如果 isSingleton() 返回 true,连续 100 次 getBean("client") 应返回同一个产品引用;如果返回 false,容器可能每次调用 getObject() 产生新对象。具体还要结合 Spring 版本和缓存策略理解,但面试层面要把工厂对象和产品对象两层分开。
如果产品对象持有连接池、线程池等资源,单例/多例语义还会影响资源释放。复杂资源更要配合销毁回调,而不是只实现 getObject()。
七、什么时候使用 FactoryBean
适合使用 FactoryBean 的场景通常有三个特点:
- 产品对象创建过程复杂,普通构造器或
@Bean方法不够表达; - 产品可能是动态代理或框架对象,不是简单 POJO;
- 希望创建过程接入 Spring 的依赖注入、类型推断和生命周期。
如果只是创建一个普通服务类,直接 @Component 或 @Bean 更清楚。过度使用 FactoryBean 会让 Bean 来源难追踪,也会增加调试成本。
八、常见误区与追问
- 误区:BeanFactory 和 FactoryBean 是同一个东西。 前者是容器接口,后者是用户可实现的特殊工厂 Bean。
- 误区:FactoryBean 就等于 GoF 工厂方法模式。 它可以体现工厂思想,但本质是 Spring 扩展机制。
- 误区:
getBean("x")一定返回工厂对象。 对 FactoryBean 来说默认返回产品对象,&x才返回工厂本身。 - 误区:
isSingleton()只影响 FactoryBean 自己。 它主要描述产品对象的单例语义。 - 追问:FactoryBean 适合创建什么对象? 动态代理、复杂客户端、框架适配对象和无法直接构造的产品。
- 追问:普通
@Bean方法是不是工厂方法? 它是 Spring 配置中的工厂方法写法,但不等于完整 GoF 工厂方法模式。 - 追问:FactoryBean 的坏处是什么? 增加理解和调试成本,过度使用会隐藏产品对象创建路径。
九、加强记忆
这题按三层记:BeanFactory 是容器,FactoryBean 是特殊 Bean,工厂方法模式是通用创建型模式。回答时再补上 getObject()、getObjectType()、isSingleton() 和 &name 语义,基本就能覆盖高频追问。