如何外置@SpringBootApplication的exclude配置,实现数据库自动配置排除复用?
问题根因
@SpringBootApplication本身已经组合了@EnableAutoConfiguration注解,Spring Boot的自动配置排除规则不会合并多个@EnableAutoConfiguration的exclude属性,只会优先取直接声明在启动类上的注解配置,你自定义注解里的@EnableAutoConfiguration配置被启动类上@SpringBootApplication自带的同名注解覆盖,所以不生效。- 自定义注解上标注的
@Configuration是无效的,该注解仅作用于普通类,不作用于注解定义。
可用解决方案
方案1:自定义组合注解替换@SpringBootApplication
直接把排除规则写在自定义的组合注解里,完全代替原生的@SpringBootApplication,需要排除数据源的启动类用自定义注解,需要数据源的启动类仍用原生注解即可。
注解定义示例:
import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.context.annotation.ComponentScan; import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited @SpringBootConfiguration @ComponentScan @EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class }) public @interface SpringBootAppWithoutDataSource { // 按需透传原生注解的属性,比如扫描路径、额外排除类等 String[] scanBasePackages() default {}; Class<?>[] exclude() default {}; }
使用方式:
// 不需要数据源的启动类 @SpringBootAppWithoutDataSource(scanBasePackages = "com.your.package") public class NoDbMainApp { public static void main(String[] args) { SpringApplication.run(NoDbMainApp.class, args); } } // 需要数据源的启动类,仍用原生注解 @SpringBootApplication public class DbMainApp { public static void main(String[] args) { SpringApplication.run(DbMainApp.class, args); } }
方案2:自定义标记注解+ImportFilter实现灵活排除
如果不想替换原生的@SpringBootApplication,可以通过自定义过滤器实现加注解就自动排除的逻辑:
- 定义空标记注解:
import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface ExcludeDataSources { }
- 实现自动配置过滤器:
import org.springframework.boot.autoconfigure.AutoConfigurationImportFilter; import org.springframework.boot.autoconfigure.AutoConfigurationMetadata; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.core.annotation.AnnotationUtils; import java.util.Arrays; import java.util.List; public class DataSourceExcludeFilter implements AutoConfigurationImportFilter { private static final List<String> EXCLUDE_CLASS_NAMES = Arrays.asList( DataSourceAutoConfiguration.class.getName(), DataSourceTransactionManagerAutoConfiguration.class.getName(), HibernateJpaAutoConfiguration.class.getName() ); @Override public boolean[] match(String[] autoConfigurationClasses, AutoConfigurationMetadata autoConfigurationMetadata) { boolean[] matches = new boolean[autoConfigurationClasses.length]; Arrays.fill(matches, true); // 检测当前启动类是否标注了排除注解 try { StackTraceElement[] stack = new RuntimeException().getStackTrace(); for (StackTraceElement ele : stack) { if ("main".equals(ele.getMethodName())) { Class<?> mainClazz = Class.forName(ele.getClassName()); if (AnnotationUtils.findAnnotation(mainClazz, ExcludeDataSources.class) != null) { // 标记需要排除的自动配置类 for (int i = 0; i < autoConfigurationClasses.length; i++) { if (EXCLUDE_CLASS_NAMES.contains(autoConfigurationClasses[i])) { matches[i] = false; } } } break; } } } catch (Exception ignored) {} return matches; } }
- 注册过滤器:在项目
resources/META-INF/spring.factories文件中添加配置:
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\ com.your.package.DataSourceExcludeFilter
- 使用方式:不需要数据源的启动类添加注解即可:
@SpringBootApplication @ExcludeDataSources public class NoDbMainApp { public static void main(String[] args) { SpringApplication.run(NoDbMainApp.class, args); } }
内容的提问来源于stack exchange,提问作者membersound
相关产品推荐
相关产品推荐

