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

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

内容简介:<!--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源码分析:声明式事务梳理》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

CSS3 Solutions

CSS3 Solutions

Marco Casario / Apress / 2012-8-13 / GBP 35.50

CSS3 brings a mass of changes, additions, and improvements to CSS across a range of new modules. Web designers and developers now have a whole host of new techniques up their sleeves, from working wit......一起来看看 《CSS3 Solutions》 这本书的介绍吧!

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

多种字符组合密码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

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

HSV CMYK互换工具