【问题标题】:Programmatic access to properties created by property-placeholder以编程方式访问由属性占位符创建的属性
【发布时间】:2012-07-10 01:42:14
【问题描述】:

我正在使用context:property-placeholder 读取属性文件。我如何以编程方式访问它们(@Value 不起作用 - 我在开发时不知道财产所有权)?

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

ps。这很奇怪,但Environment.getProperty 返回null

【问题讨论】:

标签: spring properties


【解决方案1】:

不,你不能。 PropertyPlaceholderConfigurerBeanFactoryPostProcessor,它仅在 bean 创建期间“活着”。当它遇到${property} 表示法时,它会尝试根据其内部属性来解决它,但它不会使这些属性对容器可用。

也就是说:类似的问题一次又一次地出现,建议的解决方案通常是to subclass PropertyPlaceHolderConfigurer 并手动将属性提供给上下文。或use a PropertiesFactoryBean

【讨论】:

  • 其实你可以通过编程方式从Spring env中访问属性没有问题 for (MutablePropertySource propertySource : env.getPropertySources()) { // PropertySource propertySource = (PropertySource) element; if (propertySource instanceof MapPropertySource) { mps = (MapPropertySource) propertySource;
  • @tom true,但是这个功能是在这个答案几年后引入的:-)
【解决方案2】:

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

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

然后,您可以使用限定符将属性自动装配到 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】:
    @Value
    

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

    1. 在 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" />
      
    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; }
      }
      

    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;
    

    【讨论】:

    • 这并没有回答上述问题。
    • 当前的 Mule ESB 3.7.3 运行时是否有效?我无法找到解决方案,它给了我一个错误,例如Failed to convert property value of type 'java.util.ArrayList' to required type 'java.util.List' for property 'messageProcessors'
    【解决方案4】:

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

    【讨论】:

      【解决方案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】:
        <util:properties id="prop" location="location of prop file" />
        

        这会返回 java.util.Properties 对象

        在 JAVA 代码中

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

        现在你可以访问了,

        prop.getProperty("key");
        

        【讨论】:

          【解决方案7】:

          在将属性放入属性占位符之前为您的属性创建 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")

          【讨论】:

            【解决方案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;
              

              【讨论】:

              • 在 Spring 4 中遇到错误:不支持对类型 'org.springframework.beans.factory.config.PropertyPlaceholderConfigurer' 的索引
              • 就像@SeanPatrickFloyd 评论的那样:“类似的问题一次又一次地出现,建议的解决方案通常是继承 PropertyPlaceHolderConfigurer 并手动使 Properties 可用于上下文。或者使用 PropertiesFactoryBean 。”希望对您有所帮助:Reading-valued-from-properties-file-at-Runtime
              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-07-07
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2023-01-10
              • 1970-01-01
              相关资源
              最近更新 更多