Как прочитать квалификатор из файла свойств при весенней загрузке? - PullRequest
0 голосов
/ 07 мая 2018

У меня есть классификатор, где я читаю с

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.

Но когда я делаю это, это выдает ошибку

Приложение не удалось запустить

Описание:

Поле userService в main.java.rest.TestController требует bean-компонента введите org.springframework.jdbc.core.JdbcTemplate ', который не найден.

Действие:

Рассмотрите возможность определения bean-компонента типа org.springframework.jdbc.core.JdbcTemplate в ваша конфигурация.

Любая помощь приветствуется.

Ответы [ 3 ]

0 голосов
/ 07 мая 2018

Если вы держите @Qualifier("jdbc"), Вы можете варьировать добавляемый компонент, предоставляя различные файлы конфигурации теста и загружая нужный файл для каждого класса тестирования.

0 голосов
/ 07 мая 2018

Поскольку @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
0 голосов
/ 07 мая 2018

Квалификатор не разрешает заполнитель. Вы можете написать свой 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);
    }
}
...