事务与动态数据源不能同时有效。用了动态数据源,事务就不会生效。
lxt:
pointcut:
#在controller之前切入,初步数据验证 order为切入时机,越小越先切入
controller:
value: execution(public * cn.lexiaotongvip.www.control..*.*(..))
order: 1
service:
value: execution(* cn.lexiaotongvip.www.service..*.*(..))
order: 3
is-dynamic-db: true
package cn.lexiaotongvip.www.config;
import cn.lexiaotongvip.www.config.dbConfig.DataSourceEnum;
import cn.lexiaotongvip.www.config.dbConfig.DataSourceHolder;
import cn.lexiaotongvip.www.config.dbConfig.MyDataSource;
import cn.lexiaotongvip.www.control.enums.ResCodeEnum;
import cn.lexiaotongvip.www.control.pojo.qo.ReqParQO;
import cn.lexiaotongvip.www.control.pojo.vo.ResultVO;
import cn.lexiaotongvip.www.service.IDataService;
import org.aopalliance.intercept.MethodInterceptor;
import org.slf4j.Logger;
import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.NameMatchTransactionAttributeSource;
import org.springframework.transaction.interceptor.TransactionInterceptor;
import java.lang.reflect.Method;
/**
* 乐校通切面
* 1、controller前的操作:日志、校验、解析
* 2、service 事务全局配置
* 3、配置事务的地方加入动态数据源切换
*
* @author chenzy
* @since 2019.12.17
*/
@Configuration
//@ConditionalOnProperty(prefix = "lxt",name = "pointcut")
public class LXTAspect {
@Autowired
private Logger clientLog;
@Autowired
private IDataService dataService;
/**
* //执行业务前操作:日志、校验、解析
* @return
*/
@Bean
// @ConditionalOnProperty(prefix = "lxt.pointcut.controller",name = "value")
public AspectJExpressionPointcutAdvisor dataAspect(@Value("${lxt.pointcut.controller.value}") String pointcut
,@Value("${lxt.pointcut.controller.order}") Integer order) {
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
advisor.setExpression(pointcut);
advisor.setOrder(order);
advisor.setAdvice((MethodInterceptor) invocation -> {
Object verifyResult = dataVerify(invocation.getMethod().getName(), invocation.getArguments());
if (verifyResult != null) {
return verifyResult;
}
//执行业务方法
try {
Object result = invocation.proceed();
return result;
} catch (Throwable throwable) {
throwable.printStackTrace();
return new ResultVO(ResCodeEnum.UnknownExce);
}
});
return advisor;
}
/**
* 调用业务service前后切入
* 1、日志
* 2、数据校验
* 3、数据解析
*/
private Object dataVerify(String methodName, Object[] args) {
/*
* 第一个参数是ReqParQO类型才记录日志、数据校验、解析数据
*/
if (args != null && args.length >= 1 && args[0] instanceof ReqParQO) {
ReqParQO reqParQO = (ReqParQO) args[0];
//1、日志:记录请求参数
clientLog.info("[{}的请求参数]:{}", reqParQO.getRequestType().getMsg(), reqParQO.toString());
//2、数据校验
ResultVO result = dataService.dataVerify(reqParQO);
if (result.getCode().isException()) {
return result;
}
// 3、数据解析。
result = dataService.setBusDataJson(reqParQO);
// 4、数据校验未通过,或者数据解析失败,不执行业务方法,记录错误日志后直接返回错误信息
if (result.getCode().isException()) {
clientLog.info("[{}]return data <<< {}", methodName, result);
return result;
}
}
return null;
}
@Autowired
private PlatformTransactionManager transactionManager;
/**
* 事务切面。。。暂时不用事务
* @param pointcut
* @param order
* @return
*/
// @Bean
// @ConditionalOnProperty(prefix = "lxt.pointcut.service",name = "value")
public AspectJExpressionPointcutAdvisor transactionAspect(@Value("${lxt.pointcut.service.value}") String pointcut
,@Value("${lxt.pointcut.service.order}") Integer order){
DefaultTransactionAttribute txAttr_REQUIRED = new DefaultTransactionAttribute();
txAttr_REQUIRED.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
DefaultTransactionAttribute txAttr_REQUIRED_READONLY = new DefaultTransactionAttribute();
txAttr_REQUIRED_READONLY.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
txAttr_REQUIRED_READONLY.setReadOnly(true);
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
source.addTransactionalMethod("insert*", txAttr_REQUIRED);
source.addTransactionalMethod("save*", txAttr_REQUIRED);
source.addTransactionalMethod("delete*", txAttr_REQUIRED);
source.addTransactionalMethod("update*", txAttr_REQUIRED);
source.addTransactionalMethod("remove*", txAttr_REQUIRED);
source.addTransactionalMethod("modify*", txAttr_REQUIRED);
source.addTransactionalMethod("modify*", txAttr_REQUIRED);
source.addTransactionalMethod("test*", txAttr_REQUIRED);
source.addTransactionalMethod("get*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("query*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("find*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("list*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("count*", txAttr_REQUIRED_READONLY);
source.addTransactionalMethod("is*", txAttr_REQUIRED_READONLY);
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
advisor.setExpression(pointcut);
advisor.setOrder(order);
advisor.setAdvice(new TransactionInterceptor(transactionManager, source));
return advisor;
}
/**
*
* 动态数据源切换
* @param pointcut
* @param order
* @return
*/
@Bean
// @ConditionalOnProperty(prefix = "lxt.pointcut.service",name = "is-dynamic-db",havingValue ="true")
public AspectJExpressionPointcutAdvisor dynamicDBAspect(@Value("${lxt.pointcut.service.value}") String pointcut
,@Value("${lxt.pointcut.service.order}") Integer order){
AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor();
advisor.setExpression(pointcut);
advisor.setOrder(order-1);
advisor.setAdvice((MethodInterceptor) invocation -> {
Method method = invocation.getMethod();
if (method.isAnnotationPresent(MyDataSource.class)) {
DataSourceHolder.set(method.getAnnotation(MyDataSource.class).value());
} else {
//当其他数据源操作完后,数据源不会自动变为默认数据源,需要在这里更改
DataSourceHolder.set(DataSourceEnum.DEFAULT);
}
Object result=invocation.proceed();
DataSourceHolder.clear();
return result;
});
return advisor;
}
}