以编程方式访问property-placeholder创建的属性

时间:2012-07-10 14:36:36

标签: spring properties

我正在使用context:property-placeholder阅读属性文件。我如何访问它们以编程方式@Value不起作用 - 我在开发时不知道属性标题?)

主要问题是我无法更改applicationContext.xml文件,因为它是由“父”框架设置的

PS。这很奇怪但是Environment.getProperty会返回null

9 个答案:

答案 0 :(得分:35)

不,你不能。 PropertyPlaceholderConfigurerBeanFactoryPostProcessor,它在bean创建过程中只是“活着”。当遇到${property}表示法时,它会尝试针对其内部属性解析该问题,但它不会使容器可以使用这些属性。

那就是说:类似的问题一再出现,建议的解决方案通常是to subclass PropertyPlaceHolderConfigurer,并且可以手动将属性用于上下文。或use a PropertiesFactoryBean

答案 1 :(得分:9)

@Value

注释适用于Spring的新版本(在v3.2.2上测试) 以下是它的完成方式:

  1. 在弹簧配置文件

    中映射属性文件
    <!--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" />
    
  2. 在源文件夹中创建app-config.properties

    my.property=test
    my.property2=test2
    
  3. 创建控制器类

    @Controller
    public class XRDSBuilder
    {
        @Value("${my.property}")
        private String myProperty;
    
        public String getMyProperty() { return myProperty; }
    }
    
  4. Spring会自动将my.property的内容映射到控制器内的变量

    Mapping to a list

    财产价值:

    my.list.property=test,test2,test3
    

    控制器类配置:

    @Value("#{'${my.list.property}'.split(',')}")
    private List<String> myListProperty;
    

    Advanced mapping

    @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;
    

答案 2 :(得分:8)

我们使用以下方法访问应用程序的属性

<util:properties id="appProperties" location="classpath:app-config.properties" />
<context:property-placeholder properties-ref="appProperties"/>

然后,您可以使用限定符将bean自动装配到bean中。

@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和ignore-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"/>

答案 3 :(得分:5)

Spring遵循Inversion Of Control方法,这意味着我们可以简单地将特定属性注入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; 
    } 
}

答案 4 :(得分:2)

在以下网站找到答案:

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>

答案 5 :(得分:0)

在将属性置于属性占位符之前为属性创建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 =&#34; configProperties&#34;)

答案 6 :(得分:0)

<util:properties id="prop" location="location of prop file" />

这将返回java.util.Properties对象

使用JAVA代码

Properties prop = (Properties) context.getBean("prop");

现在您可以访问,

prop.getProperty("key");

答案 7 :(得分:0)

如果您需要扫描多个位置的属性,则可以使用此功能...

<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进行测试

答案 8 :(得分:-1)

让我们假设您在“父”框架中定义的属性文件

<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;