Spring条件成分扫描配置

Spring conditional component scan configuration

我有一个配置 class,它根据一个非常简单的条件注册 bean(检查 application.properties 中的 属性 值)。配置class和条件如下:

@Configuration
@Conditional(DatabaseConfigurationCondition.class)
@ComponentScan(basePackageClasses = DBConfigComponents.class)
public class DatabaseConfigurationLoader {
    @Bean
    public DatabaseConfigurationRepository databaseConfigurationRepository() {
      return new DatabaseConfigurationRepository();
    }
}

public class DatabaseConfigurationCondition implements Condition {
  @Override
  public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
    return conditionContext.getEnvironment().getProperty("configuration.type").contains("db");
  }
}

除了在此配置中注册的 bean class 我还有组件扫描,用于扫描其他组件。当不满足条件时,我希望在配置 class 中定义的 bean 不被注册(这恰好是一种情况),但我也希望其他 classes 注释为@Component(或@Repository@Service,等等)并且与DBConfigComponents.class标记接口在同一个文件夹中不被注册,这不会发生。被扫描的 Bean 总是被注册,无论是否满足条件。

当我将 @Conditional(DatabaseConfigurationCondition.class) 放在每个 @Component 注释 class 上时,它工作正常,但我不想将它分别放在每个 class 上.

有什么建议吗?

无需实现Condition接口,需要使用'@ConditionalOnProperty'注解:

@Configuration
@ComponentScan(basePackageClasses = DBConfigComponents.class)
@ConditionalOnProperty(name = "configuration.type", havingValue = "db")
public class DatabaseConfigurationLoader {
    @Bean
    public DatabaseConfigurationRepository databaseConfigurationRepository() {
      return new DatabaseConfigurationRepository();
    }
}

您可以根据需要使用 'prefix' 而不是 'havingValue'。

实现此目的的最佳方法是不要 使用@Component / @Service 和@Repository 注释来注释这些bean。相反,您应该 return 这些作为您设置的配置的一部分,即 DatabaseConfigurationLoader。请参阅下面的示例。

@Configuration
@Conditional(DatabaseConfigurationCondition.class)
public class DatabaseConfigurationLoader {
    @Bean
    public DatabaseConfigurationRepository databaseConfigurationRepository() {
        return new DatabaseConfigurationRepository();
    }

    @Bean
    public SomeService someService() {
        return new SomeService();
    }

    @Bean
    public SomeComponent someComponent() {
        return new SomeComponent();
    }
}

Note: Typically @Configuration with @Conditional are used in libraries that you want to include in your spring boot application. Such libraries should not share the same package as your spring boot application. Thus they should not be picked up by @ComponentScan annotation. Beans from libraries should not be annotated with @Component / @Service / @Repository annotations. Spring suggests using AutoConfiguration for that. See https://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-auto-configuration.html & https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html

幸运的是,我设法解决了这个问题。我的问题是我在其他 Maven 模块的其他配置 class 中放置了另一个 @ComponentScan 注释 - 不以任何 属性 为条件。与 DBConfigComponents 标记接口在同一包中的组件实际上被另一个配置 class 扫描。

@ComponentScan 的工作方式是在包级别。虽然,在不同的 Maven 模块中,两个配置 classes 都在同一个包中。 @ComponentScan@Conditional 完美配合。不需要 @Conditional 分别放在每个组件上。