Программный доступ к свойствам, созданным заполнитель свойств
Я читаю файл свойств, используя context:property-placeholder
. Как я могу получить к ним доступ программно (@Value
не работает - я не знаю названия свойств в момент разработки)?
Основная проблема заключается в том, что я не могу изменить файл applicationContext.xml
, потому что он настроен на "родительскую" структуру
пс. Странно, но Environment.getProperty
возвращает null
Ответы
Ответ 1
Нет, ты не можешь. PropertyPlaceholderConfigurer
- это BeanFactoryPostProcessor
, он только "жив" во время создания компонента. Когда он встречает нотацию ${property}
, он пытается сопоставить ее со своими внутренними свойствами, но не делает эти свойства доступными для контейнера.
Тем не менее, подобные вопросы появляются снова и снова, предлагаемое решение обычно состоит в том, чтобы создать подкласс PropertyPlaceHolderConfigurer
и сделать свойства доступными для контекста вручную. Или используйте PropertiesFactoryBean
Ответ 2
@Value
аннотация работает над новыми выпусками Spring (проверено на версии 3.2.2)
Вот как это делается:
-
Сопоставьте файл свойств в файле конфигурации Spring
<!--Import Info:
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd-->
<context:property-placeholder location="classpath:/app-config.properties" />
-
Создайте app-config.properties внутри (root) исходной папки
my.property=test
my.property2=test2
-
Создайте класс контроллера
@Controller
public class XRDSBuilder
{
@Value("${my.property}")
private String myProperty;
public String getMyProperty() { return myProperty; }
}
Spring автоматически сопоставляет содержимое my.property с вашей переменной внутри контроллера
Сопоставление со списком
Значение свойства:
my.list.property=test,test2,test3
Конфигурация класса контроллера:
@Value("#{'${my.list.property}'.split(',')}")
private List<String> myListProperty;
Расширенное сопоставление
@Component("PropertySplitter")
public class PropertySplitter {
/**
* Example: one.example.property = KEY1:VALUE1,KEY2:VALUE2
*/
public Map<String, String> map(String property) {
return this.map(property, ",");
}
/**
* Example: one.example.property = KEY1:VALUE1.1,VALUE1.2;KEY2:VALUE2.1,VALUE2.2
*/
public Map<String, List<String>> mapOfList(String property) {
Map<String, String> map = this.map(property, ";");
Map<String, List<String>> mapOfList = new HashMap<>();
for (Entry<String, String> entry : map.entrySet()) {
mapOfList.put(entry.getKey(), this.list(entry.getValue()));
}
return mapOfList;
}
/**
* Example: one.example.property = VALUE1,VALUE2,VALUE3,VALUE4
*/
public List<String> list(String property) {
return this.list(property, ",");
}
/**
* Example: one.example.property = VALUE1.1,VALUE1.2;VALUE2.1,VALUE2.2
*/
public List<List<String>> groupedList(String property) {
List<String> unGroupedList = this.list(property, ";");
List<List<String>> groupedList = new ArrayList<>();
for (String group : unGroupedList) {
groupedList.add(this.list(group));
}
return groupedList;
}
private List<String> list(String property, String splitter) {
return Splitter.on(splitter).omitEmptyStrings().trimResults().splitToList(property);
}
private Map<String, String> map(String property, String splitter) {
return Splitter.on(splitter).omitEmptyStrings().trimResults().withKeyValueSeparator(":").split(property);
}
}
Значение свойства:
my.complex.property=test1:value1,test2:value2
Класс контроллера:
@Value("#{PropertySplitter.map('${my.complex.property}')}")
Map<String, String> myComplexProperty;
Ответ 3
Мы используем следующий подход для доступа к свойствам для наших приложений
<util:properties id="appProperties" location="classpath:app-config.properties" />
<context:property-placeholder properties-ref="appProperties"/>
Тогда у вас есть роскошь просто свойств autowiring в beans с использованием квалификатора.
@Component
public class PropertyAccessBean {
private Properties properties;
@Autowired
@Qualifier("appProperties")
public void setProperties(Properties properties) {
this.properties = properties;
}
public void doSomething() {
String property = properties.getProperty("code.version");
}
}
Если у вас более сложные свойства, вы все равно можете использовать ignore-resource-not-found и игнорировать-unresolvable. Мы используем этот подход для экстернализации некоторых наших параметров приложения.
<util:properties id="appProperties" ignore-resource-not-found="true"
location="classpath:build.properties,classpath:application.properties,
file:/data/override.properties"/>
<context:property-placeholder ignore-unresolvable="true" properties-ref="appProperties"/>
Ответ 4
Spring следует за методом инверсии управления, это означает, что мы можем просто ввести конкретное свойство в POJO. Но есть некоторые случаи, когда вы хотели бы получить доступ к свойствам, указанным по имени, непосредственно из вашего кода - некоторые могут видеть его как анти-шаблон - это правдоподобно верно, но давайте сосредоточимся на том, как это сделать.
Ниже представлен PropertiesAccessor
доступ к свойствам, загруженным Property Placeholder
, и инкапсулирует содержимое контейнера. Он также кэширует найденные свойства, потому что вызов AbstractBeanFactory#resolveEmbeddedValue(String)
не является дешевым.
@Named
public class PropertiesAccessor {
private final AbstractBeanFactory beanFactory;
private final Map<String,String> cache = new ConcurrentHashMap<>();
@Inject
protected PropertiesAccessor(AbstractBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public String getProperty(String key) {
if(cache.containsKey(key)){
return cache.get(key);
}
String foundProp = null;
try {
foundProp = beanFactory.resolveEmbeddedValue("${" + key.trim() + "}");
cache.put(key,foundProp);
} catch (IllegalArgumentException ex) {
// ok - property was not found
}
return foundProp;
}
}
Ответ 5
Найденный ответ на сайте ниже:
http://forum.spring.io/forum/spring-projects/container/106180-programmatic-access-to-properties-defined-for-the-propertyplaceholderconfigurer
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" id="propertyConfigurer">
<property name="properties" ref="props" />
</bean>
<bean id="props" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="file:C:/CONFIG/settings.properties"/>
</bean>
Ответ 6
Создайте bean-компоненты для своих свойств, прежде чем помещать их в свойство-заполнитель, чтобы облегчить доступ к свойствам в коде.
Пример:
<bean id="configProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="resources" value="classpath:META-INF/spring/config.properties" />
</bean>
<context:property-placeholder properties-ref="configProperties" ignore-unresolvable="true"/>
Код:
@Autowired
private PropertiesFactoryBean configProperties;
Вы также можете использовать @Resource (name = "configProperties")
Ответ 7
<util:properties id="prop" location="location of prop file" />
Этот возвращаемый объект java.util.Properties
В коде JAVA
Properties prop = (Properties) context.getBean("prop");
Теперь вы можете получить доступ,
prop.getProperty("key");
Ответ 8
Это работает, если вам нужно сканировать несколько мест для ваших свойств...
<bean id="yourProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<array value-type="org.springframework.core.io.Resource">
<value>classpath:yourProperties.properties</value>
<value>file:../conf/yourProperties.properties</value>
<value>file:conf/yourProperties.properties</value>
<value>file:yourProperties.properties</value>
</array>
</property>
<property name="ignoreResourceNotFound" value="true" />
</bean>
<context:property-placeholder properties-ref="yourProperties" ignore-unresolvable="true"/>
А потом в ваших реальных классах...
@Autowired
Properties yourProperties;
Протестировано с использованием Spring 5.1.4
Ответ 9
Предположим, что вы создали файл свойств, определенный в этой "родительской" структуре
<bean id="applicationProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="location" value="classpath:main.properties" />
</bean>
Вы можете использовать аннотацию @Value следующим образом:
@Value( value = "#{applicationProperties['my.app.property']}" )
private String myProperty;