前言

  • Spring事务让我们从复杂的事务处理中得到解脱,使我们再不需要去处理获得连接、关闭连接、事务提交和回滚等操作,Spring事务分为声明式事务和编程式事务,其中编程式事务因为对代码入侵较大所以不被推荐使用,我们平常最常使用的是声明式事务也就是通过@Transactional注解的形式开启事务

    • 编程式事务

      • 示例代码
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        @Autowired
        private TransactionTemplate transactionTemplate;

        @Autowired
        private PlatformTransactionManager transactionManager;

        //开启事务保存数据
        boolean result = transactionTemplate.execute(new TransactionCallback<Boolean>() {
        @Override
        public Boolean doInTransaction(TransactionStatus status) {
        try {
        // TODO something
        } catch (Exception e) {
        //TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); //手动开启事务回滚
        status.setRollbackOnly();
        logger.error(e.getMessage(), e);
        return false;
        }
        return true;
        }
        });
    • 声明式事务

      • xml配置

        1
        2
        3
        4
        5
        6
        <!-- (事务管理)transaction manager, use JtaTransactionManager for global tx -->
        <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
        </bean>

        <tx:annotation-driven proxy-target-class="false" transaction-manager="transactionManager" />
      • <tx:annotation-driven>标签是开启声明式事务的开关,配置了这个就可以使用注解@Transactional来开启事务了

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        // org.springframework.iframe.service.impl.UserServiceImpl#updateUserByRuntimeException      

        @Transactional
        public void updateUserByRuntimeException (IUser iUser) throws NullPointerException{
        log.info("开启事务");
        if (userMapper.insertSelective(iUser) == 1) {
        throw new NullPointerException("运行时异常");
        }
        IUser iUser2 = userMapper.selectByPrimaryKey(1);
        iUser2.setAge(iUser2.getAge() + 1);
        userMapper.updateByPrimaryKeySelective(iUser2);
        }
      • 也可以用xml的方式配置那些方法需要加事务

        • xml配置

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23
          24
          25
          26
          27
          28
          <!-- 配置事务通知属性 -->
          <tx:advice id="txAdvice" transaction-manager="transactionManager">
          <!-- 定义事务传播属性 -->
          <tx:attributes>
          <tx:method name="insert*" propagation="REQUIRED"/>
          <tx:method name="update*" propagation="REQUIRED"/>
          <tx:method name="edit*" propagation="REQUIRED"/>
          <tx:method name="save*" propagation="REQUIRED"/>
          <tx:method name="add*" propagation="REQUIRED"/>
          <tx:method name="new*" propagation="REQUIRED"/>
          <tx:method name="set*" propagation="REQUIRED"/>
          <tx:method name="remove*" propagation="REQUIRED"/>
          <tx:method name="delete*" propagation="REQUIRED"/>
          <tx:method name="change*" propagation="REQUIRED"/>
          <tx:method name="check*" propagation="REQUIRED"/>
          <tx:method name="get*" propagation="REQUIRED" read-only="true"/>
          <tx:method name="find*" propagation="REQUIRED" read-only="true"/>
          <tx:method name="load*" propagation="REQUIRED" read-only="true"/>
          <tx:method name="*" propagation="REQUIRED" read-only="true"/>
          </tx:attributes>
          </tx:advice>

          <!-- 配置事务切面 -->
          <aop:config>
          <aop:pointcut id="serviceOperation"
          expression="execution(* org.springframework.iframe.service.*.*(..))"/>
          <aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation"/>
          </aop:config>
        • 从上面可以看到编程式事务需要配置哪些方法需要事务控制,比如<tx:method name="insert*" propagation="REQUIRED"/>配置的就是insert开头的方法会有事务控制,然后aop:config配置了事务切面,上面的配置是org.springframework.iframe.service包下方法名符合insert*、update*规则的方法会有事务控制

解析

声明式事务原理解析

  • 由上面介绍可以看到开启声明式事务的关键是<tx:annotation-driven>标签,由前些章节知识积累可以发现这个标签也是自定义标签,所以需要找到对应的NamespaceHandler
    • 先查看NamespaceHandler的实现类
    • 根据名称可以定位到TxNamespaceHandler,下面代码可以看到标签的解析是给通过TxAdviceBeanDefinitionParser类进行解析,标签的解析是通过AnnotationDrivenBeanDefinitionParser类进行解析
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      public class TxNamespaceHandler extends NamespaceHandlerSupport {  
      static final String TRANSACTION_MANAGER_ATTRIBUTE = "transaction-manager";
      static final String DEFAULT_TRANSACTION_MANAGER_BEAN_NAME = "transactionManager";
      static String getTransactionManagerName(Element element) {
      return (element.hasAttribute(TRANSACTION_MANAGER_ATTRIBUTE) ?
      element.getAttribute(TRANSACTION_MANAGER_ATTRIBUTE) : DEFAULT_TRANSACTION_MANAGER_BEAN_NAME);
      }
      @Override
      public void init() {
      // 对<tx:advice/>标签的解析
      registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
      // 对<tx:annotation-driven/>标签的解析
      registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
      registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
      }
      }

