从@ComponentScan中排除@Component


90

我有一个要从@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.ASSIGNABLE_TYPE, value=Foo.class)})
public class MySpringConfiguration {}

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

如何排除呢?

Answers:


107

配置看起来不错,除了您应该使用excludeFilters而不是excludes

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

抱歉,这是剪切和粘贴错误。我正在使用excludeFilters。我再
看一遍

52

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

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

标记应排除的组件:

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

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

@ComponentScan(excludeFilters = @Filter(IgnoreDuringScan.class))
public class MySpringConfiguration {}

13
这是通用排除的一个聪明主意,但是如果您只想从项目中的一部分应用程序环境中排除组件,那将无济于事。确实,要普遍排除它,可以删除@Component,但是我不认为这是问题所在
Kirby 2015年

2
如果您在另一个没有相同过滤器的地方进行了其他组件扫描注释,则此方法将不起作用
Bashar Ali Labadi

@Bashar Ali Labadi,这种结构不是这样吗?如果要从所有组件扫描中排除它,则可能根本不应该是Spring组件。
luboskrnac

30

另一种方法是使用新的条件注释。从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文档。


1
+1表示条件,对我而言,这比使用过滤器要干净得多。我从来没有像条件豆一样使过滤器能够像以前一样持续工作
wondergoat77

13

如果需要定义两个或多个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) })

我建议将ASPECTJ作为过滤器类型,因为此正则表达式还将匹配“ org.xxx.yyyy.z”
wutzebaer

9

我使用的时候有一个问题@Configuration@EnableAutoConfiguration@ComponentScan试图排除特定的配置类的事情是它没有工作!

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

另一个提示是先尝试而不完善您的程序包扫描(不使用basePackages筛选器)。

@SpringBootApplication(exclude= {Foo.class})
public class MySpringConfiguration {}

我已经尝试过,但是显示错误为“由于以下类不是自动配置类,因此无法排除”。使用@ComponentScan的excludeFilters可以正常工作。
AzarEJ


0

我需要从应用程序上下文中排除审核@Aspect @Component,但仅适用于一些测试类。我最终在方面类上使用@Profile(“ audit”); 包括用于正常操作的配置文件,但不包括特定测试类上的配置文件(不要将其放在@Act​​iveProfiles中)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.