# 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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。