Java 从@ComponentScan 中排除@Component

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18992880/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 13:10:01  来源:igfitidea点击:

exclude @Component from @ComponentScan

javaspringdependency-injectionspring-bootspring-ioc

提问by ykaganovich

I have a component that I want to exclude from a @ComponentScanin a particular @Configuration:

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

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

Otherwise, it seems to clash with some other class in my project. I don't fully understand the collision, but if I comment out the @Componentannotation, things work like I want them to. But other projects that rely on this library expect this class to be managed by Spring, so I want to skip it only in my project.

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

I tried using @ComponentScan.Filter:

我尝试使用@ComponentScan.Filter

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

but it doesn't appear to work. If I try using FilterType.ASSIGNABLE_TYPE, I get a strange error about being unable to load some seemingly random class:

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

Caused by: java.io.FileNotFoundException: class path resource [junit/framework/TestCase.class] cannot be opened because it does not exist

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

I also tried using type=FilterType.CUSTOMas following:

我也尝试使用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 {}

But that doesn't seem to exclude the component from the scan like I want.

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

How do I exclude it?

我如何排除它?

采纳答案by Sergi Almar

The configuration seem alright, except that you should use excludeFiltersinstead of excludes:

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

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

回答by luboskrnac

Another approach is to use new conditional annotations. Since plainSpring 4 you can use @Conditional annotation:

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

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

and define conditional logic for registering Foo component:

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

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

Conditional logic can be based on context, because you have access to bean factory. For Example when "Bar" component is not registered as bean:

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

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

With Spring Boot (should be used for EVERY new Spring project), you can use these conditional annotations:

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

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

You can avoid Condition class creation this way. Refer to Spring Boot docs for more detail.

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

回答by luboskrnac

Using explicit types in scan filters is ugly for me. I believe more elegant approach is to create own marker annotation:

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

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

Mark component that should be excluded with it:

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

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

And exclude this annotation from your component scan:

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

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

回答by luboskrnac

In case of excluding test component or test configuration, Spring Boot 1.4 introduced new testing annotations @TestComponentand @TestConfiguration.

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

回答by Enrico Giurin

In case you need to define two or more excludeFilterscriteria, you have to use the array.

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

For instances in this section of code I want to exclude all the classes in the org.xxx.yyypackage and another specific class, MyClassToExclude

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

 @ComponentScan(            
        excludeFilters = {
                @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.xxx.yyy.*"),
                @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = MyClassToExclude.class) })

回答by dorony

I had an issue when using @Configuration, @EnableAutoConfigurationand @ComponentScanwhile trying to exclude specific configuration classes, the thing is it didn't work!

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

Eventually I solved the problem by using @SpringBootApplication, which according to Spring documentation does the same functionality as the three above in one annotation.

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

Another Tip is to try first without refining your package scan (without the basePackages filter).

另一个提示是先尝试不优化包扫描(没有 basePackages 过滤器)。

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

回答by Miguel Pereira

I needed to exclude an auditing @Aspect @Component from the app context but only for a few test classes. I ended up using @Profile("audit") on the aspect class; including the profile for normal operations but excluding it (don't put it in @ActiveProfiles) on the specific test classes.

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