您好,登录后才能下订单哦!
# Spring中 BeanFactory 与 FactoryBean 的区别是什么
## 前言
在Spring框架的核心容器模块中,`BeanFactory`和`FactoryBean`是两个名称相似但功能完全不同的接口,初学者很容易混淆。本文将深入剖析二者的设计理念、使用场景和底层实现,通过源码解析和实际案例演示它们的本质区别。
---
## 一、基础概念解析
### 1.1 BeanFactory:Spring的IoC基础容器
**定义**:
`org.springframework.beans.factory.BeanFactory`是Spring框架最基础的IoC容器接口,提供了DI(依赖注入)的核心能力。
**核心特征**:
- 基础容器功能(Bean的实例化、依赖注入)
- 延迟加载机制(默认行为)
- 支持多种Bean作用域(Singleton/Prototype等)
```java
public interface BeanFactory {
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType);
// 其他方法...
}
定义:
org.springframework.beans.factory.FactoryBean
是一个用于创建复杂对象的工厂接口,本身也是一个由Spring管理的Bean。
核心特征: - 生产对象的工厂模式实现 - 可以返回任意类型的对象实例 - 支持单例/原型模式控制
public interface FactoryBean<T> {
T getObject() throws Exception;
Class<?> getObjectType();
boolean isSingleton();
}
维度 | BeanFactory | FactoryBean |
---|---|---|
接口层级 | 顶级核心接口(容器本身) | 扩展接口(特殊的Bean类型) |
实现类示例 | DefaultListableBeanFactory | SqlSessionFactoryBean |
注册方式 | 容器根接口 | 作为普通Bean注册到容器中 |
@startuml
interface BeanFactory
interface FactoryBean
class DefaultListableBeanFactory {
+ getBean()
}
class MyFactoryBean {
+ getObject()
+ getObjectType()
}
BeanFactory <|-- DefaultListableBeanFactory
FactoryBean <|.. MyFactoryBean
DefaultListableBeanFactory --> FactoryBean : 包含
@enduml
BeanFactory: - 作为容器角色管理所有Bean的生命周期 - 提供基础的依赖查找(DL)能力 - 构成整个框架的基础设施
FactoryBean: - 作为工厂角色创建特定类型的复杂对象 - 隐藏对象创建的复杂细节 - 通常用于集成第三方库(如MyBatis的SqlSessionFactory)
// 获取容器实例
BeanFactory factory = new XmlBeanFactory(
new ClassPathResource("applicationContext.xml"));
// 获取普通Bean
MyService service = factory.getBean(MyService.class);
<!-- 配置FactoryBean -->
<bean id="toolFactory" class="com.example.ToolFactoryBean">
<property name="factoryId" value="9090"/>
</bean>
// 获取FactoryBean产品对象
Tool tool = context.getBean("toolFactory"); // 返回的是getObject()结果
// 获取FactoryBean本身
ToolFactoryBean factory = context.getBean("&toolFactory"); // 注意&前缀
BeanFactory核心逻辑(以DefaultListableBeanFactory为例):
public Object getBean(String name) throws BeansException {
// 处理Bean别名
String beanName = transformedBeanName(name);
// 尝试从缓存获取单例
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null) {
return getObjectForBeanInstance(...);
}
// 创建新实例
Object beanInstance = createBean(beanName, mbd, args);
return getObjectForBeanInstance(beanInstance, name, beanName, mbd);
}
FactoryBean处理逻辑:
protected Object getObjectForBeanInstance(
Object beanInstance, String name, String beanName, RootBeanDefinition mbd) {
// 处理&前缀请求
if (BeanFactoryUtils.isFactoryDereference(name)) {
return beanInstance;
}
// 处理FactoryBean产品对象
if (beanInstance instanceof FactoryBean) {
return getObjectFromFactoryBean((FactoryBean<?>) beanInstance, name, !synthetic);
}
return beanInstance;
}
实现类 | 作用 | 所属框架 |
---|---|---|
SqlSessionFactoryBean | 创建MyBatis的SqlSessionFactory | MyBatis-Spring |
ProxyFactoryBean | 创建AOP代理对象 | Spring AOP |
JndiObjectFactoryBean | 获取JNDI资源 | Spring核心 |
自定义FactoryBean示例:
public class TimerFactoryBean implements FactoryBean<StopWatch> {
@Override
public StopWatch getObject() {
return new StopWatch("Custom Timer");
}
@Override
public Class<?> getObjectType() {
return StopWatch.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
&
前缀的特殊含义错误代码:
// 错误地期望获取FactoryBean实例
MyFactoryBean factory = context.getBean("myFactoryBean");
// 实际上应该使用:
MyFactoryBean factory = context.getBean("&myFactoryBean");
错误配置:
<!-- 错误地将普通Bean当作FactoryBean使用 -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"
factory-method="getConnection"/> <!-- 这不是FactoryBean! -->
“A FactoryBean is a bean that is itself a factory for creating other beans.” —— Spring Framework Reference Documentation
对比维度 | BeanFactory | FactoryBean |
---|---|---|
本质 | IoC容器基础接口 | 特殊Bean类型 |
创建目标 | 管理所有Bean | 创建特定复杂对象 |
获取方式 | 直接作为容器使用 | 通过& 前缀获取工厂本身 |
典型实现 | DefaultListableBeanFactory | SqlSessionFactoryBean |
设计模式 | 容器模式 | 工厂方法模式 |
使用频率 | 框架底层使用多 | 业务开发使用多 |
理解BeanFactory
和FactoryBean
的区别,关键在于把握:
1. 角色认知:前者是容器,后者是特殊的生产者
2. 设计意图:前者提供基础设施,后者解决复杂实例化问题
3. 使用场景:根据实际需求选择合适的技术方案
掌握这一区别将帮助开发者更深入地理解Spring框架的设计哲学,在复杂系统集成和框架扩展时做出更合理的技术决策。 “`
注:本文实际约2400字,包含: - 6个主要章节 - 3个代码示例 - 2个图表(表格+UML) - 5个重点标注段落 - 完整的Markdown格式标记
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。