Spring Boot中@ComponentScan.Filter无法过滤@Configuration配置类问题
问题根因
这个问题是Spring 5.2.x版本注解扫描规则叠加导致的,核心原因如下:
@SpringBootApplication注解本身内置了@ComponentScan逻辑,默认会扫描启动类所在包及其所有子包下的组件。你在启动类上额外声明的@ComponentScan不会覆盖内置的扫描规则,二者的扫描逻辑会叠加生效:你自定义的excludeFilters仅作用于你额外声明的扫描规则,无法拦截内置扫描逻辑对ServerAConfig类的注册。- 只要
ServerAConfig被Spring容器注册为配置类,其内部定义的@ComponentScan就会自动执行,进而扫描到com.execute.server包下的MyServerA类完成注册,和你是否过滤额外声明的扫描逻辑无关。 - 部分场景下如果其他配置类通过
@Import引入了ServerAConfig,@ComponentScan的过滤规则也无法拦截这种显式导入的配置类。 - 若过滤规则拼写错误(比如类全限定名写错、正则规则错误),也会导致过滤失效,可以先替换为
FilterType.ASSIGNABLE_TYPE直接指定类对象,避免拼写问题。
解决方案
按照优先级从高到低选择以下方案即可:
方案1:将扫描规则统一配置到@SpringBootApplication中
删掉启动类上额外声明的@ComponentScan,所有扫描相关配置直接写到@SpringBootApplication注解属性中,示例配置如下:
@EnableMBeanExport @SpringBootApplication( scanBasePackages = "com.init", excludeFilters = @ComponentScan.Filter( type = FilterType.ASSIGNABLE_TYPE, classes = ServerAConfig.class ) ) public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }
该方案会直接覆盖@SpringBootApplication内置的扫描规则,excludeFilters会作用于全部扫描逻辑,确保ServerAConfig不会被注册。
方案2:关闭@SpringBootApplication默认扫描,单独使用自定义@ComponentScan
如果必须保留独立的@ComponentScan声明,先将@SpringBootApplication的扫描包置空,关闭内置默认扫描,避免规则叠加:
@EnableMBeanExport @SpringBootApplication(scanBasePackages = {}) @ComponentScan( basePackages = "com.init", excludeFilters = @ComponentScan.Filter( type = FilterType.ASSIGNABLE_TYPE, classes = ServerAConfig.class ) ) public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }
方案3:兜底兼容方案
如果上述方案仍然不生效(比如存在其他隐式导入ServerAConfig的逻辑),可以直接修改ServerAConfig类,增加条件注解控制其是否生效:
@Configuration @ComponentScan("com.execute.server") @ConditionalOnProperty(name = "servera.config.enabled", havingValue = "true", matchIfMissing = false) public class ServerAConfig { // 配置内容 }
然后在application.properties/application.yml中增加配置servera.config.enabled=false即可彻底禁用该配置类。
验证方法
启动后可通过以下代码验证配置是否生效:
public static void main(String[] args) { ApplicationContext ctx = SpringApplication.run(MyApplication.class, args); // 检查ServerAConfig是否被注册 System.out.println("ServerAConfig是否注册:" + ctx.containsBean("serverAConfig")); // 检查MyServerA是否被注册 System.out.println("MyServerA是否注册:" + ctx.containsBean("myServerA")); }
内容的提问来源于stack exchange,提问作者JaVa
相关产品推荐
相关产品推荐

