Spring @Файл конфигурации с PropertyPlaceholderConfigurer bean не разрешает аннотацию @Value
У меня есть следующий файл конфигурации:
@Configuration
public class PropertyPlaceholderConfigurerConfig {
@Value("${property:defaultValue}")
private String property;
@Bean
public static PropertyPlaceholderConfigurer ppc() throws IOException {
PropertyPlaceholderConfigurer ppc = new PropertyPlaceholderConfigurer();
ppc.setLocations(new ClassPathResource("properties/" + property + ".properties"));
ppc.setIgnoreUnresolvablePlaceholders(true);
return ppc;
}
}
Я запускаю свое приложение со следующей опцией VM:
-Dproperty=propertyValue
Поэтому я хочу, чтобы мое приложение загрузило определенный файл свойств при запуске. Но почему-то на этом этапе аннотации @Value
не обрабатываются, а свойство null
. С другой стороны, если у меня PropertyPlaceholderConfigurer
настроено через xml файл - все работает отлично, как ожидалось. Пример файла XML:
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="ignoreResourceNotFound" value="true"/>
<property name="location">
<value>classpath:properties/${property:defaultValue}.properties</value>
</property>
</bean>
Если я попытаюсь ввести значение свойства в другой файл конфигурации Spring - он правильно вставляется. Если я переношу мое создание PropertyPlaceholderConfigurer
bean в этот файл конфигурации - значение поля снова равно null.
Как обходной путь, я использую эту строку кода:
System.getProperties().getProperty("property", "defaultValue")
Это тоже работает, но я хотел бы знать, почему такое поведение происходит, и, возможно, его можно переписать другим способом, но без xml?
Ответы
Ответ 1
Из Spring JavaDoc:
Чтобы разрешить ${...} заполнители в определениях или аннотации @Value с использованием свойств из PropertySource, необходимо зарегистрировать PropertySourcesPlaceholderConfigurer. Это происходит автоматически при использовании в XML, но должно быть явно зарегистрировано с использованием статического метода @ Bean при использовании классов @Configuration. См. Раздел "Работа с внешними значениями" в разделе @Configuration javadoc и "примечание о методах BeanFactoryPostProcessor-return @Bean" @Bean javadoc для подробностей и примеров.
Итак, вы пытаетесь использовать местозаполнитель в блоке кода, требуемый для включения обработки заполнителя.
Как упоминалось в @M.Deinum, вы должны использовать PropertySource (стандартная или пользовательская реализация).
Пример ниже показывает, как использовать свойства в аннотации PropertySource, а также как вводить свойства из PropertySource в поле.
@Configuration
@PropertySource(
value={"classpath:properties/${property:defaultValue}.properties"},
ignoreResourceNotFound = true)
public class ConfigExample {
@Value("${propertyNameFromFile:defaultValue}")
String propertyToBeInjected;
/**
* Property placeholder configurer needed to process @Value annotations
*/
@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Ответ 2
Для любых других бедных душ, которые не могли заставить это работать в некоторых классах конфигурации, когда они работают в других:
Посмотрите, что у вас есть в этом классе beans, и если какой-либо из них получит экземпляр в начале ApplicationContext. Пример ConversionService - один из примеров. Это создаст экземпляр класса Configuration до того, как будет зарегистрировано требуемое значение, тем самым не произойдет никакого вливания свойств.
Я исправил это, переместив ConversionService в другой класс конфигурации, который я импортировал.
Ответ 3
Если вы запустите приложение с помощью опции VM, а затем хотите получить доступ к этому параметру в своем приложении, вы должны сделать это несколько иначе:
@Value("#{systemProperties.property}")
private String property;
Свойству PropertyPlaceholderConfigurer не известно о свойствах системы, также обратите внимание, что вы получаете доступ к свойствам с помощью $
- который относится к держателям мест, а #
относится к beans, где systemProperties
- bean.