Spring Boot的ComponentScan excludeFilters无法排除。
Spring Boot的ComponentScan excludeFilters无法排除。
我有一个SimpleTest
:\n
@RunWith(SpringRunner.class) @SpringBootTest(classes = SimpleTestConfig.class) public class SimpleTest { @Test public void test() { assertThat(true); } }
\n和一个配置SimpleTestConfig
的测试:\n
@SpringBootApplication @ComponentScan(basePackageClasses = { SimpleTestConfig.class, Application.class }, excludeFilters = @ComponentScan.Filter( type = FilterType.ASSIGNABLE_TYPE, classes = Starter.class)) public class SimpleTestConfig { }
\n我试图排除Starter
类:\n
package application.starters; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; @Component public class Starter { @PostConstruct public void init(){ System.out.println("initializing"); } }
\n而Application
类如下所示:\n
package application; import org.springframework.boot.autoconfigure.SpringBootApplication; import static org.springframework.boot.SpringApplication.run; @SpringBootApplication public class Application { public static void main(String[] args) { run(Application.class, args); } }
\n但是出于某种奇怪的原因,Starter
类仍然被初始化。\n有谁能解释为什么ComponentScan excludeFilters
没有排除我的Starter
类吗?
在使用Spring Boot时,有时候我们需要排除某些组件或类不被自动扫描到。Spring Boot提供了@ComponentScan注解来控制组件的扫描范围,通过设置excludeFilters属性可以指定需要排除的组件。
然而,在一些情况下,excludeFilters属性可能无法正常工作,即使设置了过滤器也无法排除指定的组件。这个问题的出现可能是由于配置不正确或者其他未知原因导致的。
解决这个问题的方法是自定义组件扫描过滤器来排除指定的组件。通过设置excludeFilters属性的值为自定义的过滤器类型和正则表达式模式,可以实现对指定组件的排除。
以下是一个示例代码,展示了如何使用自定义过滤器来排除指定组件:
@ComponentScan(excludeFilters = { @ComponentScan.Filter(type = FilterType.REGEX, pattern = "com.wyn.applications.starter.Starter*") }) public class SimpleTestConfig { }
在这个示例中,我们使用了正则表达式过滤器(FilterType.REGEX)来匹配以"com.wyn.applications.starter.Starter"开头的类名,并将其排除在组件扫描范围之外。
通过这种方式,我们可以自定义排除指定组件的规则,从而解决Spring Boot中@ComponentScan excludeFilters属性无法正常工作的问题。
如果想进一步了解更多关于Spring Boot中组件扫描的内容,可以参考这篇博客文章。
问题出现的原因是每个组件扫描都是独立进行过滤的。尽管在SimpleTestConfig
中排除了Starter.class
,但SimpleTestConfig
初始化了Application
,它会进行自己的扫描而不排除Starter
。
解决方法是使用ComponentScan的正确方式是为每个ComponentScan扫描不同的包,这样每个过滤器都能正常工作。当两个独立的ComponentScan扫描相同的包(如你的测试中)时,这种方法不起作用。
一个欺骗的方法是提供一个模拟的Starter
bean:
import org.springframework.boot.test.mock.mockito.MockBean; public class SimpleTest { private Starter myTestBean; ... }
Spring将使用该模拟类而不是真正的类,这样componentScan
方法就不会被调用。
其他常见的解决方法包括:
- 在任何单元测试中不直接使用Application.class
- 在Starter
类上使用Spring profile和注解,如@Profile("!TEST")
- 在Starter
类上使用Spring Boot的@ComponentScan
注解
感谢您的回答,但如果是这样的话,Spring为什么设计了过滤器?它的目的是什么?
过滤器的目的是为了让您灵活地使用。当一个testConfig进行组件扫描时,可以排除另一个配置,而该配置对相似的包进行了自己的组件扫描(就像你的情况中的Application一样),这时过滤器就非常有用。
另一个选项是使用@ComponentScan.Filter
注解,详情请参考:stackoverflow.com/a/59815772/355438。请随意修改我的答案以包含该选项。