Как заставить работать @Value или Environment в классе, реализующем интерфейсы Condition/ConfigurationCondition

Я работаю только с JavaConfig.

У меня есть следующее объявление:

@Bean
public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
}

это обязательно для JavaConfig в соответствии со следующим сообщением: Аннотация Spring 3.2 @value с чистой конфигурацией Java не работает, но работает Environment.getProperty

Следующий код работает отлично (многие @Values ​​в целях тестирования):

@Configuration
public class ActiveMQServerConfiguration {

    @Value("${localhost.address}")
    private String localHost;

    @Value("${remotehost.address}")
    private String remoteHost;

    @Value("${localhost.port}")
    private Integer localPort;

    @Value("${remotehost.port}")
    private Integer remotePort;

    @Bean(name="connectionFactory")
    @Conditional(LocalHostStatusCondition.class)
    public ActiveMQConnectionFactory localConnectionFactory(
            @Value("${localhost.protocol}") String protocol,
            @Value("${localhost.address}") String host,
            @Value("${localhost.port}") String port ){

        System.out.println("protocol: "+protocol);
        System.out.println("host: "+host);
        System.out.println("port: "+port);

        System.out.println("localHost: "+localHost);
        System.out.println("localPort: "+localPort);
        System.out.println("remoteHost: "+remoteHost);
        System.out.println("remotePort: "+remotePort);

я вижу в консоли/терминале

Альфа

protocol: tcp
host: 127.0.0.1
port: 61616
localHost: 127.0.0.1
localPort: 61616
remoteHost: 192.168.1.34
remotePort: 61616

Но следующее не работает так, как ожидалось:

public class LocalHostStatusCondition implements Condition {

    private static final Logger logger = LoggerFactory.getLogger(LocalHostStatusCondition.class);

    @Value("${localhost.address}")
    private String localHost;

    @Value("${remotehost.address}")
    private String remoteHost;

    @Value("${localhost.port}")
    private Integer localPort;

    @Value("${remotehost.port}")
    private Integer remotePort;

    @Autowired
    private Environment environment;

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        logger.info("LocalHostStatusCondition...");

        System.out.println("localHost: "+localHost);
        System.out.println("localPort: "+localPort);
        System.out.println("remoteHost: "+remoteHost);
        System.out.println("remotePort: "+remotePort);
        System.out.println("Env..." + environment.getProperty("localhost.address", String.class) );

Практически то же самое и даже работает с Environment

Результат:

Бета

localHost: null
localPort: null
remoteHost: null
remotePort: null
[WARNING] 
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:483)
    at org.codehaus.mojo.exec.ExecJavaMojo$1.run(ExecJavaMojo.java:293)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
    at com.manuel.jordan.infrastructure.support.LocalHostStatusCondition.matches(LocalHostStatusCondition.java:42)

Согласно Условию API:

Условия должны следовать тем же ограничениям, что и BeanFactoryPostProcessor, и никогда не взаимодействовать с экземплярами компонента. Для более детального управления условиями, взаимодействующими с bean-компонентами @Configuration, рассмотрите интерфейс ConfigurationCondition.

О ConfigurationCondition я прочитал это Когда использовать Spring @ ConfigurationCondition и @Condition? тоже

Я отредактировал следующее:

public class LocalHostStatusCondition implements ConfigurationCondition {

…

    @Override
    public ConfigurationPhase getConfigurationPhase() {
        return ConfigurationPhase.PARSE_CONFIGURATION;
    }

Если я использую:

  • ConfigurationPhase.REGISTER_BEAN Я получаю тот же вывод, что и бета-версия.
  • ConfigurationPhase.PARSE_CONFIGURATION; ошибок нет, но...

но консоль/терминал ничего не показывает о работе предложений, я имею в виду, что System.out не печатается (я не понимаю этого странного поведения).

Как я могу это решить?

Мне нужно иметь рабочее @Value или Environment, чтобы сообщить приложению, должно ли оно подключаться к локальному или удаленному серверу ActiveMQ.

И да, я прочитал следующее: Как мне отложить оценку аннотации конфигурации Spring @Conditional? кажется, что решения нет…

Спасибо


person Manuel Jordan    schedule 13.08.2014    source источник
comment
Меня немного смущает ваше использование Condition. Разве ваш LocalHostStatusCondition.matches() не должен оценивать какой-то условный оператор, чтобы вернуть логическое значение, чтобы определить, будет ли зарегистрирован ваш компонент конфигурации ActiveMQServerConfiguration? Зачем вашему классу LocalHostStatusCondition нужны все эти свойства подключения?   -  person ivan.sim    schedule 13.08.2014
comment
В любом случае, если вы читаете эти свойства из файла свойств, пробовали ли вы добавить @PropertySource("classpath:youfile.properties") в свой класс LocalHostStatusCondition?   -  person ivan.sim    schedule 13.08.2014
comment
@isim, да, LocalHostStatusCondition.matches() возвращает логическое значение. Я использую LocalHostStatusCondition для проверки двух подключений к серверу, одного локального и другого удаленного, поэтому мне нужен этот хост/порт. Если удаленный существует, он используется вместо локального.   -  person Manuel Jordan    schedule 13.08.2014
comment
@isim, даже если я включу @PropertySource("classpath:youfile.properties") в класс LocalHostStatusCondition на основе Condition/ConfigurationCondition, это не удастся ...   -  person Manuel Jordan    schedule 13.08.2014


Ответы (1)


У тебя есть

@Conditional(LocalHostStatusCondition.class)

Spring берет указанный вами тип Class и создает его экземпляр для использования его метода matches. Он не рассматривает экземпляр как bean-компонент, он не выполняет для него ни автоматического связывания, ни какой-либо @Value обработки. Последнее справедливо и для BeanFactoryPostProcessor.

Вы можете получить Environment из ConditionContext, если хотите. Альтернативой является загрузка свойств самостоятельно.

person Sotirios Delimanolis    schedule 13.08.2014