spring 事務

  在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 }
TransactionProxyFactoryBean

  以上代碼完成了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     }

 

相關文章
相關標籤/搜索