【问题标题】:Spring conditional component scan configurationSpring条件组件扫描配置
【发布时间】:2019-01-11 08:24:21
【问题描述】:

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

@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 之外,我还有组件扫描来扫描其他组件。当条件不满足时,我希望配置类中定义的 bean 不会被注册(恰好是这种情况),但我也希望其他类用 @Component(或@Repository@Service, etc..) 和DBConfigComponents.class 标记接口在同一文件夹中,不被注册,这不会发生。无论条件是否满足,被扫描的 Bean 都会被注册。

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

有什么建议吗?

【问题讨论】:

    标签: spring spring-boot spring-bean spring-config component-scan


    【解决方案1】:

    无需实现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”。

    【讨论】:

      【解决方案2】:

      实现这一点的最佳方法是不要使用 @Component / @Service 和 @Repository 注释来注释这些 bean。相反,您应该将这些作为您设置的配置的一部分返回,即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();
          }
      }
      

      注意:通常@Configuration@Conditional 用于您希望包含在Spring Boot 应用程序中的库中。此类库不应与您的 Spring Boot 应用程序共享相同的包。因此它们不应该被@ComponentScan 注释拾取。来自库的 Bean 不应使用 @Component / @Service / @Repository 注释进行注释。 Spring 建议为此使用 AutoConfiguration。见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

      【讨论】:

        【解决方案3】:

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

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

        【讨论】:

          猜你喜欢
          • 2015-01-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-02-16
          • 1970-01-01
          相关资源
          最近更新 更多