Spring源码分析:声明式事务梳理

栏目: Java · 发布时间: 5年前

内容简介:<!--more-->测试结果肯定是能正常运行的,下面试着跟一下源码。

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

样例

说明

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

环境搭建

POM依赖

<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>
<!-- spring提供的jdbcTemplate模块 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.3.12.RELEASE</version>
</dependency>
<!-- mysql链接驱动包 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.44</version>
    <scope>runtime</scope>
</dependency>
<!-- AOP -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.12.RELEASE</version>
</dependency>

配置类

/**
 * 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
 */
@Service
public class TxService {

    @Autowired
    private TxDao txDao;

    public void insertLog(){
        txDao.insertSth();
    }

}

<!--more-->

/**
 * description
 * @author 70KG
 */
@Repository
public 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<EnableTransactionManagement> {
    @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类,截取部分源码,如下:
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    boolean candidateFound = false;
    Set<String> 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类中,源码如下:
@Nullable
private 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
 */
@Override
public 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.<Integer>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<RollbackRuleAttribute> 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
@Nullable
public 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()

@Nullable
protected 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,最后执行目标方法,如果异常,便获取到事务管理器进行回滚,如果正常,同样拿到事务管理器提交事务。

以上所述就是小编给大家介绍的《Spring源码分析:声明式事务梳理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

新媒体运营

新媒体运营

勾俊伟 / 人民邮电出版社 / 2018-5-1 / 39.80

本书全面介绍了新媒体运营以及新媒体运营各模块的具体内容。 第 1章重点介绍新媒体运营的基本概念,其中包括运营的定义、发展历史及专业术语; 第 2章重点介绍新媒体运营的职业发展,通过企业需求反推能力清单,引导读者全面了解新媒体运营的岗位及相关要求; 第3章重点介绍用户运营的方法与策略,包括描述用户画像、搭建用户体系、吸引精准用户及提升用户活跃度等具体技巧; 第4章重点介绍产品......一起来看看 《新媒体运营》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

随机密码生成器
随机密码生成器

多种字符组合密码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具