spring boot 项目中如何排除依赖包中的@Configuration配置类?

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

依赖包中的代码如下:

这段代码大致的意思就是,会拦截包下的所有的service的类,并且为所有的方法开启事务。这个并不是我想要的,因为我需要控制事务的粒度,并且查询方法不需要开启事务。以下则是可以解决问题的方法:

1. 重新命名项目路径

这个方法最简单,他既然拦截了路径下的service方法,那么我们在创建项目包的时候,跟他的路径包不一样就行了,让它的拦截不生效即可。

2. 使@Configuration注解的类不生效

spring boot为我们提供了几种能够控制配置加载的方法:

  1. 在启动@SpringBootApplication中使用exclude排除对应的configuration. 但是这种方式只适合autoconfiguration的情形,我们这里并不满足
  2. 使用@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);
    }

}

这样的话,我们的目的就已经达到了。

Show 1 Comment

1 Comment

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注