Spring Environment and Property Sources

0

Property placeholder

This post deals with how spring manages to resolve a placeholder ${property-name} to its actual value.

PropertyPlaceholder in location path

Our context file has a Foo bean and the file is located in a directory called springdemo. Instead of hardcoding the location path, we  will use a property placeholder and inject the actual location path externally.

<beans default-lazy-init="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean class="springdemo.Foo" id="foo">
</bean>

Since the sample context file is located in folder called springdemo, in order to load the context we just need to pass the location as springdemo/testFoo.xml to ClassPathXmlApplicationContext constructor.
But instead of hard coding the directory, we would like to use a placeholder called ${springProj} so that the directory can be fed externally. The test code below tries to load it but fails as we don’t have any property value set for the placeholder.

    public void testPlaceholderWithoutPropInEnv() {
        try {
            new ClassPathXmlApplicationContext("${springProj}/testFoo.xml");
            fail("should throw exception as we have not set springProj property to replace the placeholder");
        } catch (IllegalArgumentException e) {
        }
    }

Environment

There must be a way to feed in a source of properties which we can use to replace the placeholders with their actual value. These properties can come from one or more sources, like we have java based properties and the system environment properties. The properties and the profile, together, makes the spring Environment.How do we inject these properties, when should we do it or in other words, when should we create an Environment?

The Environment will help us resolve property values as we run through the creation of context so it must be available as soon as we instantiate the ApplicationContext.

In the below object diagram, we show that as we create ClassPathXmlApplicationContext, the super class AbstractApplicationContext automatically creates an environment.

Spring Environment and Property Sources
Create environment

Spring Environment and Property Sources

By default, the environment relies on the java system properties and the system environment properties, called StandardEnvironment.

But if we want to have a different version of Environment, one can easily do this by overriding createEnvironment().
If we only want add more property sources to the existing Environment, we can do that by overriding configurePropertySources(), like StandardEnvironment adds system properties and system environment to the property sources.

 

Spring Environment and Property Sources
Environment hierarchy

 

Let’s try to pass the failing scenario we had before. In the below test code, we set the property springProj.

    public void testPropertyResolver() {
        System.setProperty("springProj", "springdemo");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("${springProj}/testFoo.xml");
        Foo foo = (Foo) context.getBean("foo");
        assertNotNull(foo);
    }
The resolving algorithm is recursive so it can also take care of the embedded place holders, like the below one.
    public void testPropertyResolver() {
        System.setProperty("app", "spring");
        System.setProperty("springProj", "springdemo");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("${${app}Proj}/testFoo.xml");
        Foo foo = (Foo) context.getBean("foo");
        assertNotNull(foo);
    }

Property Source Examples

The below diagram shows the various property sources and the actual source that the object encapsulates.

Property Sources

Stub PropertySource

Why do we need a stub property source?
If the property source is not available during the creation of environment but will be available at a later point, we would be needing stub property sources. Following two points describe the scenarios related to stub property sources.
  • It allows us to set the intended default position/order of the property sources beforehand.
  • The stub property sources will be replaced by the actual ones when they are available.
For example, the servlet config and context properties. We would need stub property sources for servlet config and context during the creation of servlet environment so that the order is set.
Servlet config and context stub property source

In the below diagram, we show the order of property sources for a servlet environment. First the properties present in servletConfig will take precedence over those in servletContext, and

properties found in either of the above take precedence over those found in jndi.

Properties in any of the above will take precedence over system properties and environment variables.

Servlet Property sources
When the request is handled by Servlet, we get to access ServletConfig, this is when the stub property source is replaced by ServletConfig.
Replace of stub property source with the actual ones

Required Properties

If can also configure required properties during the creation of environment. In the below test case, we set springproj as a required property. Spring validates them as the context is created, since the property is not available in the environment, context creation fails.
    public void testValidateRequiredProperty() {
        try {
            new ClassPathXmlApplicationContext("springdemo/testFoo.xml") {
                protected ConfigurableEnvironment createEnvironment() {
                    ConfigurableEnvironment env = super.createEnvironment();
                    env.setRequiredProperties("springProj");
                    return env;
                }
            };
            fail("should have failed as required property is missing");
        } catch (MissingRequiredPropertiesException e) {
        }
    }

 

Share.

Leave A Reply