Access properties file programmatically with Spring?

前端 未结 15 1616
说谎
说谎 2020-11-27 09:37

We use the code below to inject Spring beans with properties from a properties file.



        
相关标签:
15条回答
  • 2020-11-27 09:37

    If all you want to do is access placeholder value from code, there is the @Value annotation:

    @Value("${settings.some.property}")
    String someValue;
    

    To access placeholders From SPEL use this syntax:

    #('${settings.some.property}')
    

    To expose configuration to views that have SPEL turned off, one can use this trick:

    package com.my.app;
    
    import java.util.Collection;
    import java.util.Map;
    import java.util.Set;
    
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.BeanFactoryAware;
    import org.springframework.beans.factory.config.ConfigurableBeanFactory;
    import org.springframework.stereotype.Component;
    
    @Component
    public class PropertyPlaceholderExposer implements Map<String, String>, BeanFactoryAware {  
        ConfigurableBeanFactory beanFactory; 
    
        @Override
        public void setBeanFactory(BeanFactory beanFactory) {
            this.beanFactory = (ConfigurableBeanFactory) beanFactory;
        }
    
        protected String resolveProperty(String name) {
            String rv = beanFactory.resolveEmbeddedValue("${" + name + "}");
    
            return rv;
        }
    
        @Override
        public String get(Object key) {
            return resolveProperty(key.toString());
        }
    
        @Override
        public boolean containsKey(Object key) {
            try {
                resolveProperty(key.toString());
                return true;
            }
            catch(Exception e) {
                return false;
            }
        }
    
        @Override public boolean isEmpty() { return false; }
        @Override public Set<String> keySet() { throw new UnsupportedOperationException(); }
        @Override public Set<java.util.Map.Entry<String, String>> entrySet() { throw new UnsupportedOperationException(); }
        @Override public Collection<String> values() { throw new UnsupportedOperationException(); }
        @Override public int size() { throw new UnsupportedOperationException(); }
        @Override public boolean containsValue(Object value) { throw new UnsupportedOperationException(); }
        @Override public void clear() { throw new UnsupportedOperationException(); }
        @Override public String put(String key, String value) { throw new UnsupportedOperationException(); }
        @Override public String remove(Object key) { throw new UnsupportedOperationException(); }
        @Override public void putAll(Map<? extends String, ? extends String> t) { throw new UnsupportedOperationException(); }
    }
    

    And then use the exposer to expose properties to a view:

    <bean class="org.springframework.web.servlet.view.UrlBasedViewResolver" id="tilesViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.tiles2.TilesView"/>
        <property name="attributesMap">
            <map>
                <entry key="config">
                    <bean class="com.my.app.PropertyPlaceholderExposer" />
                </entry>
            </map>
        </property>
    </bean>
    

    Then in view, use the exposed properties like this:

    ${config['settings.some.property']}
    

    This solution has the advantage that you can rely on standard placeholder implementation injected by the context:property-placeholder tag.

    Now as a final note, if you really need a to capture all placeholder properties and their values, you have to pipe them through StringValueResolver to make sure that placeholders work inside the property values as expected. The following code will do that.

    package com.my.app;
    
    import java.util.Collection;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Properties;
    import java.util.Set;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
    import org.springframework.util.StringValueResolver;
    
    public class AppConfig extends PropertyPlaceholderConfigurer implements Map<String, String> {
    
        Map<String, String> props = new HashMap<String, String>();
    
        @Override
        protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
                throws BeansException {
    
            this.props.clear();
            for (Entry<Object, Object> e: props.entrySet())
                this.props.put(e.getKey().toString(), e.getValue().toString());
    
            super.processProperties(beanFactory, props);
        }
    
        @Override
        protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
                StringValueResolver valueResolver) {
    
            super.doProcessProperties(beanFactoryToProcess, valueResolver);
    
            for(Entry<String, String> e: props.entrySet())
                e.setValue(valueResolver.resolveStringValue(e.getValue()));
        }
    
        // Implement map interface to access stored properties
        @Override public Set<String> keySet() { return props.keySet(); }
        @Override public Set<java.util.Map.Entry<String, String>> entrySet() { return props.entrySet(); }
        @Override public Collection<String> values() { return props.values(); }
        @Override public int size() { return props.size(); }
        @Override public boolean isEmpty() { return props.isEmpty(); }
        @Override public boolean containsValue(Object value) { return props.containsValue(value); }
        @Override public boolean containsKey(Object key) { return props.containsKey(key); }
        @Override public String get(Object key) { return props.get(key); }
        @Override public void clear() { throw new UnsupportedOperationException(); }
        @Override public String put(String key, String value) { throw new UnsupportedOperationException(); }
        @Override public String remove(Object key) { throw new UnsupportedOperationException(); }
        @Override public void putAll(Map<? extends String, ? extends String> t) { throw new UnsupportedOperationException(); }
    }
    
    0 讨论(0)
  • 2020-11-27 09:37

    CREDIT: Programmatic access to properties in Spring without re-reading the properties file

    I've found a nice implementation of accessing the properties programmatically in spring without reloading the same properties that spring has already loaded. [Also, It is not required to hardcode the property file location in the source]

    With these changes, the code looks cleaner & more maintainable.

    The concept is pretty simple. Just extend the spring default property placeholder (PropertyPlaceholderConfigurer) and capture the properties it loads in the local variable

    public class SpringPropertiesUtil extends PropertyPlaceholderConfigurer {
    
        private static Map<String, String> propertiesMap;
        // Default as in PropertyPlaceholderConfigurer
        private int springSystemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK;
    
        @Override
        public void setSystemPropertiesMode(int systemPropertiesMode) {
            super.setSystemPropertiesMode(systemPropertiesMode);
            springSystemPropertiesMode = systemPropertiesMode;
        }
    
        @Override
        protected void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props) throws BeansException {
            super.processProperties(beanFactory, props);
    
            propertiesMap = new HashMap<String, String>();
            for (Object key : props.keySet()) {
                String keyStr = key.toString();
                String valueStr = resolvePlaceholder(keyStr, props, springSystemPropertiesMode);
                propertiesMap.put(keyStr, valueStr);
            }
        }
    
        public static String getProperty(String name) {
            return propertiesMap.get(name).toString();
        }
    
    }
    

    Usage Example

    SpringPropertiesUtil.getProperty("myProperty")
    

    Spring configuration changes

    <bean id="placeholderConfigMM" class="SpringPropertiesUtil">
        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE"/>
        <property name="locations">
        <list>
            <value>classpath:myproperties.properties</value>
        </list>
        </property>
    </bean>
    

    Hope this helps to solve the problems you have

    0 讨论(0)
  • 2020-11-27 09:37

    As you know the newer versions of Spring don't use the PropertyPlaceholderConfigurer and now use another nightmarish construct called PropertySourcesPlaceholderConfigurer. If you're trying to get resolved properties from code, and wish the Spring team gave us a way to do this a long time ago, then vote this post up! ... Because this is how you do it the new way:

    Subclass PropertySourcesPlaceholderConfigurer:

    public class SpringPropertyExposer extends PropertySourcesPlaceholderConfigurer {
    
        private ConfigurableListableBeanFactory factory;
    
        /**
         * Save off the bean factory so we can use it later to resolve properties
         */
        @Override
        protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
                final ConfigurablePropertyResolver propertyResolver) throws BeansException {
            super.processProperties(beanFactoryToProcess, propertyResolver);
    
            if (beanFactoryToProcess.hasEmbeddedValueResolver()) {
                logger.debug("Value resolver exists.");
                factory = beanFactoryToProcess;
            }
            else {
                logger.error("No existing embedded value resolver.");
            }
        }
    
        public String getProperty(String name) {
            Object propertyValue = factory.resolveEmbeddedValue(this.placeholderPrefix + name + this.placeholderSuffix);
            return propertyValue.toString();
        }
    }
    

    To use it, make sure to use your subclass in your @Configuration and save off a reference to it for later use.

    @Configuration
    @ComponentScan
    public class PropertiesConfig {
    
        public static SpringPropertyExposer commonEnvConfig;
    
        @Bean(name="commonConfig")
        public static PropertySourcesPlaceholderConfigurer commonConfig() throws IOException {
            commonEnvConfig = new SpringPropertyExposer(); //This is a subclass of the return type.
            PropertiesFactoryBean commonConfig = new PropertiesFactoryBean();
            commonConfig.setLocation(new ClassPathResource("META-INF/spring/config.properties"));
            try {
                commonConfig.afterPropertiesSet();
            }
            catch (IOException e) {
                e.printStackTrace();
                throw e;
            }
            commonEnvConfig.setProperties(commonConfig.getObject());
            return commonEnvConfig;
        }
    }
    

    Usage:

    Object value = PropertiesConfig.commonEnvConfig.getProperty("key.subkey");
    
    0 讨论(0)
  • 2020-11-27 09:42

    Please use the below code in your spring configuration file to load the file from class path of your application

     <context:property-placeholder
        ignore-unresolvable="true" ignore-resource-not-found="false" location="classpath:property-file-name" />
    
    0 讨论(0)
  • 2020-11-27 09:45

    This post also explatis howto access properties: http://maciej-miklas.blogspot.de/2013/07/spring-31-programmatic-access-to.html

    You can access properties loaded by spring property-placeholder over such spring bean:

    @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;
        }
    }
    
    0 讨论(0)
  • 2020-11-27 09:46

    This help me:

    ApplicationContextUtils.getApplicationContext().getEnvironment()
    
    0 讨论(0)
提交回复
热议问题