Spring 聲明式事務管理將事務邏輯作為橫切關注點通過 AOP 織入業務代碼,實現了業務邏輯與事務控制的完全解耦。其核心實現圍繞三大模塊展開:
TransactionAttributeSourceAdvisor + TransactionAttributeSource 負責讀取註解/XML 配置,決定哪些方法需要什麼事務屬性。PlatformTransactionManager 創建事務,通過 TransactionStatus 傳遞上下文。TransactionInterceptor 作為環繞通知,在方法進出時完成事務的提交、回滾、掛起/恢復等全生命周期操作。雖然現代 Spring 推薦使用 @EnableTransactionManagement + @Transactional,但理解經典的 TransactionProxyFactoryBean 有助於把握底層原理:
public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean {
private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor();
public void setTransactionManager(PlatformTransactionManager tm) {
transactionInterceptor.setTransactionManager(tm);
}
public void setTransactionAttributes(Properties attrs) {
transactionInterceptor.setTransactionAttributes(attrs);
}
protected Object createMainInterceptor() {
transactionInterceptor.afterPropertiesSet();
return (pointcut != null)
? new DefaultPointcutAdvisor(pointcut, transactionInterceptor)
: new TransactionAttributeSourceAdvisor(transactionInterceptor);
}
}
關鍵點:
TransactionInterceptor 實例,所有事務屬性、事務管理器均注入該攔截器。afterPropertiesSet() 中構建 ProxyFactory,將 Advisor 加入攔截器鏈,最終由 ProxyFactory 生成代理對象。該 Advisor 內部定義了靜態切點 TransactionAttributeSourcePointcut,其匹配邏輯極其簡潔:
public boolean matches(Method method, Class targetClass) {
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas != null && tas.getTransactionAttribute(method, targetClass) != null);
}
即:只要能解析出非空的 TransactionAttribute,該方法就納入事務管理範圍。
採用 模板方法 + 裝飾器模式,核心流程:
computeTransactionAttribute() 計算。NULL_TRANSACTION_ATTRIBUTE 哨兵對象)。computeTransactionAttribute() 採用多級回退策略:
這完美支援了「類級別 @Transactional + 方法級別覆蓋」的語義。
public Object invoke(final MethodInvocation invocation) throws Throwable {
Class targetClass = (invocation.getThis() != null) ? invocation.getThis().getClass() : null;
final TransactionAttribute txAttr = getTransactionAttributeSource()
.getTransactionAttribute(invocation.getMethod(), targetClass);
final String joinpointId = methodIdentification(invocation.getMethod());
if (txAttr == null || !(getTransactionManager() instanceof CallbackPreferringPlatformTransactionManager)) {
// 標準模式:手動控制事務邊界
TransactionInfo txInfo = createTransactionIfNecessary(txAttr, joinpointId);
try {
return invocation.proceed();
} catch (Throwable ex) {
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
} finally {
cleanupTransactionInfo(txInfo);
}
} else {
// 回調模式:委託事務管理器執行模板回調
return ((CallbackPreferringPlatformTransactionManager) getTransactionManager())
.execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(txAttr, joinpointId, status);
try {
return invocation.proceed();
} finally {
cleanupTransactionInfo(txInfo);
}
});
}
}
兩種模式本質一致:獲取事務屬性 → 創建/加入事務 → 執行業務 → 根據結果提交或回滾 → 清理上下文。
定義了事務創建的標準流程(模板方法模式):
doGetTransaction():子類獲取底層事務對象(如 JDBC Connection、Hibernate Session)。isExistingTransaction())。handleExistingTransaction() 根據傳播行為處理(掛起、嵌套、拋異常等)。REQUIRED/REQUIRES_NEW/NESTED → doBegin() 創建新事務。SUPPORTS/NOT_SUPPORTED/NEVER → 不創建事務,返回空狀態。MANDATORY → 拋異常。TransactionStatus 封裝事務狀態(是否新事務、是否有保存點、同步標記等)。con.setAutoCommit(false)。ConnectionHolder 綁定到 TransactionSynchronizationManager(ThreadLocal),實現同線程事務上下文共享。protected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
Connection con = txObject.getConnectionHolder().getConnection();
con.commit(); // 核心:JDBC 原生提交
}
protected void doRollback(DefaultTransactionStatus status) {
Connection con = txObject.getConnectionHolder().getConnection();
con.rollback(); // 核心:JDBC 原生回滾
}
最終都歸結為對 JDBC Connection 的原生操作,Spring 只是負責管理 Connection 的生命週期與線程綁定。
這是 Spring 事務生態的「粘合劑」:
ThreadLocal 存儲資源綁定(Key 為 DataSource/SessionFactory,Value 為 Holder)。registerSynchronization()),在事務提交/回滾前後觸發回調(如 Hibernate flush、延遲加載檢查)。bindResource()/unbindResource() 供事務管理器綁定/解綁底層資源。編程式事務本質是手動調用模板:
TransactionStatus status = txManager.getTransaction(def);
try {
// business logic
txManager.commit(status);
} catch (Exception ex) {
txManager.rollback(status);
throw ex;
}
聲明式事務只是將這段樣板代碼封裝進 TransactionInterceptor,並通過 AOP 自動織入,**核心邏輯完全一致**。
REQUIRED;需獨立事務用 REQUIRES_NEW;嵌套保存點用 NESTED(需數據庫支援)。@Transactional(readOnly = true) 可提示數據庫/連接池優化,Hibernate 會將 FlushMode 設為 NEVER。rollbackFor 指定。Spring 聲明式事務的優雅在於:將複雜的事務協議標準化為統一的 SPI 接口,將業務無關的樣板代碼集中到攔截器,將配置元數據解耦為可插拔的屬性源解析器。這正是 Spring「在核心複雜度換取用戶簡單度」設計哲學的經典體現。