淺析 Spring 中 FactoryBean 的實現與使用
- 一、FactoryBean核心機制剖析
- 二、高級應用場景與實戰
- 三、框架級應用案例解析
- 四、FactoryBean常見面試題

一、FactoryBean核心機制剖析
1. 本質與雙重角色
FactoryBean是Spring容器中用于定制化對象創建的核心接口(org.springframework.beans.factory.FactoryBean
),其設計體現了兩個關鍵特征:
- 工廠模式:通過getObject()方法動態生成目標對象
- 容器托管:FactoryBean本身作為Spring Bean被容器管理,支持依賴注入和生命周期回調
2. 接口方法詳解
public interface FactoryBean<T> {T getObject() throws Exception; // 核心工廠方法Class<?> getObjectType(); // 決定自動注入的類型匹配default boolean isSingleton() { // 控制對象作用域return true;}
}
運行機制:
Spring容器初始化時,若檢測到Bean實現FactoryBean接口,會通過getObject()
生成目標對象。通過&
前綴獲取工廠實例本身(如getBean("&myFactory")
)
3. 源碼級工作流程
參考Spring源碼的Bean創建流程:
- Bean實例化:
AbstractAutowireCapableBeanFactory.createBeanInstance()
創建FactoryBean實例 - 對象生成:在
getObjectForBeanInstance()
方法中調用getObject()
生成目標對象 - 緩存處理:單例對象存入
factoryBeanObjectCache
,多例對象每次新建
關鍵源碼片段(簡化):
// AbstractBeanFactory.doGetBean()
Object beanInstance = getSingleton(beanName);
if (beanInstance instanceof FactoryBean) {return getObjectFromFactoryBean((FactoryBean<?>) beanInstance, beanName);
}
二、高級應用場景與實戰
1. 多例對象動態生成
public class PrototypeToolFactory implements FactoryBean<Tool> {@Override public boolean isSingleton() {return false; // 每次請求新實例}@Overridepublic Tool getObject() {return new Tool(UUID.randomUUID().toString());}
}
應用場景:數據庫連接池、線程不安全對象的按需創建
2. 手動配置代理(AOP場景)
(ProxyFactoryBean 是 Spring AOP 中用于 手動配置代理對象的核心類;而動態代理底層是基于AnnotationAwareAspectJAutoProxyCreator實現)
public class ServiceProxyFactory implements FactoryBean<Object> {private Object target;@Overridepublic Object getObject() {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),(proxy, method, args) -> {System.out.println("[Before] Method: " + method.getName());Object result = method.invoke(target, args);System.out.println("[After] Result: " + result);return result;});}
}
實現原理:Spring AOP的ProxyFactoryBean
即采用類似機制生成代理對象
3. 延遲初始化策略
public class LazyDataSourceFactory implements FactoryBean<DataSource> {private boolean initialized = false;private DataSource dataSource;@Overridepublic DataSource getObject() {if (!initialized) {initializeDataSource(); // 首次調用時初始化initialized = true;}return dataSource;}
}
優勢:優化啟動速度,按需加載重量級資源
三、框架級應用案例解析
1. MyBatis SqlSessionFactoryBean
核心邏輯:
- 實現
InitializingBean
確保屬性設置完成后構建SqlSessionFactory
- 通過
buildSqlSessionFactory()
解析XML
配置、Mapper
映射 - 集成
Spring
事務管理
2. Spring Cloud FeignClientFactoryBean
實現機制:
- 動態生成
Feign
客戶端接口代理 - 整合
Ribbon
負載均衡、Hystrix
熔斷 - 通過
Targeter.target()
生成最終代理對象
3. Spring AOP ProxyFactoryBean
(ProxyFactoryBean 是 Spring AOP 中用于 手動配置代理對象的核心類;而動態代理底層是基于AnnotationAwareAspectJAutoProxyCreator實現)
<bean id="personTarget" class="com.example.PersonImpl"/>
<bean id="myAdvisor" class="com.example.MyAdvisor"/><bean id="personProxy" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="personTarget"/><property name="proxyInterfaces" value="com.example.Person"/><property name="interceptorNames"><list><value>myAdvisor</value></list></property>
</bean>
工作流程:
- 配置
Advisor
(切面)和Advice
(增強) - 通過
getObject()
生成JDK/CGLIB
代理 - 將攔截器鏈織入代理對象
四、FactoryBean常見面試題
1. BeanFactory 和 FactoryBean 的區別?
維度 | BeanFactory | FactoryBean |
---|---|---|
角色 | Spring 容器根接口,管理所有 Bean | 特殊 Bean,用于生成其他對象 |
獲取方式 | getBean(“beanName”) 直接獲取 Bean | getBean(“beanName”) 獲取目標對象,&beanName 獲取工廠 |
設計目標 | 提供容器基礎功能(如依賴注入) | 擴展復雜對象的創建邏輯(如代理、動態配置) |
典型實現 | ApplicationContext | SqlSessionFactoryBean、ProxyFactoryBean |
2. FactoryBean 的初始化時機?
- 普通 Bean 階段:FactoryBean 實例在 Spring 容器初始化時創建。
- 目標對象階段:目標對象(
getObject()
生成)在首次調用getBean()
時創建,支持懶加載(@Lazy
)。 源碼位置:AbstractBeanFactory.getObjectForBeanInstance()
→getObjectFromFactoryBean()
3. 如何通過 FactoryBean 實現多例對象?
-
重寫方法:
isSingleton()
返回false
,每次調用getObject()
生成新實例。 -
示例:
public class PrototypeFactory implements FactoryBean<MyObject> {@Overridepublic boolean isSingleton() { return false; }@Overridepublic MyObject getObject() { return new MyObject(); } }
應用場景:線程不安全對象(如數據庫連接)、動態配置對象
4. FactoryBean 在 MyBatis 中的應用?
- 案例:SqlSessionFactoryBean
- 核心流程:
- 實現
FactoryBean<SqlSessionFactory>
,在getObject()
中解析 MyBatis 配置。 - 集成 Spring 事務管理,通過
InitializingBean
確保屬性初始化完成
- 實現
5. 如何獲取 FactoryBean 自身實例?
- 語法:在 Bean 名稱前添加
&
前綴,例如context.getBean("&myFactory")
- 原理:Spring 容器通過
BeanFactory.FACTORY_BEAN_PREFIX
標識工廠實例
6. FactoryBean 與 @Bean 注解的區別?
維度 | FactoryBean | @Bean |
---|---|---|
實現方式 | 需實現接口,編寫 getObject() 邏輯 | 通過注解聲明,直接返回對象實例 |
對象生成 | 動態生成(如代理、復雜初始化) | 直接實例化(簡單對象) |
獲取方式 | beanName 獲取目標對象,&beanName 獲取工廠 | 直接通過 beanName 獲取實例 |
生命周期 | 支持單例/多例控制 | 默認單例,可通過 @Scope 修改 |