Access properties file programmatically with Spring?

Viewed 295733

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

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations" value="classpath:/my.properties"/>
</bean>

<bean id="blah" class="abc">
    <property name="path" value="${the.path}"/>
</bean>

Is there a way we can access the properties programmatically? I'm trying to do some code without dependency injection. So I'd like to just have some code like this:

PropertyPlaceholderConfigurer props = new PropertyPlaceholderConfigurer();
props.load("classpath:/my.properties");
props.get("path");
16 Answers

You can get your properties through Environment class. As documentation stands:

Properties play an important role in almost all applications, and may originate from a variety of sources: properties files, JVM system properties, system environment variables, JNDI, servlet context parameters, ad-hoc Properties objects, Maps, and so on. The role of the environment object with relation to properties is to provide the user with a convenient service interface for configuring property sources and resolving properties from them.

Having Environment as a env variable, simply call:

env.resolvePlaceholders("${your-property:default-value}")

You can get your 'raw' properties through:

env.getProperty("your-property")

It will search through all properties source that spring has registered.

You can either obtain Environment through:

  • inject ApplicationContext by implementing ApplicationContextAware and then call getEnvironment() on context
  • implement EnvironmentAware.

It's obtain through implementation of a class because properties are resolved on early stage of application startup, as they may be required for bean construction.

Read more on documentation: spring Environment documentation

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

This help me:

ApplicationContextUtils.getApplicationContext().getEnvironment()

This is the finest way I got it to work:

package your.package;

import java.io.IOException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;

public class ApplicationProperties {

    private Properties properties;

    public ApplicationProperties() {
        // application.properties located at src/main/resource
        Resource resource = new ClassPathResource("/application.properties");
        try {
            this.properties = PropertiesLoaderUtils.loadProperties(resource);
        } catch (IOException ex) {
            Logger.getLogger(ApplicationProperties.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public String getProperty(String propertyName) {
        return this.properties.getProperty(propertyName);
    }
}
create .properties file in classpath of your project and add path configuration in xml`<context:property-placeholder location="classpath*:/*.properties" />`

in servlet-context.xml after that u can directly use your file everywhere

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" />

I know this is an old thread, however, this topic in my opinion becomes of great importance for those using the functional approach for all those usecases where you need a microservice that loads "instantly" and therefore you avoid using annotations. The problem that remained unsolved was to load eventually the environment variables which I had in my application.yml.

public class AppPropsLoader {
public static Properties load() {
  var propPholderConfig = new PropertySourcesPlaceHolderConfigurer();
  var yaml = new YamlPropertiesFactoryBean();
  ClassPathResource resource = new ClassPathResource("application.yml");
  Objects.requireNonNull(resource, "File application.yml does not exist");
  yaml.setResources(resource);
  Objects.requireNonNull(yaml.getObject(), "Configuration cannot be null");
  propPholderConfig.postProcessBeanFactory(new DefaultListableBeanFactory());
  propPholderConfig.setProperties(yaml.getObject());
  PropertySources appliedPropertySources = 
  propPholderConfig.getAppliedPropertySources();
  var resolver = new PropertySourcesPlaceholderResolver(appliedPropertySources);
  Properties resolvedProps = new Properties();
  for (Map.Entry<Object, Object> prop: yaml.getObject().entrySet()) {
    resolvedProps.setProperty((String)prop.getKey(), 
      getPropertyValue(resolver.resolvePlaceHolders(prop.getValue()));
  }
  return resolvedProps;
}
 static String getPropertyValue(Object prop) {
   var val = String.valueOf(prop);
   Pattern p = Pattern.compile("^(\\$\\{)([a-zA-Z0-9-._]+)(\\})$");
   Matcher m = p.matcher(val);
   if(m.matches()) {
    return System.getEnv(m.group(2));
  }
   return val;
 }
}
Related