Spring源码分析:声明式事务梳理
发布日期:2021-06-24 18:22:51 浏览次数:2 分类:技术文章

本文共 12619 字,大约阅读时间需要 42 分钟。

使用注解方式简单模拟事务

样例

说明

  1. 数据源采用c3p0
  2. 采用JdbcTemplate持久化
  3. 采用Spring事务注解

环境搭建

POM依赖

c3p0
c3p0
0.9.1.2
org.springframework
spring-jdbc
4.3.12.RELEASE
mysql
mysql-connector-java
5.1.44
runtime
org.springframework
spring-aspects
4.3.12.RELEASE

配置类

/** * description:声明式事务配置类,其中@EnableTransactionManagement * 一定要开启。 * @author 70KG */@Configuration@ComponentScan("com.nmys.story.springCore.springaop.tx_sample")@EnableTransactionManagement // -- 开启基于注解的事务管理public class TxConfig {    // -- 配置数据源    @Bean    public DataSource dataSource() throws Exception {        ComboPooledDataSource pool = new ComboPooledDataSource();        pool.setUser("root");        pool.setPassword("root");        pool.setDriverClass("com.mysql.jdbc.Driver");        pool.setJdbcUrl("jdbc:mysql://localhost:3306/usthe?useSSL=false");        return pool;    }    // -- 加入模板    @Bean    public JdbcTemplate jdbcTemplate() throws Exception {        JdbcTemplate template = new JdbcTemplate(dataSource());        return template;    }    // -- 配置事务管理器,它才是用来提交回滚事务的主导者    @Bean    public DataSourceTransactionManager txManager() throws Exception {        DataSourceTransactionManager tx = new DataSourceTransactionManager(dataSource());        return tx;    }}

业务类

/** * description * @author 70KG */@Servicepublic class TxService {    @Autowired    private TxDao txDao;    public void insertLog(){        txDao.insertSth();    }}

<!--more-->

/** * description * @author 70KG */@Repositorypublic class TxDao {    @Autowired    private JdbcTemplate jdbcTemplate;    // @Transactional仅表明它是一个事务方法,开启事务仅有注解是不够的,还需要配置事务管理器    @Transactional    public void insertSth() {        String sql = "INSERT into sys_log (username) VALUES(?);";        jdbcTemplate.update(sql, "lisi");        System.out.println("------>插入成功");        int i = 10/0;    }}

测试类

/** * description * @author 70KG */public class Test01 {    public static void main(String[] args) {        AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(TxConfig.class);        TxService bean = app.getBean(TxService.class);        bean.insertLog();    }}

测试结果

测试结果肯定是能正常运行的,下面试着跟一下源码。

源码分析

  1. 当容器开始启动运行的时候就会找到@EnableTransactionManagement注解
  2. 进入注解,发现它使用@Import(TransactionManagementConfigurationSelector.class)向容器中注入了这个类
  3. 跟进TransactionManagementConfigurationSelector,发现它最终实现的是ImportSelector接口,这个接口可以向IOC容器中以Bean的全类名的方式注入Bean。

源码如下,AdviceMode在注解@EnableTransactionManagement默认就是PROXY,可见它向容器中注入了两个类,分别是AutoProxyRegistrar和ProxyTransactionManagementConfiguration。

public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector
{ @Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME}; default: return null; } }}

AutoProxyRegistrar

  1. AutoProxyRegistrar翻译过来:自动代理注册器。进入AutoProxyRegistrar类,截取部分源码,如下:
@Overridepublic void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {    boolean candidateFound = false;    Set
annoTypes = importingClassMetadata.getAnnotationTypes(); for (String annoType : annoTypes) { AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType); if (candidate == null) { continue; } Object mode = candidate.get("mode"); Object proxyTargetClass = candidate.get("proxyTargetClass"); if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && Boolean.class == proxyTargetClass.getClass()) { candidateFound = true; if (mode == AdviceMode.PROXY) { // -- 前面的代码主要是获取注解类型,注解信息等等。 // -- 主要是这个地方,如果必要的话,就向容器中注册一个自动代理创建器。 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); if ((Boolean) proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); return; } } } } ...........
  1. 进入registerAutoProxyCreatorIfNecessary(registry),AopConfigUtils类中,源码如下:
@Nullableprivate static BeanDefinition registerOrEscalateApcAsRequired(Class
cls, BeanDefinitionRegistry registry, @Nullable Object source) { // -- 断言 Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); // 先判断有没有org.springframework.aop.config.internalAutoProxyCreator // 首次进来,肯定没有 if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) { BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME); if (!cls.getName().equals(apcDefinition.getBeanClassName())) { int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName()); int requiredPriority = findPriorityForClass(cls); if (currentPriority < requiredPriority) { apcDefinition.setBeanClassName(cls.getName()); } } return null; } // -- 将cls也就是InfrastructureAdvisorAutoProxyCreator包装成RootBeanDefinition RootBeanDefinition beanDefinition = new RootBeanDefinition(cls); beanDefinition.setSource(source); beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // -- 将beanDefinition注册到IOC容器中,Bean的 // -- 名字就叫org.springframework.aop.config.internalAutoProxyCreator registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition); return beanDefinition;}
  1. 向容器中注入了InfrastructureAdvisorAutoProxyCreator,进入此类,发现父类是AbstractAdvisorAutoProxyCreator,AbstractAdvisorAutoProxyCreator的父类是AbstractAutoProxyCreator,AbstractAutoProxyCreator中的方法,创建并返回了代理类,如下:
/** * Create a proxy with the configured interceptors if the bean is * identified as one to proxy by the subclass. * @see #getAdvicesAndAdvisorsForBean */@Overridepublic Object postProcessAfterInitialization(@Nullable Object bean, String beanName) throws BeansException {    if (bean != null) {        Object cacheKey = getCacheKey(bean.getClass(), beanName);        if (!this.earlyProxyReferences.contains(cacheKey)) {            return wrapIfNecessary(bean, beanName, cacheKey);        }    }    return bean;}

给容器中注入InfrastructureAdvisorAutoProxyCreator的主要作用就是,利用后置处理器机制在对象创建以后,对对象进行包装,返回一个代理对象(增强器),代理对象执行方法,利用拦截器链进行调用。

ProxyTransactionManagementConfiguration

  1. 进入ProxyTransactionManagementConfiguration,部分源码如下:
// -- 向容器中注入名字为TRANSACTION_ADVISOR_BEAN_NAME的切面@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {    BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();        // -- 向切面中注入注解解析器,专门来解析事务注解的    advisor.setTransactionAttributeSource(transactionAttributeSource());        // -- 向切面中注入事务的拦截器,专门来拦截方法,包括事务的提交以及回滚操作    advisor.setAdvice(transactionInterceptor());    if (this.enableTx != null) {        advisor.setOrder(this.enableTx.
getNumber("order")); } return advisor;}
  1. 进入transactionAttributeSource()注解解析器,源码如下:
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {    this.publicMethodsOnly = publicMethodsOnly;    this.annotationParsers = new LinkedHashSet<>(2);        // -- Spring注解的解析器    this.annotationParsers.add(new SpringTransactionAnnotationParser());    if (jta12Present) {                // -- jta的解析器        this.annotationParsers.add(new JtaTransactionAnnotationParser());    }    if (ejb3Present) {                // -- ejb的解析器        this.annotationParsers.add(new Ejb3TransactionAnnotationParser());    }}
  1. 进入SpringTransactionAnnotationParser(),部分源码如下:
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
rollBackRules = new ArrayList<>(); Class
[] rbf = attributes.getClassArray("rollbackFor"); for (Class
rbRule : rbf) {

会发现@Transactional中的各种属性都在这里,这样,注解解析器就分析完了

  1. 再来看事务的拦截器,分析事务是如何回滚和提交的,进入transactionInterceptor()
@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionInterceptor transactionInterceptor() {        // -- 事务的拦截器    TransactionInterceptor interceptor = new TransactionInterceptor();    interceptor.setTransactionAttributeSource(transactionAttributeSource());    if (this.txManager != null) {                // -- 将事务管理器设置进去,为了事务的提交和回滚操作        interceptor.setTransactionManager(this.txManager);    }    return interceptor;}

TransactionInterceptor 是一个实现了MethodInterceptor接口的类,标志着TransactionInterceptor是一个方法拦截器,进入它的invoke()方法

@Override@Nullablepublic Object invoke(final MethodInvocation invocation) throws Throwable {    // Work out the target class: may be {@code null}.    // The TransactionAttributeSource should be passed the target class    // as well as the method, which may be from an interface.    Class
targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); // Adapt to TransactionAspectSupport's invokeWithinTransaction... return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);}

进入invokeWithinTransaction()

@Nullableprotected Object invokeWithinTransaction(Method method, @Nullable Class
targetClass, final InvocationCallback invocation) throws Throwable { // If the transaction attribute is null, the method is non-transactional. TransactionAttributeSource tas = getTransactionAttributeSource(); // -- 拿到事务注解信息包括事务的qualifier和rollback信息 final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); // -- 获取事务管理器 final PlatformTransactionManager tm = determineTransactionManager(txAttr); // -- 事务连接点的定义信息 final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // 创建并开启事务 TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked. // -- 调用目标方法 retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // target invocation exception // -- 出现异常了,获取事务管理器,进行事务的回滚 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); } // -- 未出现异常,也获取事务管理器则进行事务的提交 commitTransactionAfterReturning(txInfo); return retVal; } .........

总结

Spring事务源码梳理
  1. 通过注解@EnableTransactionManagement中的@Import(TransactionManagementConfigurationSelector.class)给容器中导入了两个组件,分别是:AutoProxyRegistrar和ProxyTransactionManagementConfiguration
  2. AutoProxyRegistrar:它是一个后置处理器,给容器中注册一个InfrastructureAdvisorAutoProxyCreator,InfrastructureAdvisorAutoProxyCreator利用后置处理器机制在对象创建以后,对对象进行包装,返回一个代理对象(增强器),代理对象执行方法,利用拦截器链进行调用。
  3. ProxyTransactionManagementConfiguration:给容器中注册事务增强器
  • 事务增强器要用事务注解信息:AnnotationTransactionAttributeSource来解析事务注解
  • 事务拦截器中:transactionInterceptor(),它是一个TransactionInterceptor(保存了事务属性信息和事务管理器),而TransactionInterceptor是一个MethodInterceptor,在目标方法执行的时候,执行拦截器链,事务拦截器(首先获取事务相关的属性,再获取PlatformTransactionManager,如果没有指定任何transactionManager,最终会从容器中按照类型获取一个PlatformTransactionManager,最后执行目标方法,如果异常,便获取到事务管理器进行回滚,如果正常,同样拿到事务管理器提交事务。

转载地址:https://blog.csdn.net/weixin_34248258/article/details/88656323 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:记一次前端面试试水笔记
下一篇:Spring Cloud Gateway 使用 Token 验证

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2024年04月26日 06时47分55秒