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

  • 相关阅读:
    重写
    mongodb版本区别
    mysql备份还原
    mysql备份恢复
    mysql的锁
    mysql索引
    mysql日志详解
    mysql基本语法
    mysql主从bin-log的三种方式
    mysql的GTID主从复制方式
  • 原文地址:https://www.cnblogs.com/toUpdating/p/9818499.html
Copyright © 2020-2023  润新知