用spring-boot-starter实现事务的统一配置
一、前言
微服务架构下,多个微服务都需要事务操作,如果在每个微服务下都从头配置事务,将非常繁锁。事务配置具有高度的一致性,可以抽取出来,制作starter,在需要配置事务的服务中引入starter依赖即可。
-
采用springAOP的方式实现事务
-
制作过程可以参考:
- 自定义启动器 Starter【保姆级教程】
- 用starter实现Oauth2中资源服务的统一配置
二、制作starter
1、完整结构图
2、引用模块
名称:
tuwer-transaction-spring-boot-starter
引用模块用于外部引用。只有
pom.xml
文件
- pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.tuwer</groupId><artifactId>tuwer-transaction-spring-boot-starter</artifactId><version>1.0-SNAPSHOT</version><description>事务starter</description><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><!-- 编译编码 --><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!-- 自动配置模块 --><dependency><groupId>com.tuwer</groupId><artifactId>tuwer-transaction-spring-boot-starter-autoconfigure</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies>
</project>
3、自动配置模块
名称:
tuwer-transaction-spring-boot-starter-autoconfigure
\\
1> pom.xml
使用jdbc的事务管理器
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.7</version></parent><modelVersion>4.0.0</modelVersion><groupId>com.tuwer</groupId><artifactId>tuwer-transaction-spring-boot-starter-autoconfigure</artifactId><version>1.0-SNAPSHOT</version><description>事务starter自动配置模块</description><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><!-- 编译编码 --><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!-- 基础启动器 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><!-- aop --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- 数据库 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency></dependencies>
</project>
2> 切入点属性类
用于外部配置切入点
可以配置多个
如果没有配置,就使用默认的:
execution(* com.tuwer.service..*Impl.*(..))
,【com.tuwer.service】包及子包下,所有以【Impl】结尾的类的所有方法
package com.tuwer.config;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.util.CollectionUtils;import java.util.HashSet;
import java.util.Set;/* <p>事务属性类</p> @author 土味儿* Date 2023/4/17* @version 1.0*/
@ConfigurationProperties(prefix = "tuwer-transaction")
public class TransactionProperty {/* 切入点(可以有多个)* 格式必须符合要求*/private Set<String> pointcut = new HashSet<>();/* 获取切入点表达式(可以有多个组合)* -----------------------------------* execution(...) || execution(...)* -----------------------------------* @return*/public String getPointcutExpression() {// 如果set集合为null,或没有值时,使用默认值if(CollectionUtils.isEmpty(this.pointcut)){// 默认切入点:【com.tuwer.service】包及子包下,所有以【Impl】结尾的类的所有方法return "execution(* com.tuwer.service..*Impl.*(..))";}StringBuilder sb = new StringBuilder();// 组合多个切入点for (String p : this.pointcut) {sb.append(" || ").append("execution(").append(p).append(")");}// 组合后,去除最前面的" || "返回return sb.substring(3);}public void setPointcut(Set<String> pointcut) {this.pointcut = pointcut;}
}
外部配置切入点示例:
由于切入点中有特殊字符
*
,所以需要加入引号:单引号或双引号都可以
# 事务切入点
tuwer-transaction:pointcut:- '* com.tuwer1231.service..*Impl.*(..))'- '* com.tuwer.service123..*Impl.*(..))'- '* com.tuwer345.service123..*Impl.*(..))'
3> 切面自动配置类
package com.tuwer.config;import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;import javax.annotation.Resource;/* <p>事务自动配置类</p> @author 土味儿* Date 2023/4/17* @version 1.0*/
@Aspect
@Configuration
@EnableConfigurationProperties(TransactionProperty.class)
public class TuwerTransactionAutoConfiguration {/* 注入 TransactionProperty 属性配置类*/@Resourceprivate TransactionProperty transactionProperty;/* 注入事务管理器*/@Resourceprivate TransactionManager transactionManager;/* 定义事务增强 @return*/@Beanpublic TransactionInterceptor txAdvice() {NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();// 查询等;只读DefaultTransactionAttribute readonlyAttr = new DefaultTransactionAttribute();readonlyAttr.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);readonlyAttr.setReadOnly(true);source.addTransactionalMethod("get*", readonlyAttr);source.addTransactionalMethod("select*", readonlyAttr);source.addTransactionalMethod("query*", readonlyAttr);source.addTransactionalMethod("load*", readonlyAttr);source.addTransactionalMethod("search*", readonlyAttr);source.addTransactionalMethod("find*", readonlyAttr);source.addTransactionalMethod("list*", readonlyAttr);source.addTransactionalMethod("count*", readonlyAttr);source.addTransactionalMethod("is*", readonlyAttr);// 增删改DefaultTransactionAttribute otherAttr = new DefaultTransactionAttribute();otherAttr.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);source.addTransactionalMethod("*", otherAttr);return new TransactionInterceptor(transactionManager, source);}/* 织入事务 @return*/@Beanpublic Advisor txAdviceAdvisor() {// 切入点AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();pointcut.setExpression(transactionProperty.getPointcutExpression());return new DefaultPointcutAdvisor(pointcut, txAdvice());}
}
4> spring.factories
指明自动配置类的地址,在
resources
目录下编写一个自己的META-INF\\spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\com.tuwer.config.TuwerTransactionAutoConfiguration
5> Install
把starter安装install到本地maven仓库中
三、使用说明
1、引入starter依赖
<!-- 事务starter -->
<dependency><groupId>com.tuwer</groupId><artifactId>tuwer-transaction-spring-boot-starter</artifactId><version>1.0-SNAPSHOT</version>
</dependency>
2、配置切入点
如果不配置,就使用默认的切入点;此步骤可以省略。
至此,事务配置就OK了!