Spring AOP-5 @Transactionl生成AOP代理对象

一. 介绍

从前面介绍的,我们对 Spring AOP 已经有了较全面的了解,现在我们对 @Transactional 注解生成 AOP 代理对象的过程做一个解析;

我们直接在 AbstractAutoProxyCreator#wrapIfNecessary() 方法中创建代理对象处打一个断点,和 Spring AOP 相关的 Advisor 是 BeanFactoryTransactionAttributeSourceAdvisor;

BeanFactoryTransactionAttributeSourceAdvisor 是在 ProxyTransactionManagementConfiguration 中引用的,ProxyTransactionManagementConfiguration 的配置类如下:

@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

    @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
        TransactionAttributeSource transactionAttributeSource,
        TransactionInterceptor transactionInterceptor) {
        
        // 使用的 pointcut 是: TransactionAttributeSourcePointcut  
        BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        
        // TransactionAttributeSource 是用来获取事务元数据的
        advisor.setTransactionAttributeSource(transactionAttributeSource);
        
        // 针对 @Transactional 使用的 Advice 
        advisor.setAdvice(transactionInterceptor);
        
        if (this.enableTx != null) {
            advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
        }
        return advisor;
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionAttributeSource transactionAttributeSource() {
        return new AnnotationTransactionAttributeSource();
    }

    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public TransactionInterceptor transactionInterceptor(
        TransactionAttributeSource transactionAttributeSource) {
        
        // 和 @Transactional 事务处理有关的 MethodInterceptor 是 TransactionInterceptor
        TransactionInterceptor interceptor = new TransactionInterceptor();
        interceptor.setTransactionAttributeSource(transactionAttributeSource);
        if (this.txManager != null) {
            // 设置事务管理器
            interceptor.setTransactionManager(this.txManager);
        }
        return interceptor;
    }

}

二. 事务处理相关的pointcutAdvisor

从上面分析我们知道和 @Transactional 事务处理的 PointcutAdvisor 是 BeanFactoryTransactionAttributeSourceAdvisor;

它包含了 pointcut 和 advice,pointcut 用于匹配 bean 和对应的 method,advice 用于通知;

  • TransactionAttributeSourcePointcut:用于匹配 @Transactional 标记的方法或类;
  • TransactionInterceptor:用于处理事务方法的执行拦截;

对于 TransactionAttributeSourcePointcut,感兴趣可以看看,我们主要看 TransactionInterceptor 作为 MethodInterceptor 的 invoke() 逻辑;

三. TransactionInterceptor

事务的开启、提交、回滚,都是通过 TransactionInterceptor#invoke() 来进行拦截处理的;

TransactionInterceptor 实现了 MethodInterceptor 接口,它是一个 Advice;

// ------------------------ TransactionInterceptor ---------------------------
public class TransactionInterceptor 
    extends TransactionAspectSupport 
    implements MethodInterceptor, Serializable {

    public TransactionInterceptor() {
    }

    public TransactionInterceptor(TransactionManager ptm, 
                                  TransactionAttributeSource tas) {
        setTransactionManager(ptm);
        setTransactionAttributeSource(tas);
    }

    @Override
    @Nullable
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

        // 调用父类 TransactionAspectSupport 的 invokeWithinTransaction()
        // 方法执行完后执行我们熟悉的 invocation.proceed() 继续触发调用链
        return invokeWithinTransaction(invocation.getMethod(), targetClass, new CoroutinesInvocationCallback() {
            @Override
            @Nullable
            public Object proceedWithInvocation() throws Throwable {
                return invocation.proceed();
            }
            @Override
            public Object getTarget() {
                return invocation.getThis();
            }
            @Override
            public Object[] getArguments() {
                return invocation.getArguments();
            }
        });
    }

}

TransactionAspectSupport 的 invokeWithinTransaction() 方法体很长,我们关注重点部分;