AnnotationDrivenBeanDefinitionParser

  • 进入parse()方法开始解析
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
registerTransactionalEventListenerFactory(parserContext);
String mode = element.getAttribute("mode");
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerTransactionAspect(element, parserContext);
}
else {
// mode="proxy"
// 提供对aspectj方式进行事务切入的支持
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
return null;
}
  • 我们这里是进入AopAutoProxyConfigurer.configueAutoProxyCreator(element, parserContext);方法,可以看到下面逻辑主要是注册了一些bean,这些bean支撑了整个事务功能,后面会详细说明

    • InfrastructureAdvisorAutoProxyCreator
    • AnnotationTransactionAttributeSource
    • TransactionInterceptor
    • BeanFactoryTransactionAttributeSourceAdvisor
  • 进入AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/**
* Inner class to just introduce an AOP framework dependency when actually in proxy mode.
*/
private static class AopAutoProxyConfigurer {

public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
// 注册 InfrastructureAdvisorAutoProxyCreator bean 这个类继承了 BeanPostProcessor,这里实现了AOP代理对象的创建
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
Object eleSource = parserContext.extractSource(element);

// 创建 AnnotationTransactionAttributeSource definition.
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 注册TransactionAttributeSource bean,并使用Spring中的定义规则生成beanname
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

// 创建 TransactionInterceptor definition.
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

// <tx:annotation-driven/>标签在不指定transaction-manager属性的时候,会默认寻找id固定名为transactionManager的bean作为事务管理器
registerTransactionManager(element, interceptorDef);
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
// 注册TransactionInterceptor bean,
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

// 创建 BeanFactoryTransactionAttributeSourceAdvisor definition.
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
advisorDef.setSource(eleSource);
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 将sourceName的bean注入advisorDef的transactionAttributeSource属性中
// 并将前两个BeanDefinition添加到第三个BeanDefinition的属性当中
advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
if (element.hasAttribute("order")) {
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
}
// 注册BeanFactoryTransactionAttributeSourceAdvisor bean
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);

// 创建CompositeComponentDefinition
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
parserContext.registerComponent(compositeDef);
}
}
}
  • AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);,这里注册了 InfrastructureAdvisorAutoProxyCreator bean 这个类继承了 BeanPostProcessor,这里实现了AOP代理对象的创建
  • 所以关注InfrastructureAdvisorAutoProxyCreatorpostProcessAfterInitialization()方法,进入其父类AbstractAutoProxyCreator中,这行代码是不是很熟悉没错就是创建AOP动态代理对象的方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
// 根据给定的bean的class和name构建出个key,格式: beanClassName_beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 如果它适合被代理,则需要封装指定的bean
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 如果已经处理过
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 无需增强
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 给定的bean类是否代表一个基础设施类,基础设施类不应代理,或者配置了指定bean不需要自动代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

// Create proxy if we have advice.
// 如果存在增强方法则创建代理
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果获取到了增强则需要针对增强创建代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理 1、获取增强方法或者增强器 2、根据获取的增强进行代理
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}

