SpringBoot 无法识别多个 @ComponentScan 元注释
Posted
技术标签:
【中文标题】SpringBoot 无法识别多个 @ComponentScan 元注释【英文标题】:SpringBoot not recognizing multiple @ComponentScan meta-annotations 【发布时间】:2021-11-14 03:49:21 【问题描述】:我注意到 Spring 的 @ComponentScan
注释在用作元注释时存在问题。
在以下示例项目结构中,FirstHandler
和 SecondService
类都应作为组件进行扫描并注册为 bean:
org/example/
|_ ExampleContext.java
|___ api/
| |___ ExampleCommand.java
|___ application/
|___ FirstHandler.java
|___ SecondService.java
// --- ExampleContext.java ---
@ContextConfiguration
public class ExampleContext
// --- api/ExampleCommand.java ---
public class ExampleCommand extends Command
// -snip-
// --- application/FirstHandler.java ---
public class FirstHandler implements CommandHandler<ExampleCommand>
// -snip-
// --- application/SecondService.java ---
@CommandService
public class SecondService
@CommandMethod(ExampleCommand.class)
public void handle(ExampleCommand command)
// -snip-
Command
和相关类是自定义的,与手头的问题无关。出于这个问题的目的,它们充当标记并驻留在不依赖于 Spring 的模块中,因此不能对自身进行元注释。
自定义注释ContextConfiguration
应该扫描所有实现CommandHandler<C>
或使用CommandService
注释的类:
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Configuration
@ComponentScans(
// Scan for CommandHandler implementations
@ComponentScan(includeFilters =
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes =
CommandHandler.class,
)
),
// Scan for @CommandService annotated classes
@ComponentScan(includeFilters =
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes =
CommandService.class,
)
)
)
public @interface ContextConfiguration
但实际发生的是只使用了第一个@ComponentScan
注解,而第二个注解被简单地忽略了。
通过更改注释的顺序或删除一个,我可以更改哪个被忽略/激活,但 Spring 只扫描其中一个类。
这是一个已知问题吗? 有什么解决方案/变通办法吗?
谢谢你,祝你有美好的一天, 亚历克斯。
【问题讨论】:
注意:如果需要完整的项目示例,我可以创建一个公共 GitHub 示例项目,尽管这将比上面给出的示例更详细。 【参考方案1】:我找到了一种解决方法,它基本上重新实现了重复的@ComponentScan
注释应该 做的事情。
它受到this answer 的启发,并略微简化了实现。
要使用多个不同的组件扫描,可以在注释上导入实现ImportBeanDefinitionRegistrar
的嵌套配置。
例子:
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Configuration
@Import(ContextConfiguration.ScanContextComponents.class)
public @interface ContextConfiguration
class ScanContextComponents implements ImportBeanDefinitionRegistrar, EnvironmentAware
private Environment environment;
@Override
public void setEnvironment(Environment environment)
this.environment = environment;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingMetadata, BeanDefinitionRegistry registry)
String basePackage = ClassUtils.getPackageName(importingMetadata.getClassName());
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
// Add include-filters for different types here
provider.addIncludeFilter(new AssignableTypeFilter(CommandHandler.class));
provider.addIncludeFilter(new AnnotationTypeFilter(CommandService.class, true));
// Register bean-definition candidates
provider.setEnvironment(environment);
for (BeanDefinition beanDefinition : provider.findCandidateComponents(basePackage))
String beanName = AnnotationBeanNameGenerator.INSTANCE.generateBeanName(beanDefinition, registry);
registry.registerBeanDefinition(beanName, beanDefinition);
【讨论】:
以上是关于SpringBoot 无法识别多个 @ComponentScan 元注释的主要内容,如果未能解决你的问题,请参考以下文章
为啥我的 @Aspect 无法被我的 SpringBoot 应用程序识别?
SpringBoot 无法从多模块 Java 应用程序中的另一个模块识别 RestController
Spring Boot + Thymeleaf Security 无法识别