Spring AOP应用之事务

一、定义

二、核心概念

1、@EnableTransactionManager

作用:在Spring开启事务功能。

2、数据源DataSource

A、Spring的DataSource种类

  • org.springframework.jdbc.datasource.DriverManagerDataSource 

        DriverManagerDataSource建立连接是只要有连接就新建一个connection,根本没有连接池的作用。

  • org.apache.commons.dbcp.BasicDataSource 

        BasicDataSource是一种推荐的数据源配置方式,它真正使用了连接池技术 

  • org.springframework.jndi.JndiObjectFactoryBean 

        JndiObjectFactoryBean能够通过JNDI获取DataSource,但要在web server中配置数据源,不方便于部署

B、DataSource的配置

3、事务管理器TransactionManager

A、TransactionManager的种类

B、TransactionManager的使用

4、@Transactional

A、作用

用@Transactional注解声明某个类或者某个方法具备事务功能。

B、失效场景

  • 开启事务、执行sql、回滚sql不是同一个连接
  • 目标方法不是公共方法
  • 抛出的异常被try{}catch住
  • 只有RuntimeException及其子类会默认回滚,除此之外的异常需要手动指定rollbackForClassName
  • 在同个类中,一个没有事务的方法内部调用另一个有事务的方法

        解决方法:

        a、把有事务的方法提到另一个类

        b、自己注入自己,然后用这个注入的类调取这个有事务的方法。

参考地址:https://blog.csdn.net/qq_45607784/article/details/134897741

三、原理

1、认识

2、总体流程

a、前置准备

有一个SysConfig类使用了@EnableTransactionManangement和@Configuration注解进行声明,类里面使用@Bean注解声明了DataSource、TestAopMethod类的bean信息。TestAopMethod里有一个testTransaction方法声明了@Transactional注解。

@EnableTransactionManagement
@Configuration
// 实现TransactionManagementConfigurer接口可以重新设置TransactionManagement
public class SysConfig
{

    @Bean
    DataSource dataSource() {
        CustomDataSource dataSource = new CustomDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://xxx:xxx/xxx?characterEncoding=utf-8&useSSL=false");
        dataSource.setUsername("xxx");
        dataSource.setPassword("xxx");
        return dataSource;
    }

    @Bean
    DataSourceTransactionManager dataSourceTransactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }


    @Bean
    public TestAopMethod testAopMethod() {
        return new TestAopMethod();
    }

}
public class CustomDataSource extends DriverManagerDataSource {
    private Connection conn;

    @Override
    public Connection getConnection() throws SQLException {
        if(conn==null){
            // 保证同个连接
            conn=super.getConnection();
        }

        return conn;
    }
}
public class TestAopMethod {

    @Transactional
    public void testTransaction(DataSource ds) throws SQLException {
        Connection conn=ds.getConnection();
        Statement sm=conn.createStatement();
        ResultSet res=sm.executeQuery("SELECT * FROM label");
        while(res.next()){
            System.out.println(res.getString("name"));
        }

        res.close();
        sm.close();
        conn.close();

        System.out.println("I AM TESTTRANSACTION");
    }
}
    public static void main(String[] args) throws SQLException {

        AnnotationConfigApplicationContext context1=new AnnotationConfigApplicationContext(SysConfig.class);
        TestAopMethod obj= (TestAopMethod) context1.getBean("testAopMethod");
        DataSource ds= (DataSource) context1.getBean("dataSource");
        obj.testTransactionAboutInsert(ds);
    }

b、Spring事务执行过程

(1)启动容器

(2)创建并初始化容器

添加ConfigurationClassPostProcessor类的bean信息到容器中

(3)添加配置类SysConfig的bean信息到容器中

(4)容器刷新

a、调用invokeBeanFactoryPostProcessor方法解析SysConfig配置类上标注的@EnableTransactionManagement注解,真正解析的是里面的@Import注解,调用@Import注解的TransactionManagementConfigurationSelector类的selectImports方法,该方法会返回AutoProxyRegistrarProxyTransactionManagementConfiguration的Bean信息。根据返回的bean信息继续解析ProxyTransactionManagementConfiguration bean信息里面声明了@Bean注解的方法,即BeanFactoryTransactionAttributeSourceAdvisorAnnotationTransactionAttributeSourceTransactionInterceptor这3个bean信息。BeanFactoryTransactionAttributeSourceAdvisor是Spring AOP的Advisor的实现类,包含AnnotationTransactionAttributeSource和通知TransactionInterceptor,而BeanFactoryTransactionAttributeSourceAdvisor里面的切点TransactionAttributeSourcePointcut是通过getTransactionAttributeSourcePointcut方法获得,方法内容是返回AnnotationTransactionAttributeSource实例。接着会通过loadBeanDefinitionFromRegistrars方法执行AutoProxyRegistrar类的registerBeanDefinitions方法。该方法会向容器中添加InfrastructureAdvisorAutoProxyCreator的bean信息。

b、调用finishBeanFactoryInitialization方法实例化所有非懒加载的bean信息。该方法的核心是调用容器的getBean方法。

在getBean方法对bean实例进行applyBeanPostProcessorsAfterInitialization初始化后处理阶段,会在这个阶段调用InfrastructureAdvisorAutoProxyCreatorpostProcessAfterInitialization方法,该方法是创建那些声明了@Transactional注解的类的代理对象。这里实际调用的是InfrastructureAdvisorAutoProxyCreator的祖父类AbstractAutoProxyCreatorpostProcessAfterInitialization方法。该方法里面的核心逻辑是执行wrapIfNecessary方法。wrapIfNecessary方法会去执行findAdvisorBeans方法来找到所有isEligibleBean方法为true的Advisor实现类。这里实际调用的是InfrastructureAdvisorAutoProxyCreator的isEligibleBean方法,它的判断逻辑是Bean信息上是否声明了role属性BeanDefinition.ROLE_INFRASTRUCTURE(即声明了@Role注解,且value为BeanDefinition.ROLE_INFRASTRUCTURE)。找到所有Advisor实现类后,会去调用findAdvisorsThatCanApply筛出切入点和bean实例符合的Advisor实现类。筛选方式是调用PointCut实现类的内部类ClassFiltermatches方法是否为true,这里是调用TransactionAttributeSourcePointCut里面的内部类TransactionAttributeSourceClassFiltermatches方法。该matches方法会去调用Advisor实现类的切入点TransactionAttributeSource的isCandidateClass方法,即实际调用的是AnnotationTransactionAttributeSourceisCandidateClass方法,该isCandidateClass的核心逻辑是执行TransactionAnnotationParser的isCandidateClass方法。这里的默认TransactionAnnotationParser是SpringTransactionAnnotationParser类。而SpringTransactionAnnotationParser类的isCandidateClass方法是判断目标类是否声明了@Transactional注解找到符合条件的Advisor实现类后,就会基于这些实现类创建代理对象代理方法内容是对目标方法使用环绕通知TransactionInterceptor

(5)调用容器的getBean方法获取TestAopMethod实例

(6)执行TestAopMethod实例的testTransactional方法,这里实际上是执行TestAopMethod代理对象的testTransactional方法。真正执行的是TransactionInterceptor的invoke方法(这个invoke方法已经合成在代理对象中),该方法的核心是invokeWithTransaction方法,该方法对目标方法的增强方式是在目标方法前开启事务,在目标方法后关闭事务,出现异常会回滚事务

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值