从 @ComponentScan 中排除 @Component
Posted
技术标签:
【中文标题】从 @ComponentScan 中排除 @Component【英文标题】:exclude @Component from @ComponentScan 【发布时间】:2013-09-30 08:01:36 【问题描述】:我有一个组件要从特定@Configuration
中的@ComponentScan
中排除:
@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
但这似乎并没有像我想要的那样从扫描中排除组件。
如何排除?
【问题讨论】:
【参考方案1】:配置看起来没问题,除了你应该使用excludeFilters
而不是excludes
:
@Configuration @EnableSpringConfigured
@ComponentScan(basePackages = "com.example", excludeFilters=
@ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, value=Foo.class))
public class MySpringConfiguration
【讨论】:
抱歉,这是一个剪切和粘贴错误。我正在使用排除过滤器。我再看一下,这给我的错误真的很奇怪...... 就我而言,FilterType.ASSIGNABLE_TYPE 不起作用 - 我认为它仅在您要排除的类也是@Configuration
类时才起作用。但是 FilterType.ASPECTJ 有效 - 特别是它甚至可以工作,例如对于单个类 - 不必引用包。此外,如果您的类层次结构中有多个@Configuration
类,则必须将排除过滤器应用于主@SpringBootApplication
类(这也是@Configuration
) - 否则它会进行组件扫描并设法在之前实例化类其他过滤器开始工作。【参考方案2】:
在扫描过滤器中使用显式类型对我来说很难看。我相信更优雅的方法是创建自己的标记注释:
@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoreDuringScan
标记应与它一起排除的组件:
@Component("foo")
@IgnoreDuringScan
class Foo
...
并从您的组件扫描中排除此注释:
@ComponentScan(excludeFilters = @Filter(IgnoreDuringScan.class))
public class MySpringConfiguration
【讨论】:
这是一个通用排除的聪明想法,但如果您只想从项目中的应用程序上下文的子集中排除组件,这将无济于事。真的,要普遍排除它,可以删除@Component
,但我认为这不是问题所在
如果您在某个地方有另一个组件扫描注释但没有相同的过滤器,这将不起作用
@Bashar Ali Labadi,这不是这个结构的重点吗?如果你想从所有组件扫描中排除它,它可能根本不应该是 Spring 组件。【参考方案3】:
另一种方法是使用新的条件注释。 从 plain 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 用于条件,这对我来说比使用过滤器更干净。我从来没有让过滤器像条件加载 bean 那样始终如一地工作【参考方案4】:如果您需要定义两个或多个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”【参考方案5】:在尝试排除特定配置类时,我在使用 @Configuration、@EnableAutoConfiguration 和 @ComponentScan 时遇到了问题,问题就是这样没用!
最终我通过使用@SpringBootApplication 解决了这个问题,根据 Spring 文档,它在一个注释中与上述三个功能相同。
另一个提示是先尝试不优化包扫描(不使用 basePackages 过滤器)。
@SpringBootApplication(exclude= Foo.class)
public class MySpringConfiguration
【讨论】:
我已经尝试过了,但显示错误为“无法排除以下类,因为它们不是自动配置类”。带有@ComponentScan 的 excludeFilters 工作正常。 这是错误的。Foo
只能是自动配置类。【参考方案6】:
在排除测试组件或测试配置的情况下,Spring Boot 1.4 引入了新的测试注解@TestComponent
and @TestConfiguration
。
【讨论】:
【参考方案7】:我需要从应用程序上下文中排除审计@Aspect @Component,但仅适用于少数测试类。我最终在方面类上使用了 @Profile("audit") ;包括用于正常操作的配置文件,但在特定测试类中排除它(不要放在@ActiveProfiles 中)。
【讨论】:
以上是关于从 @ComponentScan 中排除 @Component的主要内容,如果未能解决你的问题,请参考以下文章
spring boot增加@ComponentScan后就扫描不到其他包了
Spring注解驱动开发自定义TypeFilter指定@ComponentScan注解的过滤规则