protected Object invokeWithinTransaction(Method method, 
                                         @Nullable Class<?> targetClass,
                                         final InvocationCallback invocation) {
    TransactionAttributeSource tas = getTransactionAttributeSource();
    
    // 1. 根据目标类和方法获取 TransactionAttribute
    // 其实这个类就是解析 @Transactional 注解得到的!!!
    // 如果 TransactionAttribute 是 null,表示方法不需要事务
    final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
    
    // 2. 获取事务管理器 TransactionManager
    final TransactionManager tm = determineTransactionManager(txAttr);

    // ...

    PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
    String joinpointIdentification =methodIdentification(method,targetClass,txAttr);

    if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
        // 3. 根据 TransactionManager、TransactionAttribute、方法标识等
        // 创建得到 TransactionInfo 对象
        TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

        Object retVal;
        try {
            // 4. 执行 methodInvocation.proceed()
            // 执行完一系列 MethodInterceptor 后最终会执行到目标方法,并得到方法返回值
            retVal = invocation.proceedWithInvocation();
        }
        catch (Throwable ex) {
            // 5.1 如果执行过程中出现了异常
            // 根据 @Transactional 注解信息决定是否进行回滚
            // 不管是否回滚,都会将异常抛出
            completeTransactionAfterThrowing(txInfo, ex);
            throw ex;
        }
        finally {
            // 清理事务信息,暂不是重点
            cleanupTransactionInfo(txInfo);
        }

        if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
            // ...
        }

        // 5.2 执行过程中没有出现异常
        // 对事务进行提交
        commitTransactionAfterReturning(txInfo);
        return retVal;
    }

    else {
        // ...
    }
}

重点是 3、5.1、5.2;下面我们逐个解析;

1. createTransactionIfNecessary()

根据 TransactionManager、TransactionAttribute、joinpointIdentification 方法标识等创建出 TransactionInfo 类对象,这里会根据事务管理器 TransactionManager 创建出事务状态对象 TransactionStatus;

// ----------------------- TransactionAspectSupport ----------------------------
protected TransactionInfo createTransactionIfNecessary(PlatformTransactionManager tm,
                                                     TransactionAttribute txAttr, 
                                                     String joinpointIdentification) {
    if (txAttr != null && txAttr.getName() == null) {
        txAttr = new DelegatingTransactionAttribute(txAttr) {
            @Override
            public String getName() {
                return joinpointIdentification;
            }
        };
    }

    TransactionStatus status = null;
    if (txAttr != null) {
        if (tm != null) {
            // 1. 根据事务管理器创建出事务状态对象 TransactionStatus
            status = tm.getTransaction(txAttr);
        }
        else {
            // ...
        }
    }
    
    // 2. 根据 tm、txAttr、joinpointIdentification、transactionStatus
    // 创建出 TransactionInfo 对象
    return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

2. completeTransactionAfterThrowing()

// ------------------------- TransactionAspectSupport ---------------------------
protected void completeTransactionAfterThrowing(TransactionInfo txInfo,
                                                Throwable ex) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        // 1. 如果当前异常需要需要回滚,那么回滚事务
        if (txInfo.transactionAttribute != null && 
            txInfo.transactionAttribute.rollbackOn(ex)) {
            // 回滚事务
            // tm.rollback(transactionStatus)
            txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
        } else {
            // 当前异常不需要回滚,不回滚事务
            // 提交事务
            // tm.commit(transactionStatus)
            txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
        }
    }
}

如果当前异常需要回滚,那么回滚事务;

如果当前异常不需要回滚,那么不回滚事务,提交事务;

我们看下 rollbackOn(ex) 的逻辑;

// ------------------------ RuleBasedTransactionAttribute ----------------------
public boolean rollbackOn(Throwable ex) {
    RollbackRuleAttribute winner = null;
    int deepest = Integer.MAX_VALUE;

    // 1. 根据 rollbackRules 匹配异常 ex
    // rollbackFor 属性对应的是 RollbackRuleAttribute
    // noRollbackFor 属性对应的是 NoRollbackRuleAttribute
    if (this.rollbackRules != null) {
        for (RollbackRuleAttribute rule : this.rollbackRules) {
            int depth = rule.getDepth(ex);
            if (depth >= 0 && depth < deepest) {
                deepest = depth;
                winner = rule;
            }
        }
    }

    // 2. 如果都不匹配的话,调用父类的匹配模式
    if (winner == null) {
        return super.rollbackOn(ex);
    }

    // 3. 如果异常匹配到了 RollbackRuleAttribute,返回 true,此时需要回滚
    // 如果异常匹配到了 NoRollbackRuleAttribute,返回 false,此时不需要回滚
    return !(winner instanceof NoRollbackRuleAttribute);
}



// 2. 如果都不匹配的话,调用父类的匹配模式
// ----------------------- DefaultTransactionAttribute -------------------------
public boolean rollbackOn(Throwable ex) {
    // 如果当前异常是 RuntimeException 或者 Error 类型的,返回 true,需要回滚
    // 其他异常如受检异常,返回 false,不回滚
    return (ex instanceof RuntimeException || ex instanceof Error);
}

