本篇是通过aop实现多数据源事务的处理,多数据源事务网上页有很多例子,但大多数是运用分布式事务实现的,对于一站式应用总感觉怪怪的,于是总结了一下通过aop实现多数据源事务的例子。
org.springframework.boot
spring-boot-starter-aop
1、事务注解 TransactionAnno,用于标注使用事务
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TransactionAnno {
}
2、事务管理注解 TransactionManagerAnno,用于对多个事务管理对象进行管理
import org.springframework.context.annotation.Bean;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Bean
public @interface TransactionManagerAnno {
}
import com.boot.framework.common.config.ApplicationContextHolder;
import com.boot.framework.common.utils.FileUtil;
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.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;
/**
* Created by wxp on 2019/8/28.
*/
@Aspect
@Component
public class TransactionOperateAspect {
private Set multiTransactional=new HashSet<>();
@Pointcut("@annotation(com.boot.framework.common.config.aop.TransactionAnno)")
public void transactionAnno(){}
@Pointcut("@annotation(com.boot.framework.common.config.aop.TransactionManagerAnno)")
public void TransactionManagerAnno(){}
@Around(value = "transactionAnno()")
public Object manageTransaction(ProceedingJoinPoint pjp) throws Throwable{
Object result = null;
Stack dataSourceTransactionManagers = new Stack<>();
Stack transactionStatuses = new Stack<>();
try {
if (!openTransaction(dataSourceTransactionManagers, transactionStatuses))
return result;
result = pjp.proceed();
commit(dataSourceTransactionManagers, transactionStatuses);
}catch (Throwable e){
rollback(dataSourceTransactionManagers, transactionStatuses);
throw e;
}
return result;
}
/**
* 开启事务
* @param dataSourceTransactionManagers
* @param transactionStatuses
* @return
*/
private boolean openTransaction(Stack dataSourceTransactionManagers,
Stack transactionStatuses){
if (multiTransactional.size() == 0){
//获取所有数据源文件
ArrayList> classList = FileUtil.getClasses("com.boot.framework.common.config.datasource");
for (Class object: classList){
//获取类中所有方法
Method[] methods = object.getDeclaredMethods();
for (Method method : methods){
//方法上吐过存在TransactionManagerAnno注解则将方法添加进multiTransactional对象中
TransactionManagerAnno managerAnno = method.getAnnotation(TransactionManagerAnno.class);
if (managerAnno != null)//
multiTransactional.add(method.getName());
}
}
//无数据源事物
if (multiTransactional.size() == 0)
return false;
}
//将列表中的事务入栈
for (String transactionManagerName : multiTransactional){
DataSourceTransactionManager dataSourceTransactionManager = ApplicationContextHolder.getBean(transactionManagerName);
TransactionStatus status = dataSourceTransactionManager.getTransaction(new DefaultTransactionDefinition());
transactionStatuses.push(status);
dataSourceTransactionManagers.push(dataSourceTransactionManager);
}
return true;
}
/**
* 提交栈中事务
* @param dataSourceTransactionManagerStack
* @param transactionStatuStack
*/
private void commit(Stack dataSourceTransactionManagerStack,
Stack transactionStatuStack){
while (!dataSourceTransactionManagerStack.isEmpty()){
dataSourceTransactionManagerStack.pop().commit(transactionStatuStack.pop());
}
}
/**
* 回滚栈中事务
* @param dataSourceTransactionManagerStack
* @param transactionStatuStack
*/
private void rollback(Stack dataSourceTransactionManagerStack,
Stack transactionStatuStack){
while (!dataSourceTransactionManagerStack.isEmpty()){
dataSourceTransactionManagerStack.pop().rollback(transactionStatuStack.pop());
}
}
}
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;
@Service
public class ApplicationContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext = null;
private static Logger logger = LoggerFactory.getLogger(ApplicationContextHolder.class);
// private static final Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);
/**
* 取得存储在静态变量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
assertContextInjected();
return applicationContext;
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static T getBean(String name) {
assertContextInjected();
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static T getBean(Class requiredType) {
assertContextInjected();
return applicationContext.getBean(requiredType);
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
public static void clearHolder() {
logger.debug("清除SpringContextHolder中的ApplicationContext:"
+ applicationContext);
applicationContext = null;
}
/**
* 实现ApplicationContextAware接口, 注入Context到静态变量中.
*/
public void setApplicationContext(ApplicationContext applicationContext) {
// logger.debug("注入ApplicationContext到SpringContextHolder:{}", applicationContext);
if (ApplicationContextHolder.applicationContext != null) {
logger.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + ApplicationContextHolder.applicationContext);
}
ApplicationContextHolder.applicationContext = applicationContext; // NOSONAR
}
/**
* 实现DisposableBean接口, 在Context关闭时清理静态变量.
*/
public void destroy() throws Exception {
ApplicationContextHolder.clearHolder();
}
/**
* 检查ApplicationContext不为空.
*/
private static void assertContextInjected() {
Validate.validState(applicationContext != null, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
}
}
当执行标注@TransactionAnno注解的方法时,会将所有的数据源事务管理器名字度存入局部变量集类型的multiTransactional,然后在访问这个方法前通过multiTransactional里面的所有数据源事务管理器名字取到对应的bean,手动开启事务后将的TransactionStatus对象全部放入一个栈中,(使用栈是因为要保障事务管理器出现的顺序,而不会因为顺序问题而报错),然后在方法正常执行完之后提交事务,在捕获到异常后回滚事务,并抛出事务。