🔗 关联阅读:推荐先阅读 → 《BeanFactory与FactoryBean:Spring Boot中的核心概念解析》
在Spring框架的底层设计中,FactoryBean是一个充满技巧性的接口,它隐藏着许多开发者容易忽视的重要细节。今天我们就来深入剖析它的核心秘密!
一、FactoryBean的双重身份:工厂与产品
FactoryBean的本质:它是一个能生产其他Bean的工厂Bean。与普通Bean不同,它实现了FactoryBean<T>接口,在Spring容器中具有双重身份:
public interface FactoryBean<T> {
T getObject() throws Exception; // 生产实际需要的Bean
Class<?> getObjectType(); // 返回产品类型
boolean isSingleton(); // 决定产品是否单例
}
二、&符的魔法:获取工厂与产品的区别
假设我们定义了如下FactoryBean:
@Component("myFactoryBean")
public class MyFactoryBean implements FactoryBean<MyProduct> {
@Override
public MyProduct getObject() {
return new MyProduct(); // 创建产品实例
}
@Override
public Class<?> getObjectType() {
return MyProduct.class;
}
}
关键区别对比表
| 获取方式 | 实际获取的对象 | Spring处理逻辑 |
|---|---|---|
getBean("myFactoryBean") | MyProduct实例 | 调用factoryBean.getObject() |
getBean("&myFactoryBean") | MyFactoryBean实例 | 返回FactoryBean本身 |
代码验证:
// 获取产品对象(自动调用getObject())
MyProduct product = (MyProduct) context.getBean("myFactoryBean");
// 获取工厂对象本身(需要&前缀)
MyFactoryBean factory = (MyFactoryBean) context.getBean("&myFactoryBean");
三、对象加载过程与缓存机制深度解析
加载流程时序图
sequenceDiagram
participant C as Spring容器
participant FB as FactoryBean
participant OC as 对象缓存
C->>FB: getBean("myFactoryBean")
alt 首次请求
FB->>FB: 调用getObject()创建新对象
FB->>OC: 存入一级缓存(singletonObjects)
else 非首次请求且isSingleton=true
C->>OC: 直接从一级缓存获取
else isSingleton=false
FB->>FB: 每次调用getObject()创建新对象
end
C-->>C: 返回产品对象
缓存机制的核心逻辑:
-
单例模式(isSingleton()返回true):
- 第一次调用
getBean()时:- 触发
getObject()方法创建对象 - 将产品对象存入一级缓存(singletonObjects)
- 触发
- 后续调用直接返回缓存对象
- 第一次调用
-
原型模式(isSingleton()返回false):
- 每次调用
getBean()都会执行getObject() - 创建全新对象实例
- 不会进行任何缓存
- 每次调用
源码佐证(AbstractBeanFactory):
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
// ✅ 从单例缓存获取
Object object = this.factoryBeanObjectCache.get(beanName);
if (object == null) {
object = doGetObjectFromFactoryBean(factory);
// ✅ 存入一级缓存
this.factoryBeanObjectCache.put(beanName, object);
}
return object;
}
} else {
// ❌ 原型模式直接创建新对象
return doGetObjectFromFactoryBean(factory);
}
}
private Object doGetObjectFromFactoryBean(FactoryBean<?> factory) {
return factory.getObject(); // 最终调用getObject()
}
四、关键问题解答:缓存位置之谜
问题:FactoryBean创建的对象是否存入一级缓存?
答案:分两种情况!
- ✅ 单例产品:存入专门为FactoryBean设计的
factoryBeanObjectCache(本质是单例缓存的特例) - ❌ 原型产品:不缓存,每次创建新对象
📌 重要提示:Spring对FactoryBean创建的对象进行了特殊缓存处理,它们不会进入普通的单例缓存(singletonObjects),而是存储在独立的
factoryBeanObjectCache中。
五、避坑指南:常见使用误区
-
混淆工厂与产品:
// 错误!获取的是产品对象而非工厂 MyFactoryBean factory = context.getBean("myFactoryBean"); // 正确!使用&前缀获取工厂 MyFactoryBean factory = context.getBean("&myFactoryBean"); -
忽视作用域配置:
@Override public boolean isSingleton() { return false; // 必须显式声明作用域 }
总结
FactoryBean的核心秘密可归纳为三点:
- &前缀魔法:区分获取工厂本身还是产品对象
- 缓存双轨制:单例产品特殊缓存,原型产品不缓存
- 作用域控制:通过
isSingleton()决定对象生命周期
理解这些机制后,我们就能在Spring应用中游刃有余地使用FactoryBean实现灵活的对象创建逻辑,同时避免常见的陷阱。