这么看可能有些乱,需要仔细 debug 看看 RuleBasedTransactionAttribute 的流程,我们举几个例子看看:

1、例1:@Transactional 没有 rollbackFor,也没有 noRollbackFor;

此时 NullPointerException、IllegalArgumentException 都是 RuntimeException 类型,会走 DefaultTransactionAttribute#rollbackOn(),两种异常均会回滚;

@Transactional
public User updateUser(User user) throws IOException {
    int count = userMapper.updateUser(user);
    if (user.getId() == 4) {
        throw new NullPointerException("模拟出现空指针异常");
    } else if (user.getId() == 5) {
        throw new IllegalArgumentException();
    }

    return user;
}

2、例2:@Transactional 有 rollbackFor,没有 noRollbackFor;

出现 NullPointerException 异常会回滚事务;

出现 IllegalArgumentException 异常也会回滚事务;是不是很纳闷,IllegalArgumentException 不在 rollbackFor 列表啊,事务应该不回滚才对啊,错啦!我们按 RuleBasedTransactionAttribute#rollbackOn() 看一下,IllegalArgumentException 不会匹配到 RollbackRuleAttribute,winner == null,会走 DefaultTransactionAttribute#rollbackOn(),IllegalArgumentException 属于 RuntimeException,事务需要回滚;

@Transactional(rollbackFor = {NullPointerException.class})
public User updateUser(User user) throws IOException {
    int count = userMapper.updateUser(user);
    if (user.getId() == 4) {
        throw new NullPointerException("模拟出现空指针异常");
    } else if (user.getId() == 5) {
        throw new IllegalArgumentException();
    }

    return user;
}

3、例3:@Transactional 有 rollbackFor,也有 noRollbackFor;

出现 NullPointerException 异常会回滚事务;

出现 IllegalArgumentException 异常不会回滚事务;按 RuleBasedTransactionAttribute#rollbackOn() 看一下,IllegalArgumentException 会匹配到 NoRollbackRuleAttribute,winner != null,返回值为 false,不回滚事务;

@Transactional(rollbackFor = {NullPointerException.class}, 
               noRollbackFor = {IllegalArgumentException.class})
public User updateUser(User user) throws IOException {
    int count = userMapper.updateUser(user);
    if (user.getId() == 4) {
        throw new NullPointerException("模拟出现空指针异常");
    } else if (user.getId() == 5) {
        throw new IllegalArgumentException();
    }

    return user;
}

4、例4:@Transactional,没有 rollbackFor,也没有 noRollbackFor,且发生的是受检异常;

如上分析,RuleBasedTransactionAttribute#rollbackOn() 看一下,IOException 不会匹配到 RollbackRuleAttribute、NoRollbackRuleAttribute,winner == null,会走 DefaultTransactionAttribute#rollbackOn(),IOException 属于 RuntimeException,也不属于 Error,返回值 false,不回滚事务;

至此,事务回滚结束!

3. commitTransactionAfterReturning()

提交事务,这个我们在上面就分析过了;

// ------------------------- TransactionAspectSupport ----------------------------
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
    if (txInfo != null && txInfo.getTransactionStatus() != null) {
        // 提交事务
        // tm.commit(transactionStatus)
        txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
    }
}

四. 手动事务

首先,你需要获取一个 PlatformTransactionManager 的实例,这个实例通常在 Spring 的配置中定义;如果你使用的是 JDBC,可能会有一个 JdbcTransactionManager;如果是使用 Hibernate,则可能是HibernateTransactionManager;

  • TransactionDefinition:定义了事务的隔离级别、传播行为等属性;DefaultTransactionDefinition是一个默认实现,你也可以根据需要自定义;
  • TransactionStatus:表示事务的状态,包括是否新开始的事务、是否已提交或回滚等;
  • PlatformTransactionManager:提供了事务的管理接口,包括开始事务、提交事务、回滚事务等方法;
@Autowired
private PlatformTransactionManager transactionManager;


public void update() {
    TransactionDefinition def = new DefaultTransactionDefinition();
    TransactionStatus status = transactionManager.getTransaction(def);
    try {
        // 你的业务逻辑代码放在这里
        // ...

        // 业务逻辑成功,提交事务
        transactionManager.commit(status);
    } catch (Exception ex) {
        // 业务逻辑失败,回滚事务
        transactionManager.rollback(status);
        throw ex; // 可以选择重新抛出异常
    }
}

至此,手动事务完成;

  • 17
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值