在Spring的事務處理模塊中,能夠看到的類層次結構以下java
從圖6-1中能夠看到,Spring事務處理模塊是經過AOP功能來實現聲明式事務處理的,好比事務屬性的spring
配置和讀取,事務對象的抽象等。所以,在Spring事務處理中,能夠經過設計一個數據庫
TransactionProxyFactoryBean來使用AOP功能,經過這個TransactionProxyFactoryBean能夠生成Proxy代理express
對象,在這個代理對象中,經過TransactionInterceptor來完成對代理方法的攔截,正是這些AOP的攔截功能apache
,將事務處理的功能編織進來。在Spring事務處理中,在實現聲明式事務處理時,這是AOP和IoC模塊集成的數據結構
部分。對於具體的事務處理實現,好比事務的生成、提交、回滾、掛起等,因爲不一樣的底層數據庫有不一樣的app
支持方式,所以,在Spring的事務處理中,對主要的事務實現作了一個抽象和適配。適配的具體事務處理器less
包含:對DataSource數據源的事務處理支持,對Hibernate數據源的事務處理支持,對JDO數據源的事務處理ide
支持,對JPA和JTA等數據源的事務處理支持等。這一系列的事務處理支持,都是經過設計PlatformTransactiopost
-nManager、AbstractPlatformTransactionManager以及一系列具體事務處理器來實現的,而PlatfromTransac
-tionManager又在TransactionInterceptor被包含,經過這樣一個接口實現設計,就把這一系列的事務處理的
實現與前面提到的TransactionProxyFactoryBean結合起來,從而造成了一個Spring聲明式事務處理的設計
體系
配置demo
1 <bean id="baseProxyFactory" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" 2 abstract="true"> 3 <property name="transactionManager"><ref local="mockMan"/></property> 4 <property name="transactionAttributes"> 5 <props> 6 <prop key="s*">PROPAGATION_MANDATORY</prop> 7 <prop key="setAg*"> PROPAGATION_REQUIRED , readOnly </prop> 8 <prop key="set*">PROPAGATION_SUPPORTS</prop> 9 </props> 10 </property> 11 </bean> 12 13 <bean id="proxyFactory2DynamicProxy" parent="baseProxyFactory"> 14 <property name="target"><ref local="target"/></property> 15 </bean> 16 17 <!-- 18 Same as proxyFactory2DynamicProxy but forces the use of CGLIB. 19 --> 20 <bean id="proxyFactory2Cglib" parent="baseProxyFactory"> 21 <property name="proxyTargetClass"><value>true</value></property> 22 <property name="target"><ref local="target"/></property> 23 </bean> 24 25 <bean id="proxyFactory2Lazy" parent="baseProxyFactory"> 26 <property name="target"> 27 <bean class="org.springframework.aop.target.LazyInitTargetSource"> 28 <property name="targetBeanName"><idref local="target"/></property> 29 </bean> 30 </property> 31 </bean> 32 33 <bean id="proxyFactory3" parent="baseProxyFactory"> 34 <property name="target"><ref local="target"/></property> 35 <property name="proxyTargetClass"><value>true</value></property> 36 <property name="pointcut"> 37 <ref local="txnInvocationCounterPointcut"/> 38 </property> 39 <property name="preInterceptors"> 40 <list> 41 <ref local="preInvocationCounterInterceptor"/> 42 </list> 43 </property> 44 <property name="postInterceptors"> 45 <list> 46 <ref local="postInvocationCounterInterceptor"/> 47 </list> 48 </property> 49 </bean>
聲明式事務處理的實現大體能夠分爲如下幾個部分
1)讀取和處理在IoC容器中配置的事務處理屬性,並轉化爲Spring事務處理須要的內部數據結構。具體
來講,這裏涉及的類是TransactionAttributeSourceAdvisor,從名字能夠看出,它是一個AOP通知器,Spring
使用這個通知器來完成對事務處理屬性值的處理。處理的結果是,在IoC容器中配置的事務處理屬性信息,會
被讀入並轉化成TransactionAttribute表示的數據對象,這個數據對象是Spring對事務處理屬性值的數據抽象,
對這些屬性的處理是和TransactionProxyFactoryBean攔截下來的事務方法的處理結合起來的。
2)Spring事務處理模塊實現統一的事務處理過程。這個通用的事務處理過程包含處理事務配置屬性,
以及與線程綁定完成事務處理的過程,Spring經過TransactionInfo和TransactionStatus這兩個數據對象,在
事務處理過程當中記錄和傳遞相關執行場景。
3)底層的事務處理實現。對於底層的事務操做,Spring委託給具體的事務處理器來完成,這些具體的事
務處理器,就是在IoC容器中配置聲明式事務處理時,配置的PlatformTransactionManager的具體實現,好比
DataSourceTransactionManager和HibernateTransactionManager等。
實現分析
在TransactionProxyFactoryBean中,在IoC容器進行注入的時候,會建立TransactionInterceptor對象,而這
個對象會建立一個TransactionAttributePointcut,爲讀取TransactionAtturbute作準備。在容器初始化的過程
中,因爲實現了InitializingBean接口,所以AbstractSingletonProxyFactoryBean會實現afterPropertiesSet()
方法,正是在這個方法實例化了一個ProxyFactory,創建起Spring AOP的應用,在這裏,會爲這個Proxy
-Factory設置通知、目標對象,並最終返回Proxy代理對象。在Proxy代理對象創建起來之後,在調用其代理
方法的時候,會調用相應的TransactionInteceptor攔截器,在這個調用過程當中,會根據TransactionAttribute
配置是事務屬性進行配置,從而爲事務處理作好準備。
從TransactionProxyFactoryBean代碼
1 /* 2 * Copyright 2002-2014 the original author or authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.springframework.transaction.interceptor; 18 19 import java.util.Properties; 20 21 import org.springframework.aop.Pointcut; 22 import org.springframework.aop.framework.AbstractSingletonProxyFactoryBean; 23 import org.springframework.aop.support.DefaultPointcutAdvisor; 24 import org.springframework.beans.factory.BeanFactory; 25 import org.springframework.beans.factory.BeanFactoryAware; 26 import org.springframework.beans.factory.FactoryBean; 27 import org.springframework.beans.factory.ListableBeanFactory; 28 import org.springframework.transaction.PlatformTransactionManager; 29 30 /** 31 * Proxy factory bean for simplified declarative transaction handling. 32 * This is a convenient alternative to a standard AOP 33 * {@link org.springframework.aop.framework.ProxyFactoryBean} 34 * with a separate {@link TransactionInterceptor} definition. 35 * 36 * <p><strong>HISTORICAL NOTE:</strong> This class was originally designed to cover the 37 * typical case of declarative transaction demarcation: namely, wrapping a singleton 38 * target object with a transactional proxy, proxying all the interfaces that the target 39 * implements. However, in Spring versions 2.0 and beyond, the functionality provided here 40 * is superseded by the more convenient {@code tx:} XML namespace. See the <a 41 * href="http://bit.ly/qUwvwz">declarative transaction management</a> section of the 42 * Spring reference documentation to understand the modern options for managing 43 * transactions in Spring applications. For these reasons, <strong>users should favor of 44 * the {@code tx:} XML namespace as well as 45 * the @{@link org.springframework.transaction.annotation.Transactional Transactional} 46 * and @{@link org.springframework.transaction.annotation.EnableTransactionManagement 47 * EnableTransactionManagement} annotations.</strong> 48 * 49 * <p>There are three main properties that need to be specified: 50 * <ul> 51 * <li>"transactionManager": the {@link PlatformTransactionManager} implementation to use 52 * (for example, a {@link org.springframework.transaction.jta.JtaTransactionManager} instance) 53 * <li>"target": the target object that a transactional proxy should be created for 54 * <li>"transactionAttributes": the transaction attributes (for example, propagation 55 * behavior and "readOnly" flag) per target method name (or method name pattern) 56 * </ul> 57 * 58 * <p>If the "transactionManager" property is not set explicitly and this {@link FactoryBean} 59 * is running in a {@link ListableBeanFactory}, a single matching bean of type 60 * {@link PlatformTransactionManager} will be fetched from the {@link BeanFactory}. 61 * 62 * <p>In contrast to {@link TransactionInterceptor}, the transaction attributes are 63 * specified as properties, with method names as keys and transaction attribute 64 * descriptors as values. Method names are always applied to the target class. 65 * 66 * <p>Internally, a {@link TransactionInterceptor} instance is used, but the user of this 67 * class does not have to care. Optionally, a method pointcut can be specified 68 * to cause conditional invocation of the underlying {@link TransactionInterceptor}. 69 * 70 * <p>The "preInterceptors" and "postInterceptors" properties can be set to add 71 * additional interceptors to the mix, like 72 * {@link org.springframework.aop.interceptor.PerformanceMonitorInterceptor}. 73 * 74 * <p><b>HINT:</b> This class is often used with parent / child bean definitions. 75 * Typically, you will define the transaction manager and default transaction 76 * attributes (for method name patterns) in an abstract parent bean definition, 77 * deriving concrete child bean definitions for specific target objects. 78 * This reduces the per-bean definition effort to a minimum. 79 * 80 * <pre code="class"> 81 * {@code 82 * <bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" 83 * abstract="true"> 84 * <property name="transactionManager" ref="transactionManager"/> 85 * <property name="transactionAttributes"> 86 * <props> 87 * <prop key="insert*">PROPAGATION_REQUIRED</prop> 88 * <prop key="update*">PROPAGATION_REQUIRED</prop> 89 * <prop key="*">PROPAGATION_REQUIRED,readOnly</prop> 90 * </props> 91 * </property> 92 * </bean> 93 * 94 * <bean id="myProxy" parent="baseTransactionProxy"> 95 * <property name="target" ref="myTarget"/> 96 * </bean> 97 * 98 * <bean id="yourProxy" parent="baseTransactionProxy"> 99 * <property name="target" ref="yourTarget"/> 100 * </bean>}</pre> 101 * 102 * @author Juergen Hoeller 103 * @author Dmitriy Kopylenko 104 * @author Rod Johnson 105 * @author Chris Beams 106 * @since 21.08.2003 107 * @see #setTransactionManager 108 * @see #setTarget 109 * @see #setTransactionAttributes 110 * @see TransactionInterceptor 111 * @see org.springframework.aop.framework.ProxyFactoryBean 112 */ 113 @SuppressWarnings("serial") 114 public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean 115 implements BeanFactoryAware { 116 117 private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor(); 118 119 private Pointcut pointcut; 120 121 122 /** 123 * Set the transaction manager. This will perform actual 124 * transaction management: This class is just a way of invoking it. 125 * @see TransactionInterceptor#setTransactionManager 126 */ 127 public void setTransactionManager(PlatformTransactionManager transactionManager) { 128 this.transactionInterceptor.setTransactionManager(transactionManager); 129 } 130 131 /** 132 * Set properties with method names as keys and transaction attribute 133 * descriptors (parsed via TransactionAttributeEditor) as values: 134 * e.g. key = "myMethod", value = "PROPAGATION_REQUIRED,readOnly". 135 * <p>Note: Method names are always applied to the target class, 136 * no matter if defined in an interface or the class itself. 137 * <p>Internally, a NameMatchTransactionAttributeSource will be 138 * created from the given properties. 139 * @see #setTransactionAttributeSource 140 * @see TransactionInterceptor#setTransactionAttributes 141 * @see TransactionAttributeEditor 142 * @see NameMatchTransactionAttributeSource 143 */ 144 public void setTransactionAttributes(Properties transactionAttributes) { 145 this.transactionInterceptor.setTransactionAttributes(transactionAttributes); 146 } 147 148 /** 149 * Set the transaction attribute source which is used to find transaction 150 * attributes. If specifying a String property value, a PropertyEditor 151 * will create a MethodMapTransactionAttributeSource from the value. 152 * @see #setTransactionAttributes 153 * @see TransactionInterceptor#setTransactionAttributeSource 154 * @see TransactionAttributeSourceEditor 155 * @see MethodMapTransactionAttributeSource 156 * @see NameMatchTransactionAttributeSource 157 * @see org.springframework.transaction.annotation.AnnotationTransactionAttributeSource 158 */ 159 public void setTransactionAttributeSource(TransactionAttributeSource transactionAttributeSource) { 160 this.transactionInterceptor.setTransactionAttributeSource(transactionAttributeSource); 161 } 162 163 /** 164 * Set a pointcut, i.e a bean that can cause conditional invocation 165 * of the TransactionInterceptor depending on method and attributes passed. 166 * Note: Additional interceptors are always invoked. 167 * @see #setPreInterceptors 168 * @see #setPostInterceptors 169 */ 170 public void setPointcut(Pointcut pointcut) { 171 this.pointcut = pointcut; 172 } 173 174 /** 175 * This callback is optional: If running in a BeanFactory and no transaction 176 * manager has been set explicitly, a single matching bean of type 177 * {@link PlatformTransactionManager} will be fetched from the BeanFactory. 178 * @see org.springframework.beans.factory.BeanFactory#getBean(Class) 179 * @see org.springframework.transaction.PlatformTransactionManager 180 */ 181 public void setBeanFactory(BeanFactory beanFactory) { 182 this.transactionInterceptor.setBeanFactory(beanFactory); 183 } 184 185 186 /** 187 * Creates an advisor for this FactoryBean's TransactionInterceptor. 188 */ 189 @Override 190 protected Object createMainInterceptor() { 191 this.transactionInterceptor.afterPropertiesSet(); 192 if (this.pointcut != null) { 193 return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor); 194 } 195 else { 196 // Rely on default pointcut. 197 return new TransactionAttributeSourceAdvisor(this.transactionInterceptor); 198 } 199 } 200 201 }
以上代碼完成了AOP配置,對於用戶來講,一個值得關心的問題是,Spring的TransactionInterceptor
配置是在何時被啓動併成爲Advisor通知器的一部分的呢?從對createMainInterceptor方法的調用分析
這個createMainInterceptor方法在IoC容器完成Bean的依賴注入時,經過initializeBean方法被調用
TransactionInterceptor中invoke方法
1 public Object invoke(final MethodInvocation invocation) throws Throwable { 2 // Work out the target class: may be {@code null}. 3 // The TransactionAttributeSource should be passed the target class 4 // as well as the method, which may be from an interface. 5 Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); 6 7 // Adapt to TransactionAspectSupport's invokeWithinTransaction... 8 return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() { 9 public Object proceedWithInvocation() throws Throwable { 10 return invocation.proceed(); 11 } 12 }); 13 } 14 15 16 protected Object invokeWithinTransaction(Method method, Class targetClass, final InvocationCallback invocation) 17 throws Throwable { 18 19 // If the transaction attribute is null, the method is non-transactional. 20 final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass); 21 final PlatformTransactionManager tm = determineTransactionManager(txAttr); 22 final String joinpointIdentification = methodIdentification(method, targetClass); 23 24 if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { 25 // Standard transaction demarcation with getTransaction and commit/rollback calls. 26 TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); 27 Object retVal = null; 28 try { 29 // This is an around advice: Invoke the next interceptor in the chain. 30 // This will normally result in a target object being invoked. 31 retVal = invocation.proceedWithInvocation(); 32 } 33 catch (Throwable ex) { 34 // target invocation exception 35 completeTransactionAfterThrowing(txInfo, ex); 36 throw ex; 37 } 38 finally { 39 cleanupTransactionInfo(txInfo); 40 } 41 commitTransactionAfterReturning(txInfo); 42 return retVal; 43 } 44 45 else { 46 // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in. 47 try { 48 Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, 49 new TransactionCallback<Object>() { 50 public Object doInTransaction(TransactionStatus status) { 51 TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); 52 try { 53 return invocation.proceedWithInvocation(); 54 } 55 catch (Throwable ex) { 56 if (txAttr.rollbackOn(ex)) { 57 // A RuntimeException: will lead to a rollback. 58 if (ex instanceof RuntimeException) { 59 throw (RuntimeException) ex; 60 } 61 else { 62 throw new ThrowableHolderException(ex); 63 } 64 } 65 else { 66 // A normal return value: will lead to a commit. 67 return new ThrowableHolder(ex); 68 } 69 } 70 finally { 71 cleanupTransactionInfo(txInfo); 72 } 73 } 74 }); 75 76 // Check result: It might indicate a Throwable to rethrow. 77 if (result instanceof ThrowableHolder) { 78 throw ((ThrowableHolder) result).getThrowable(); 79 } 80 else { 81 return result; 82 } 83 } 84 catch (ThrowableHolderException ex) { 85 throw ex.getCause(); 86 } 87 } 88 }