Подтвердить что ты не робот

Программный доступ к свойствам, созданным заполнитель свойств

Я читаю файл свойств, используя context:property-placeholder. Как я могу получить к ним доступ программно (@Value не работает - я не знаю названия свойств в момент разработки)?

Основная проблема заключается в том, что я не могу изменить файл applicationContext.xml, потому что он настроен на "родительскую" структуру

пс. Странно, но Environment.getProperty возвращает null

4b9b3361

Ответ 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;