事情是这样的,在最近开发项目中,由于公司引入了一些内部开发的包,但是包中做了一个切面,切面的目的是拦截所有的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); } }
这样的话,我们的目的就已经达到了。
加油哦。。