103

我有一个要从@ComponentScan特定中排除的组件@Configuration

@Component("foo") class Foo {
...
}

否则,它似乎与我项目中的其他类发生冲突。我不完全理解碰撞,但如果我注释掉@Component注释,事情就会像我想要的那样工作。但是其他依赖这个库的项目希望这个类由 Spring 管理,所以我只想在我的项目中跳过它。

我尝试使用@ComponentScan.Filter

@Configuration 
@EnableSpringConfigured
@ComponentScan(basePackages = {"com.example"}, excludeFilters={
  @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=Foo.class)})
public class MySpringConfiguration {}

但它似乎不起作用。如果我尝试使用FilterType.ASSIGNABLE_TYPE,我会收到一个奇怪的错误,即无法加载一些看似随机的类:

原因:java.io.FileNotFoundException:类路径资源[junit/framework/TestCase.class]无法打开,因为它不存在

我也尝试使用type=FilterType.CUSTOM如下:

class ExcludeFooFilter implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader,
            MetadataReaderFactory metadataReaderFactory) throws IOException {
        return metadataReader.getClass() == Foo.class;
    }
}

@Configuration @EnableSpringConfigured
@ComponentScan(basePackages = {"com.example"}, excludeFilters={
  @ComponentScan.Filter(type=FilterType.CUSTOM, value=ExcludeFooFilter.class)})
public class MySpringConfiguration {}

但这似乎并没有像我想要的那样从扫描中排除组件。

我该如何排除它?

4

7 回答 7

126

配置似乎没问题,除了你应该使用excludeFilters而不是excludes

@Configuration @EnableSpringConfigured
@ComponentScan(basePackages = {"com.example"}, excludeFilters={
  @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=Foo.class)})
public class MySpringConfiguration {}
于 2013-09-24T22:39:12.503 回答
56

在扫描过滤器中使用显式类型对我来说很难看。我相信更优雅的方法是创建自己的标记注释:

@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoreDuringScan {
}

标记应与它一起排除的组件:

@Component("foo") 
@IgnoreDuringScan
class Foo {
    ...
}

并从您的组件扫描中排除此注释:

@ComponentScan(excludeFilters = @Filter(IgnoreDuringScan.class))
public class MySpringConfiguration {}
于 2014-12-07T16:06:24.257 回答
33

另一种方法是使用新的条件注释。从普通的 Spring 4 开始,您可以使用 @Conditional 注释:

@Component("foo")
@Conditional(FooCondition.class)
class Foo {
    ...
}

并定义注册 Foo 组件的条件逻辑:

public class FooCondition implements Condition{
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // return [your conditional logic]
    }     
}

条件逻辑可以基于上下文,因为您可以访问 bean 工厂。例如,当“Bar”组件未注册为 bean 时:

    return !context.getBeanFactory().containsBean(Bar.class.getSimpleName());

使用 Spring Boot(应该用于每个新的 Spring 项目),您可以使用这些条件注释:

  • @ConditionalOnBean
  • @ConditionalOnClass
  • @ConditionalOnExpression
  • @ConditionalOnJava
  • @ConditionalOnMissingBean
  • @ConditionalOnMissingClass
  • @ConditionalOnNotWebApplication
  • @ConditionalOnProperty
  • @ConditionalOnResource
  • @ConditionalOnWebApplication

您可以通过这种方式避免创建 Condition 类。有关更多详细信息,请参阅 Spring Boot 文档。

于 2014-12-06T16:11:04.913 回答
16

如果您需要定义两个或更多excludeFilters条件,则必须使用数组。

对于这部分代码中的实例,我想排除org.xxx.yyy包中的所有类和另一个特定类MyClassToExclude

 @ComponentScan(            
        excludeFilters = {
                @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.xxx.yyy.*"),
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = MyClassToExclude.class) })
于 2017-06-22T14:30:25.730 回答
7

我在尝试排除特定配置类时使用@Configuration@EnableAutoConfiguration@ComponentScan时遇到问题,问题是它不起作用!

最终我通过使用@SpringBootApplication解决了这个问题,根据 Spring 文档,它在一个注释中执行与上述三个相同的功能。

另一个提示是先尝试不改进包扫描(不使用 basePackages 过滤器)。

@SpringBootApplication(exclude= {Foo.class})
public class MySpringConfiguration {}
于 2017-07-09T14:54:06.500 回答
1

在排除测试组件或测试配置的情况下,Spring Boot 1.4 引入了新的测试注解@TestComponent@TestConfiguration.

于 2016-12-06T10:36:46.953 回答
0

我需要从应用程序上下文中排除审计@Aspect @Component,但仅适用于少数测试类。我最终在方面类上使用了 @Profile("audit") ;包括正常操作的配置文件,但在特定的测试类上不包括它(不要把它放在@Act​​iveProfiles 中)。

于 2018-07-12T05:10:08.753 回答