微服务架构下,多个微服务都需要事务操作,如果在每个微服务下都从头配置事务,将非常繁锁。事务配置具有高度的一致性,可以抽取出来,制作starter,在需要配置事务的服务中引入starter依赖即可。
采用springAOP的方式实现事务
制作过程可以参考:
名称:
tuwer-transaction-spring-boot-starter
引用模块用于外部引用。只有
pom.xml
文件
<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.0modelVersion>
<groupId>com.tuwergroupId>
<artifactId>tuwer-transaction-spring-boot-starterartifactId>
<version>1.0-SNAPSHOTversion>
<description>事务starterdescription>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>com.tuwergroupId>
<artifactId>tuwer-transaction-spring-boot-starter-autoconfigureartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
dependencies>
project>
名称:
tuwer-transaction-spring-boot-starter-autoconfigure
\
使用jdbc的事务管理器
<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.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.6.7version>
parent>
<modelVersion>4.0.0modelVersion>
<groupId>com.tuwergroupId>
<artifactId>tuwer-transaction-spring-boot-starter-autoconfigureartifactId>
<version>1.0-SNAPSHOTversion>
<description>事务starter自动配置模块description>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-aopartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
dependencies>
project>
用于外部配置切入点
可以配置多个
如果没有配置,就使用默认的:
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;
/**
* 事务属性类
*
* @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.*(..))'
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;
/**
* 事务自动配置类
*
* @author 土味儿
* Date 2023/4/17
* @version 1.0
*/
@Aspect
@Configuration
@EnableConfigurationProperties(TransactionProperty.class)
public class TuwerTransactionAutoConfiguration {
/**
* 注入 TransactionProperty 属性配置类
*/
@Resource
private TransactionProperty transactionProperty;
/**
* 注入事务管理器
*/
@Resource
private TransactionManager transactionManager;
/**
* 定义事务增强
*
* @return
*/
@Bean
public 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
*/
@Bean
public Advisor txAdviceAdvisor() {
// 切入点
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression(transactionProperty.getPointcutExpression());
return new DefaultPointcutAdvisor(pointcut, txAdvice());
}
}
指明自动配置类的地址,在
resources
目录下编写一个自己的META-INF\spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.tuwer.config.TuwerTransactionAutoConfiguration
把starter安装install到本地maven仓库中
<dependency>
<groupId>com.tuwergroupId>
<artifactId>tuwer-transaction-spring-boot-starterartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
如果不配置,就使用默认的切入点;此步骤可以省略。
至此,事务配置就OK了!