spring 事务

  在Spring的事务处理模块中,可以看到的类层次结构如下

  从图6-1中可以看到,Spring事务处理模块是通过AOP功能来实现声明式事务处理的,比如事务属性的

配置和读取,事务对象的抽象等。因此,在Spring事务处理中,可以通过设计一个

TransactionProxyFactoryBean来使用AOP功能,通过这个TransactionProxyFactoryBean可以生成Proxy代理

对象,在这个代理对象中,通过TransactionInterceptor来完成对代理方法的拦截,正是这些AOP的拦截功能

,将事务处理的功能编织进来。在Spring事务处理中,在实现声明式事务处理时,这是AOP和IoC模块集成的

部分。对于具体的事务处理实现,比如事务的生成、提交、回滚、挂起等,由于不同的底层数据库有不同的

支持方式,因此,在Spring的事务处理中,对主要的事务实现做了一个抽象和适配。适配的具体事务处理器

包含:对DataSource数据源的事务处理支持,对Hibernate数据源的事务处理支持,对JDO数据源的事务处理

支持,对JPA和JTA等数据源的事务处理支持等。这一系列的事务处理支持,都是通过设计PlatformTransactio

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

 

posted on 2018-10-19 20:05  持续在更新  阅读(245)  评论(0编辑  收藏  举报

导航