事情是这样的,在最近开发项目中,由于公司引入了一些内部开发的包,但是包中做了一个切面,切面的目的是拦截所有的service类中的所有的方法,并开启事务管理。这就导致了项目结构中,如果你想控制事务的粒度成了问题,并且在普通查询的时候,是不需要开启事务的。
依赖包中的代码如下:

这段代码大致的意思就是,会拦截包下的所有的service的类,并且为所有的方法开启事务。这个并不是我想要的,因为我需要控制事务的粒度,并且查询方法不需要开启事务。以下则是可以解决问题的方法:
1. 重新命名项目路径
这个方法最简单,他既然拦截了路径下的service方法,那么我们在创建项目包的时候,跟他的路径包不一样就行了,让它的拦截不生效即可。
2. 使@Configuration注解的类不生效
spring boot为我们提供了几种能够控制配置加载的方法:
- 在启动@SpringBootApplication中使用exclude排除对应的configuration. 但是这种方式只适合autoconfiguration的情形,我们这里并不满足
- 使用@Conditional注解,使得在满足一定条件时,加载配置类。但是这个依赖包并没有提供这种机制。
因此,我在尝试了spring boot提供的方法之后,都无法控制,甚至我都用了继承,还是不行的。因此,就只能从类加载的角度来考虑这个问题。
我的思路是,重新定义路径和类名称一样的配置类,然后在配置类中不做任何操作,代码如下:
import org.springframework.context.annotation.Configuration;
@Configuration
public class GlobalTransactionHandler {
}
经过测试,依赖包中的配置类不会被加载。
这是因为,在做类加载的时候,会优先加载项目下的类,然后才会加载依赖包中的类,当路径和类名称相同时,会被认为对应的类已经被加载,则不会再去加载依赖包中的类,一次来达到目的。
当禁止了依赖包的配置后,我们就只需要实现我们自己的配置就好,配置如下:
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.interceptor.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@Aspect
@Configuration
@Order(value = Ordered.HIGHEST_PRECEDENCE)
public class GlobalTransactionAspectConfiguration {
private static final int TIME_OUT = -1;
private static final String AOP_POINTCUT_EXPRESSION = "execution(* com.console..service..*.*(..))";
public GlobalTransactionAspectConfiguration() {
}
@Bean
public TransactionInterceptor txAdvice(PlatformTransactionManager platformTransactionManager) {
// 只读配置
// RuleBasedTransactionAttribute readOnlyRule = new RuleBasedTransactionAttribute();
// readOnlyRule.setReadOnly(true);
// readOnlyRule.setPropagationBehavior(0);
// 需要开启事务的配置规则
RuleBasedTransactionAttribute requireRule = new RuleBasedTransactionAttribute();
requireRule.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
requireRule.setPropagationBehavior(0);
requireRule.setTimeout(-1);
Map<String, TransactionAttribute> nameMap = new HashMap(16);
nameMap.put("save*", requireRule);
nameMap.put("insert*", requireRule);
nameMap.put("add*", requireRule);
nameMap.put("update*", requireRule);
nameMap.put("move*", requireRule);
nameMap.put("delete*", requireRule);
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
source.setNameMap(nameMap);
return new TransactionInterceptor(platformTransactionManager, source);
}
@Bean
public Advisor txAdviceAdvisor(TransactionInterceptor txAdvice) {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
pointcut.setExpression("execution(* com..service..*.*(..))");
return new DefaultPointcutAdvisor(pointcut, txAdvice);
}
}
这样的话,我们的目的就已经达到了。
加油哦。。