【问题标题】:How to read Qualifier from property file in spring boot?如何在 Spring Boot 中从属性文件中读取限定符?
【发布时间】:2018-10-16 21:28:20
【问题描述】:

我有一个从

读取的限定符
public class TestController{
     @Autowired
     @Qualifier("jdbc")
     private JdbcTemplate jtm;
     //.....
}

限定符“jdbc”是定义为的bean

@Bean(name = "jdbc")
@Autowired
public JdbcTemplate masterJdbcTemplate(@Qualifier("prod") DataSource prod) {
            return new JdbcTemplate(prod);
        }

这是返回该限定符的数据源并且工作正常。

现在我想从 application.properties 中读取限定符名称。所以我将代码更改为

public class TestController{
     @Autowired
     @Qualifier("${database.connector.name}")
     private JdbcTemplate jtm;
     //.....

}

database.connector.name=jdbc 在我的 application.properties 中的位置。

但是当我这样做时会抛出一个错误

应用程序启动失败

说明:

main.java.rest.TestController 中的字段 userService 需要一个 bean 键入找不到的“org.springframework.jdbc.core.JdbcTemplate”。

行动:

考虑定义一个类型为“org.springframework.jdbc.core.JdbcTemplate”的bean 你的配置。

感谢任何帮助。

【问题讨论】:

    标签: java spring-boot properties qualifiers


    【解决方案1】:

    限定符不解析占位符。您可以将TestController 类写为

    public class TestController {
    
        @Value("${database.connector.name}")
        private String name;
    
        private JdbcTemplate jtm;
    
        @Autowired
        public void setJdbcTemplate(ApplicationContext context) {
    
            jtm = (JdbcTemplate) context.getBean(name);
        }
    }
    

    【讨论】:

      【解决方案2】:

      正如@Hemant 已经提到的默认QualifierCandidateResolver 不解析属性。

      但你可以制作一个,它确实:

      import java.lang.annotation.Annotation;
      import org.springframework.beans.TypeConverter;
      import org.springframework.beans.factory.annotation.Qualifier;
      import org.springframework.beans.factory.annotation.QualifierAnnotationAutowireCandidateResolver;
      import org.springframework.beans.factory.config.BeanDefinitionHolder;
      import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
      import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
      import org.springframework.beans.factory.support.DefaultListableBeanFactory;
      import org.springframework.stereotype.Component;
      @Component
      public static class AutowireCandidateResolverConfigurer implements BeanFactoryPostProcessor {
          private static class EnvironmentAwareQualifierAnnotationAutowireCandidateResolver extends QualifierAnnotationAutowireCandidateResolver {
      
              private static class ResolvedQualifier implements Qualifier {
                  private final String value;
                  ResolvedQualifier(String value) { this.value = value; }
                  @Override
                  public String value() { return this.value; }
                  @Override
                  public Class<? extends Annotation> annotationType() { return Qualifier.class; }
              }
      
              @Override
              protected boolean checkQualifier(BeanDefinitionHolder bdHolder, Annotation annotation, TypeConverter typeConverter) {
                  if (annotation instanceof Qualifier) {
                      Qualifier qualifier = (Qualifier) annotation;
                      if (qualifier.value().startsWith("${") && qualifier.value().endsWith("}")) {
                          DefaultListableBeanFactory bf = (DefaultListableBeanFactory) this.getBeanFactory();
                          ResolvedQualifier resolvedQualifier = new ResolvedQualifier(bf.resolveEmbeddedValue(qualifier.value()));
                          return super.checkQualifier(bdHolder, resolvedQualifier, typeConverter);
                      }
                  }
                  return super.checkQualifier(bdHolder, annotation, typeConverter);
              }
          }
      
          public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
              DefaultListableBeanFactory bf = (DefaultListableBeanFactory) beanFactory;
              bf.setAutowireCandidateResolver(new EnvironmentAwareQualifierAnnotationAutowireCandidateResolver());
          }
      }
      

      这样你就可以使用@Qualifier,就像你问过@Qualifier("${database.connector.name}")一样

      完整示例:

      @SpringBootApplication
      public class SO50208018Application {
      
          public static void main(String[] args) { SpringApplication.run(SO50208018Application.class, args); }
      
          interface MyBean { }
          static class MyBeanImpl1 implements MyBean { }
          static class MyBeanImpl2 implements MyBean { }
      
          @Bean @Qualifier("impl1")
          MyBean bean1() { return new MyBeanImpl1(); }
      
          @Bean @Qualifier("impl2")
          MyBean bean2() { return new MyBeanImpl2(); }
      
      
          @Component
          public static class AutowireCandidateResolverConfigurer implements BeanFactoryPostProcessor {
              // configurer from above
          }
      
          @Bean
          CommandLineRunner run(@Qualifier("${spring.application.bean}") MyBean bean) {
              return (args) -> System.out.println(bean.getClass().getName());
          }
      }
      

      使用spring.application.bean=impl1 运行:

      com.stackoverflow.java.SO50208018Application$MyBeanImpl1
      

      使用spring.application.bean=impl2 运行:

      com.stackoverflow.java.SO50208018Application$MyBeanImpl2
      

      【讨论】:

        【解决方案3】:

        如果您保留@Qualifier("jdbc"), 您可以通过提供不同的测试配置文件并为每个测试类加载所需的配置文件来改变注入的 bean。

        【讨论】:

          猜你喜欢
          • 2019-01-11
          • 1970-01-01
          • 2020-04-27
          • 2016-04-29
          • 1970-01-01
          • 2018-09-28
          • 2019-07-23
          • 2018-10-27
          • 2020-07-01
          相关资源
          最近更新 更多