this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
  • 关注Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);这里是检查是否存在增强方法,如果有的话则创建代理,这里的内容AOP章节已经介绍了些
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Override
protected Object[] getAdvicesAndAdvisorsForBean(Class<?> beanClass, String beanName, TargetSource targetSource) {
// 获取所有的增强以及寻找所有增强中适用于bean的增强并应用
List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
// 获取所有增强器
List<Advisor> candidateAdvisors = findCandidateAdvisors();
// 从所有增强器中找出适合的增强器
List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
  • 可以看到先是获取了所有的增强器,然后在所有增强器中找出适合的增强器并返回

    • 获取所有增强器

      • 进入findCandidateAdvisors();方法之后直接跳到findAdvisorBeans()方法,关注advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);方法这里获取所有对应Advisor.class的类
      • 回顾之前的AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);方法是注册了BeanFactoryTransactionAttributeSourceAdvisor,看名称可以知道是继承了Advisor接口,所以这里获取增强器也会把这个类添加进来
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        public List<Advisor> findAdvisorBeans() {
        // Determine list of advisor bean names, if not cached already.
        String[] advisorNames = null;
        synchronized (this) {
        advisorNames = this.cachedAdvisorBeanNames;
        if (advisorNames == null) {
        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the auto-proxy creator apply to them!
        // 获取所有的beanName
        advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Advisor.class, true, false);
        this.cachedAdvisorBeanNames = advisorNames;
        }
        }
        if (advisorNames.length == 0) {
        return new LinkedList<Advisor>();
        }

        List<Advisor> advisors = new LinkedList<Advisor>();
        // 循环所有的beanname找出对应的增强方法
        for (String name : advisorNames) {
        if (isEligibleBean(name)) {
        if (this.beanFactory.isCurrentlyInCreation(name)) {
        if (logger.isDebugEnabled()) {
        logger.debug("Skipping currently created advisor '" + name + "'");
        }
        }
        else {
        try {
        advisors.add(this.beanFactory.getBean(name, Advisor.class));
        }
        catch (BeanCreationException ex) {
        Throwable rootCause = ex.getMostSpecificCause();
        if (rootCause instanceof BeanCurrentlyInCreationException) {
        BeanCreationException bce = (BeanCreationException) rootCause;
        if (this.beanFactory.isCurrentlyInCreation(bce.getBeanName())) {
        if (logger.isDebugEnabled()) {
        logger.debug("Skipping advisor '" + name +
        "' with dependency on currently created bean: " + ex.getMessage());
        }
        // Ignore: indicates a reference back to the bean we're trying to advise.
        // We want to find advisors other than the currently created bean itself.
        continue;
        }
        }
        throw ex;
        }
        }
        }
        }
        return advisors;
        }
    • 从所有增强器中找出适合的增强器

      • 上面已经获取了所有增强器,接下来就是匹配符合条件的增强器了,下面关注最后一个canApply()方法可以看到if (advisor instanceof PointcutAdvisor)判断

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        protected List<Advisor> findAdvisorsThatCanApply(
        List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

        ProxyCreationContext.setCurrentProxiedBeanName(beanName);
        try {
        // 过滤已经得到的advisors
        return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
        }
        finally {
        ProxyCreationContext.setCurrentProxiedBeanName(null);
        }
        }

        public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
        if (candidateAdvisors.isEmpty()) {
        return candidateAdvisors;
        }
        List<Advisor> eligibleAdvisors = new LinkedList<Advisor>();
        // 首先处理引介增强
        for (Advisor candidate : candidateAdvisors) {
        // canApply真正的匹配
        if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
        eligibleAdvisors.add(candidate);
        }
        }
        boolean hasIntroductions = !eligibleAdvisors.isEmpty();
        for (Advisor candidate : candidateAdvisors) {
        if (candidate instanceof IntroductionAdvisor) {
        // 引介增强已经处理
        // already processed
        continue;
        }
        // 对于普通bean的处理
        if (canApply(candidate, clazz, hasIntroductions)) {
        eligibleAdvisors.add(candidate);
        }
        }
        return eligibleAdvisors;
        }

        public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
        if (advisor instanceof IntroductionAdvisor) {
        return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
        }
        else if (advisor instanceof PointcutAdvisor) {
        PointcutAdvisor pca = (PointcutAdvisor) advisor;
        return canApply(pca.getPointcut(), targetClass, hasIntroductions);
        }
        else {
        // It doesn't have a pointcut so we assume it applies.
        return true;
        }
        }
      • 当前我们分析UserService是否适用于此增强方法,那么当前的advisor就是之前自定义标签解析的BeanFactoryTransactionAttributeSourceAdvisor,这个类间接实现了PointcutAdvisor,然后调用canApply(pca.getPointcut(), targetClass, hasIntroductions)方法,所以现在就将AOPTX联系起来了

      • 进入canApply(pca.getPointcut(), targetClass, hasIntroductions)方法,这里pca.getPointcut()返回的是TransactionAttributeSourcePointcut,这也是上面解析自定义标签时注入进入的

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
        Assert.notNull(pc, "Pointcut must not be null");
        if (!pc.getClassFilter().matches(targetClass)) {
        return false;
        }
        // TransactionAttributeSourcePointcut里的MethodMatcher
        MethodMatcher methodMatcher = pc.getMethodMatcher();
        if (methodMatcher == MethodMatcher.TRUE) {
        // No need to iterate the methods if we're matching any method anyway...
        return true;
        }

        IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
        if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
        introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
        }

        Set<Class<?>> classes = new LinkedHashSet<Class<?>>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
        classes.add(targetClass);
        for (Class<?> clazz : classes) {
        Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
        // 获取对应类的所有接口并连同类本身一起遍历,在遍历过程中又对类中的方法再次遍历,一但匹配成功便认为这个类使用于当前增强器
        for (Method method : methods) {
        if ((introductionAwareMethodMatcher != null &&
        introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
        methodMatcher.matches(method, targetClass)) {
        return true;
        }
        }
        }

        return false;
        }
      • 可以看到先是获取TransactionAttributeSourcePointcut里的MethodMatcher,然后就是获取对应类的所有接口并连同类本身一起遍历,在遍历过程中又对类中的方法再次遍历,一但匹配成功便认为这个类使用于当前增强器,所以关注TransactionAttributeSourcePointcut里的MethodMatcher里的matches(method, targetClass)方法

        1
        2
        3
        4
        5
        6
        7
        8
        9
        @Override
        public boolean matches(Method method, Class<?> targetClass) {
        if (TransactionalProxy.class.isAssignableFrom(targetClass)) {
        return false;
        }
        // 自定义标签解析时注入,这里tas是AnnotationTransactionAttributeSource
        TransactionAttributeSource tas = getTransactionAttributeSource();
        return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
        }
      • 进入tas.getTransactionAttribute()方法,这里跳到org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource#getTransactionAttribute,这里是判断我们的业务方法或者类上是否有@Transactional注解并且做了一下缓存处理

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        /**
        * 判断我们的业务方法或者类上是否有@Transactional注解
        *
        * Determine the transaction attribute for this method invocation.
        * <p>Defaults to the class's transaction attribute if no method attribute is found.
        * @param method the method for the current invocation (never {@code null})
        * @param targetClass the target class for this invocation (may be {@code null})
        * @return TransactionAttribute for this method, or {@code null} if the method
        * is not transactional
        */
        @Override
        public TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass) {
        if (method.getDeclaringClass() == Object.class) {
        return null;
        }

        // First, see if we have a cached value.
        Object cacheKey = getCacheKey(method, targetClass);
        Object cached = this.attributeCache.get(cacheKey);
        if (cached != null) {
        // Value will either be canonical value indicating there is no transaction attribute,
        // or an actual transaction attribute.
        if (cached == NULL_TRANSACTION_ATTRIBUTE) {
        return null;
        }
        else {
        return (TransactionAttribute) cached;
        }
        }
        else {
        // We need to work it out.
        // 获取事物属性
        TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
        // Put it in the cache.
        if (txAttr == null) {
        this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
        }
        else {
        String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
        if (txAttr instanceof DefaultTransactionAttribute) {
        ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
        }
        if (logger.isDebugEnabled()) {
        logger.debug("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
        }
        // 存入缓存
        this.attributeCache.put(cacheKey, txAttr);
        }
        return txAttr;
        }
        }
      • 关注computeTransactionAttribute(method, targetClass);,可以看到如果方法中存在事务属性,则使用方法上的事务属性,否则使用方法所在类上的事务属性,如果还是没找到就搜寻接口中的方法的事务属性,再没有就找接口类上的事务属性

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        protected TransactionAttribute computeTransactionAttribute(Method method, Class<?> targetClass) {
        // Don't allow no-public methods as required.
        if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
        return null;
        }

        // Ignore CGLIB subclasses - introspect the actual user class.
        Class<?> userClass = ClassUtils.getUserClass(targetClass);
        // The method may be on an interface, but we need attributes from the target class.
        // If the target class is null, the method will be unchanged.
        Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
        // If we are dealing with method with generic parameters, find the original method.
        specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);

        // First try is the method in the target class.
        // 查看方法中是否存在事务声明
        TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
        if (txAttr != null) {
        return txAttr;
        }

        // Second try is the transaction attribute on the target class.
        // 查看方法所在类中是否有事务声明
        txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
        if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
        return txAttr;
        }

        if (specificMethod != method) {
        // Fallback is to look at the original method.
        // 查看接口方法中是否有事务声明
        txAttr = findTransactionAttribute(method);
        if (txAttr != null) {
        return txAttr;
        }
        // Last fallback is the class of the original method.
        // 查看接口类中是否有事务声明
        txAttr = findTransactionAttribute(method.getDeclaringClass());
        if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
        return txAttr;
        }
        }

        return null;
        }
      • 具体查找逻辑在findTransactionAttribute()方法上

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        @Override
        protected TransactionAttribute findTransactionAttribute(Method method) {
        return determineTransactionAttribute(method);
        }
        protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
        if (ae.getAnnotations().length > 0) {
        for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
        TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
        if (attr != null) {
        return attr;
        }
        }
        }
        return null;
        }
      • 然后就是跳到org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(java.lang.reflect.AnnotatedElement)方法上,这里的方法就是解析 {@link Transactional} 注解,并封装成TransactionAttribute

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        @Override
        public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
        AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, Transactional.class);
        if (attributes != null) {
        return parseTransactionAnnotation(attributes);
        }
        else {
        return null;
        }
        }
        /**
        * 解析 {@link Transactional} 注解
        *
        * @param attributes
        * @return
        */
        protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
        RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
        Propagation propagation = attributes.getEnum("propagation");
        rbta.setPropagationBehavior(propagation.value());
        Isolation isolation = attributes.getEnum("isolation");
        rbta.setIsolationLevel(isolation.value());
        rbta.setTimeout(attributes.getNumber("timeout").intValue());
        rbta.setReadOnly(attributes.getBoolean("readOnly"));
        rbta.setQualifier(attributes.getString("value"));
        ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<RollbackRuleAttribute>();
        Class<?>[] rbf = attributes.getClassArray("rollbackFor");
        for (Class<?> rbRule : rbf) {
        RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
        }
        String[] rbfc = attributes.getStringArray("rollbackForClassName");
        for (String rbRule : rbfc) {
        RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
        }
        Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");
        for (Class<?> rbRule : nrbf) {
        NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
        }
        String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
        for (String rbRule : nrbfc) {
        NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
        }
        rbta.getRollbackRules().addAll(rollBackRules);
        return rbta;
        }
  • 回到AbstractAutoProxyCreator#postProcessAfterInitialization方法,这里是创建AOP代理对象的逻辑

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean != null) {
// 根据给定的bean的class和name构建出个key,格式: beanClassName_beanName
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
// 如果它适合被代理,则需要封装指定的bean
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
// 如果已经处理过
if (beanName != null && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
// 无需增强
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
// 给定的bean类是否代表一个基础设施类,基础设施类不应代理,或者配置了指定bean不需要自动代理
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}

// Create proxy if we have advice.
// 如果存在增强方法则创建代理
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
// 如果获取到了增强则需要针对增强创建代理
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
// 创建代理 1、获取增强方法或者增强器 2、根据获取的增强进行代理
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}

