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