Spring's Road to God Chapter 50: How to control the order of spring transaction interceptors?

Spring's Road to God Chapter 50: How to control the order of spring transaction interceptors?

1 Introduction

We know that Spring transactions add a transaction interceptor through aop. The transaction interceptor intercepts the execution of the target method and adds transaction control before and after method execution .

So how to control the order of spring transaction interceptors? If we also add some interceptors ourselves, how is their order executed when transaction interceptors and custom interceptors coexist? How to manually control their order? ?

Some friends may ask, what is the use of this function to control their order? why learn this

After learning these, you can achieve many amazing functions, such as

1. Separation of reading and writing

2. General idempotent framework

3. Distributed transaction framework

Interested in these? So let's continue.

2. Transaction interceptor order setting

The @EnableTransactionManagement annotation has an order attribute. The default value is Integer.MAX_VALUE, which is used to specify the order of transaction interceptors. The smaller the value, the higher the priority of the interceptor , such as:

@EnableTransactionManagement(order = 2)

Let's look at the case below.

3. Case

We customize 2 interceptors: one is executed before the transaction interceptor, and the other is executed after the transaction interceptor

interceptor order
TransactionInterceptorBefore 1
@EnableTransactionManagement transaction interceptor 2
TransactionInterceptorAfter 3

3.1. Prepare SQL

DROP DATABASE IF EXISTS javacode2018;
CREATE DATABASE if NOT EXISTS javacode2018;

USE javacode2018;
DROP TABLE IF EXISTS t_user;
CREATE TABLE t_user(
  id int PRIMARY KEY AUTO_INCREMENT,
  name varchar(256) NOT NULL DEFAULT '' COMMENT '姓名'
);

3.2, Spring configuration class MainConfig10

@1: The transaction management function is enabled, and the order of setting the transaction interceptor is 2, and the full class name of the spring transaction interceptor is

org.springframework.transaction.interceptor.TransactionInterceptor

@2: Enable aop function

package com.javacode2018.tx.demo10;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import javax.sql.DataSource;

@Configuration //说明当前类是一个配置类
@ComponentScan //开启bean自动扫描注册功能
@EnableTransactionManagement(order = 2) //@1:设置事务拦截器的顺序是2
@EnableAspectJAutoProxy // @2:开启@Aspect Aop功能
public class MainConfig10 {
    
    
    @Bean
    public DataSource dataSource() {
    
    
        org.apache.tomcat.jdbc.pool.DataSource dataSource = new org.apache.tomcat.jdbc.pool.DataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/javacode2018?characterEncoding=UTF-8");
        dataSource.setUsername("root");
        dataSource.setPassword("root123");
        dataSource.setInitialSize(5);
        return dataSource;
    }

    //定义一个jdbcTemplate
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource) {
    
    
        return new JdbcTemplate(dataSource);
    }

    //定义事务管理器transactionManager
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
    
    
        return new DataSourceTransactionManager(dataSource);
    }
}

3.3. Define a service class with transactions

The @Transactional annotation is added to the addUser method, indicating that spring is used to manage transactions. A piece of data is inserted into the db inside the method. In order to facilitate the analysis of the results, 2 lines of logs are output inside the method

package com.javacode2018.tx.demo10;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
public class UserService {
    
    
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Transactional
    public void addUser() {
    
    
        System.out.println("--------UserService.addUser start");
        this.jdbcTemplate.update("insert into t_user(name) VALUES (?)", "张三");
        System.out.println("--------UserService.addUser end");
    }
}

3.4. Customize the first interceptor and execute it before the transaction interceptor

The following defines an interceptor in the way of Aspect, and the order is set to 1** through **@Order(1), then this interceptor will be executed before the transaction interceptor.

package com.javacode2018.tx.demo10;

import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Order(1) //@1
public class TransactionInterceptorBefore {
    
    

    @Pointcut("execution(* com.javacode2018.tx.demo10.UserService.*(..))")
    public void pointcut() {
    
    
    }

    @Around("pointcut()")
    public Object tsBefore(ProceedingJoinPoint joinPoint) throws Throwable {
    
    
        System.out.println("--------before start!!!");
        Object result = joinPoint.proceed();
        System.out.println("--------before end!!!");
        return result;
    }
} 

3.4. Customize the second interceptor and execute it behind the transaction interceptor

The order of this interceptor is 3 , and it will be executed after the transaction interceptor.

package com.javacode2018.tx.demo10;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Order(2)
public class TransactionInterceptorAfter {
    
    

    @Pointcut("execution(* com.javacode2018.tx.demo10.UserService.*(..))")
    public void pointcut() {
    
    
    }

    @Around("pointcut()")
    public Object tsAfter(ProceedingJoinPoint joinPoint) throws Throwable {
    
    
        System.out.println("--------after start!!!");
        Object result = joinPoint.proceed();
        System.out.println("--------after end!!!");
        return result;
    }
}

3.5. Add test class

package com.javacode2018.tx.demo10;

import org.junit.Before;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;

public class Demo10Test {
    
    

    private UserService userService;

    private JdbcTemplate jdbcTemplate;

    @Before
    public void before() {
    
    
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig10.class);
        userService = context.getBean(UserService.class);
        this.jdbcTemplate = context.getBean("jdbcTemplate", JdbcTemplate.class);
        jdbcTemplate.update("truncate table t_user");
    }

    @Test
    public void test1() {
    
    
        this.userService.addUser();
    }
}

3.6. Analyze the code execution sequence of the test1 method

Let's not execute it first, but analyze the execution sequence of the test1 method. The test1 method will call the addUser method of userService inside, and this method will be intercepted by three interceptors.

Two custom interceptors and transaction interceptor TransactionInterceptor intercept, the execution order is as follows:

[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-TOwq5IVd-1684758884785)(%E6%96%B0%E5%BB%BA%E6%96%87% E6%9C%AC%E6%96%87%E6%A1%A3/1369022-20211107214634339-149521515.png)]

Let's run it to see if the results are consistent with our analysis.

3.7, run test1 output

--------before start!!!
--------after start!!!
--------UserService.addUser start
--------UserService.addUser end
--------after end!!!
--------before end!!!

The result is consistent with the above figure. You can set breakpoints in the three interceptors and debug to see more detailed information, which can deepen your understanding.

4. Summary

Today's content is relatively simple. The key point is how to set the order of transaction interceptors. @EnableTransactionManagement has an order attribute. The default value is Integer.MAX_VALUE, which is used to specify the order of transaction interceptors. The smaller the value, the priority of the interceptor The higher the level.

Later, we will use this function to achieve read-write separation and general idempotence.

5. Case source code

git地址:
https://gitee.com/javacode2018/spring-series

本文案例对应源码:
    spring-series\lesson-002-tx\src\main\java\com\javacode2018\tx\demo10

img

Passerby A All java case codes will be put on this in the future, everyone watch it, you can continue to pay attention to the dynamics.

Idempotent functions.

5. Case source code

git地址:
https://gitee.com/javacode2018/spring-series

本文案例对应源码:
    spring-series\lesson-002-tx\src\main\java\com\javacode2018\tx\demo10

[External link image transfer...(img-QzXTdX1k-1684758884786)]

Passerby A All java case codes will be put on this in the future, everyone watch it, you can continue to pay attention to the dynamics.

Source: https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648937858&idx=2&sn=b0e122919f677ee0cfd93c0036503b8d&scene=21#wechat_redirect

Guess you like

Origin blog.csdn.net/china_coding/article/details/130814731