this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
  • 现在来看看UserService的获取到的增强器,可以看到是获取到了BeanFactoryTransactionAttributeSourceAdvisor,这里是根据该Advisor来创建代理对象,到这里Spring事务自定义标签的解析过程已经介绍完了,可以总结为下面几个步骤:
    • 1、解析事务自定义标签<tx:annotation-driven>,注册InfrastructureAdvisorAutoProxyCreatorBeanFactoryTransactionAttributeSourceAdvisorbean
    • 2、InfrastructureAdvisorAutoProxyCreator实现了BeanPostProcessor,所以可以遍历所有的bean用于创建代理对象
    • 3、那些类需要创建事务代理对象,则由BeanFactoryTransactionAttributeSourceAdvisor提供实现

编程式事务原理解析

  • 可以看到编程式事务是通过TransactionTemplatePlatformTransactionManager硬编码的形式来实现的,实际使用起来比声明式事务麻烦,而且侵入性强,因为这个很少使用所以不解析

总结

  • <tx:annotation-driven>标签是开启事务的开关,配置了这个就可以使用注解@Transactional来开启事务了,解析该标签的过程就是注册bean的过程
    • 注册BeanFactoryTransactionAttributeSourceAdvisor是整个事务功能的基础,这个类是判断这个bean是否需要适用事务增强,如果需要的话就创建AOP代理对象
    • 在解析事务自定义标签时SpringTransactionInterceptor类注入到了BeanFactoryTransactionAttributeSourceAdvisor,所以在调用事务增强器增强的代理类时会首先执行TransactionInterceptor进行增强,同时其invoke方法完成了整个事务的逻辑
  • Spring事务的初始化过程的大概逻辑是检查所有的bean是否需要创建AOP代理,判断逻辑是判断所在类及所在类的方法是否有@Transactional注解,如果有的话就创建代理,创建代理之后就是执行代理方法了,下章介绍

    参考

  • 《Spring 源码深度解析》