BeanFactory vs FactoryBean:Spring核心接口深度解析与实战避坑指南
你是否曾陷入这样的困惑?
- 面试被问二者区别时,大脑突然一片空白?
- 在代码中看到
FactoryBean却不敢随意改动?- 尝试获取Bean时,拿到的不是预期对象?
- 自定义扩展点时,不确定该用哪个接口?
这些问题的根源在于:没有真正理解Spring容器最核心的设计哲学!
作为Spring框架的基石,BeanFactory和FactoryBean虽然名称相似,却代表了截然不同的设计理念。本文将直击痛点,通过源码解析、场景化对比和实战案例,彻底终结你对这两个核心接口的困惑。
一、本质区别:容器骨架 vs 特殊Bean
| 维度 | BeanFactory | FactoryBean |
|---|---|---|
| 定位 | IOC容器顶层接口(骨架) | 特殊Bean创建工厂(零件) |
| 职责 | 管理Bean的生命周期和依赖关系 | 生产特定类型的Bean实例 |
| 设计模式 | 工厂方法模式(容器级) | 工厂方法模式(Bean级) |
| 创建目标 | 所有Bean的创建与管理 | 单个复杂对象的定制化创建 |
| 使用场景 | 所有Spring应用的基础 | 代理对象、连接池、第三方集成等特殊场景 |
| 获取方式 | context.getBean("beanName") | context.getBean("&beanName")获取工厂本身 |
二、源码级解析:深入理解工作机制
1. BeanFactory - 容器的脊柱
核心方法解析:
public interface BeanFactory {
// 基础获取Bean(存在多态问题)
Object getBean(String name) throws BeansException;
// 解决类型安全的获取方式
<T> T getBean(String name, Class<T> requiredType);
// 类型获取(避免命名耦合)
<T> T getBean(Class<T> requiredType);
// 作用域判断
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// 类型判断
boolean isTypeMatch(String name, Class<?> targetType);
}
容器继承体系:
BeanFactory (基础接口)
├── ListableBeanFactory (支持批量获取)
├── HierarchicalBeanFactory (支持父子容器)
└── AutowireCapableBeanFactory (自动装配能力)
└── ConfigurableBeanFactory (配置能力)
└── ApplicationContext (应用上下文) // 实际使用最多的容器
2. FactoryBean - 定制化生产的利器
核心接口定义:
public interface FactoryBean<T> {
// 生产目标对象(核心方法)
T getObject() throws Exception;
// 目标对象类型
Class<?> getObjectType();
// 是否单例(控制对象复用)
boolean isSingleton();
}
经典实现案例 - ProxyFactoryBean(AOP核心):
public class ProxyFactoryBean implements FactoryBean<Object> {
private Object target; // 原始对象
private String[] interceptorNames; // 拦截器
public Object getObject() {
// 创建代理的核心逻辑
return createAopProxy().getProxy();
}
public Class<?> getObjectType() {
return (this.target != null) ?
this.target.getClass() : null;
}
public boolean isSingleton() {
return true;
}
}
三、实战场景对比:如何正确使用与避坑?
场景1:获取Bean时的经典陷阱
// 注册FactoryBean
@Bean
public MyFactoryBean myFactoryBean() {
return new MyFactoryBean();
}
// ❌ 错误方式:获取的是产品对象
Object product = context.getBean("myFactoryBean");
// ✅ 正确方式:获取工厂本身
FactoryBean<?> factory =
(FactoryBean<?>) context.getBean("&myFactoryBean");
场景2:自定义复杂对象创建(数据库连接池)
public class HikariPoolFactoryBean implements FactoryBean<DataSource> {
private HikariConfig config;
public DataSource getObject() {
// 创建复杂连接池对象
return new HikariDataSource(config);
}
// 配置注入
public void setConfig(HikariConfig config) {
this.config = config;
}
// 其他方法实现...
}
// 配置使用
@Bean
public HikariPoolFactoryBean dataSource() {
HikariPoolFactoryBean factory = new HikariPoolFactoryBean();
factory.setConfig(createHikariConfig());
return factory;
}
场景3:集成第三方框架(MyBatis SqlSessionFactory)
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
factory.setMapperLocations(
new PathMatchingResourcePatternResolver()
.getResources("classpath:mappers/*.xml"));
return factory; // 注意:返回的是FactoryBean
}
四、深度辨析:核心差异对照表
| 特性 | BeanFactory | FactoryBean |
|---|---|---|
| 接口类型 | 容器接口 | Bean接口 |
| 实例数量 | 容器中只有一个实现 | 可定义多个不同的实现 |
| 创建时机 | 容器启动时初始化 | 首次请求getBean()时初始化 |
| 扩展点 | 定义容器行为 | 定义单个Bean的创建逻辑 |
| 典型实现 | DefaultListableBeanFactory | ProxyFactoryBean, SqlSessionFactoryBean |
| 是否被代理 | 容器本身不被代理 | 可能被AOP代理 |
| 使用频率 | 100%使用(底层支撑) | 约5-10%的特殊场景 |
五、高频问题解决方案
问题1:如何检测Bean是否是FactoryBean?
if (beanInstance instanceof FactoryBean) {
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
Class<?> objectType = factory.getObjectType();
// 特殊处理逻辑...
}
问题2:FactoryBean如何参与依赖注入?
@Service
public class OrderService {
// 直接注入产品对象(非工厂本身)
@Autowired
private DataSource dataSource; // 来自HikariPoolFactoryBean
// 需要工厂本身时使用全名
@Autowired
@Qualifier("&dataSource")
private FactoryBean<DataSource> dataSourceFactory;
}
问题3:自定义FactoryBean的最佳实践
public class CustomFactoryBean implements FactoryBean<ComplexObject> {
private String configParam;
private DependencyService dependency;
// ✅ 推荐:通过setter注入依赖
@Autowired
public void setDependency(DependencyService dependency) {
this.dependency = dependency;
}
public ComplexObject getObject() {
// 使用依赖和配置构建复杂对象
return dependency.buildComplexObject(configParam);
}
// 配置参数(通过properties设置)
public void setConfigParam(String param) {
this.configParam = param;
}
}
六、性能与安全关键点
-
延迟初始化优化:
@Bean public FactoryBean<ExpensiveResource> resourceFactory() { return new FactoryBean<>() { public ExpensiveResource getObject() { // 实际使用时才初始化 return initExpensiveResource(); } // ... }; } -
防御性编程:
public Object getObject() { if (this.config == null) { throw new IllegalStateException("Configuration not initialized"); } // 安全创建逻辑... } -
并发控制:
public class ThreadSafeFactoryBean implements FactoryBean<Connection> { private final Object lock = new Object(); private Connection connection; public Connection getObject() { synchronized (lock) { if (connection == null || connection.isClosed()) { connection = createConnection(); } return connection; } } }
七、最佳实践总结
-
命名规范:
- FactoryBean实现类后缀明确:
XxxFactoryBean - Bean名称避免歧义:
dataSource(产品) vsdataSourceFactory(工厂)
- FactoryBean实现类后缀明确:
-
使用原则:
graph TD A[需要创建对象] --> B{对象是否复杂?} B -->|是| C[使用FactoryBean] B -->|否| D[普通Bean定义] C --> E{需要依赖注入?} E -->|是| F[在FactoryBean中注入依赖] E -->|否| G[直接创建] -
避坑清单:
- 永远记得使用
&前缀获取FactoryBean本身 - 在FactoryBean中避免
@PostConstruct,改用getObject()内初始化 - 谨慎实现
isSingleton(),错误返回会导致内存泄漏
- 永远记得使用
-
扩展进阶:
- 实现
SmartFactoryBean:对工厂行为更精细控制 - 结合
BeanDefinitionRegistryPostProcessor:动态注册FactoryBean
- 实现
立即行动:
- 在项目中搜索
implements FactoryBean,检查实现是否符合规范- 确认所有FactoryBean的使用是否都正确处理了
&前缀问题- 将任意一个复杂对象的创建重构为FactoryBean实现
- 使用
context.getBean("&beanName")获取工厂实例进行验证
549

被折叠的 条评论
为什么被折叠?



