从@ComponentScan中排除@Component

yka*_*ich 76 java spring dependency-injection spring-ioc spring-boot

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

@Component("foo") class Foo {
...
}
Run Code Online (Sandbox Code Playgroud)

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

我试过用@ComponentScan.Filter:

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

但它似乎不起作用.如果我尝试使用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 {}
Run Code Online (Sandbox Code Playgroud)

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

我如何排除它?

Ser*_*mar 87

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

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


lub*_*nac 46

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

public @interface IgnoreDuringScan {
}
Run Code Online (Sandbox Code Playgroud)

标记应该用它排除的组件:

@Component("foo") 
@IgnoreDuringScan
class Foo {
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

@ComponentScan(excludeFilters = @Filter(IgnoreDuringScan.class))
public class MySpringConfiguration {}
Run Code Online (Sandbox Code Playgroud)

  • 对于通用排除而言,这是一个聪明的想法,但如果您想要仅从项目中的应用程序上下文的子集中排除组件,那么这将无济于事.真的,要普遍排除它,人们可以删除`@Component`,但我不认为这是问题的问题 (11认同)
  • 如果您在其他地方没有相同过滤器的其他组件扫描注释,则此方法将不起作用 (2认同)
  • @Bashar Ali Labadi,这不是这个结构的要点吗?如果您想将其从所有组件扫描中排除,它可能根本不应该是 Spring 组件。 (2认同)

lub*_*nac 23

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

@Component("foo")
@Conditional(FooCondition.class)
class Foo {
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

    return !context.getBeanFactory().containsBean(Bar.class.getSimpleName());
Run Code Online (Sandbox Code Playgroud)

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

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

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


Enr*_*rin 11

如果您需要定义两个或更多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) })
Run Code Online (Sandbox Code Playgroud)


dor*_*ony 8

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

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

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

@SpringBootApplication(exclude= {Foo.class})
public class MySpringConfiguration {}
Run Code Online (Sandbox Code Playgroud)

  • 我已经尝试过此操作,但显示错误为“无法排除以下类,因为它们不是自动配置类”。使用 @ComponentScan 的排除过滤器工作正常。 (4认同)
  • 这是错误的。`Foo` 只能是一个自动配置类。 (3认同)