Spring 聲明式事務雖強大,但傳統配置讓開發者陷入「XML 地獄」:每個業務 Bean 需配置目標 Bean + 代理 Bean,N 個類需 2N 個 Bean 定義,維護成本極高。本文梳理四種主流配置演進路徑,並創新實現 BeanClassTypeAutoProxyCreator 實現「零配置」事務代理。
共享 TransactionInterceptor 定義屬性,但每個業務 Bean 仍需單獨定義 ProxyFactoryBean 代理,注入時需用代理 Bean 替代目標 Bean,增加理解負擔。
每個代理 Bean 獨立定義事務屬性,配置最繁瑣,同樣面臨 2N Bean 與注入混淆問題。
抽象父 Bean 定義通用事務屬性,子 Bean 繼承並僅指定 target。簡化屬性配置,但仍需維護 2N Bean 定義。
框架自動創建代理,僅需維護 N 個業務 Bean,直接注入目標 Bean 而非代理 Bean。但需手工維護 beanNames 列表,易遺漏。
核心思路:定義標記接口(如 BaseService),所有需事務的 Service 實現該接口,框架掃描上下文中所有實現類自動代理。
AbstractAutoProxyCreator,重寫 getAdvicesAndAdvisorsForBeanApplicationContextAware 獲取上下文InitializingBean,在 afterPropertiesSet 中按類型掃描 Bean 名稱列表classTypes 属性接收標記接口全限定名public class BeanClassTypeAutoProxyCreator extends AbstractAutoProxyCreator
implements ApplicationContextAware, InitializingBean {
private List classTypes;
private List beanNames;
protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName, TargetSource targetSource) {
if (beanNames != null && beanNames.contains(beanName)) {
return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
}
return DO_NOT_PROXY;
}
public void afterPropertiesSet() throws Exception {
if (classTypes != null && !classTypes.isEmpty()) {
beanNames = new ArrayList();
for (String classType : classTypes) {
String[] names = getApplicationContext().getBeanNamesForType(Class.forName(classType), true, false);
if (names != null) beanNames.addAll(Arrays.asList(names));
}
}
}
// ... ApplicationContextAware 實現省略
}
<!-- 1. 定義標記接口 -->
public interface BaseService {}
<!-- 2. 業務接口繼承標記 -->
public interface SampleService extends BaseService { ... }
<!-- 3. 僅配置業務 Bean,無需代理 Bean -->
<bean id="sampleService" class="...SampleServiceImpl">
<property name="userInfoDAO" ref="userInfoDAO"/>
</bean>
<!-- 4. 一次性配置自動代理器 -->
<bean id="autoClassTypeProxyCreator" class="...BeanClassTypeAutoProxyCreator">
<property name="interceptorNames" value="transactionInterceptor"/>
<property name="classTypes">
<list><value>com.prs.application.ehld.biz.service.BaseService</value></list>
</property>
</bean>
嵌套 Bean 定義減少頂層 Bean 數量;核心基礎設施(事務、安全、日誌)應由架構層封裝,業務開發者「感知不到」其存在,才是優秀框架設計的標誌。