Wednesday, May 9, 2012

Custom PropertySource in Spring 3.1 - Part 3

This post is the third in a series of posts showing examples of registering a custom property source in Spring 3.1, where the property source requires non-trivial initialization of its own. Part 1 showed initialization of a stand-alone application, and Part 2 showed initialization of integration tests. This part will show how to initialize a custom property source in a Spring MVC web application.

Spring 3.1 introduced a very convenient hook for customizing the application context in a Spring web application - the ApplicationContextInitializer interface. An ApplicationContextInitializer can be used to set active profiles and register custom property sources, among other things.

Here is an example of an ApplicationContextInitializer that registers the RedisPropertySource introduced in Part 1.

Just like in the stand-alone example from Part 1, an ApplicationContext is created and initialized in order to wire up the components of the custom property source. This example uses the same property-source-context.xml configuration file from Part 1.

The ApplicationContextInitializer is registered with the Spring MVC servlet by adding a stanza to the web.xml file like this:

An alternative to adding the context-param stanza to web.xml is to implement a WebApplicationInitializer and add the ApplicationContextInitializer programmatically.

The JavaDoc for WebApplicationInitializer is a great source of documentation on programmatically configuring the servlet context. In this example, most of the servlet context configuration is in web.xml, showing that the two approaches can be combined.

The last interesting part of this example is a Controller to show the property placeholder values injected into the GreetingService from Part 1:

For the sake of simplicity, this example just returns a String without using a view. Like with the stand-alone example, the values returned from the GreetingService are resolved against a properties file included with the project. These default values can be overridden by setting operating system environment variables, setting Java command line options, or by starting a Redis server as described in Part 1.

The code for all three parts of this series is available in a runnable project in GitHub. The GitHub project also shows all the configuration using Java config in addition to the XML config shown here.

Tuesday, March 20, 2012

Custom PropertySource in Spring 3.1 - Part 2

A previous post described the process for registering a custom PropertySource in a Spring 3.1 application. Part 1 covered registering the custom PropertySource in a stand-alone Spring application. As part of building out an example, I also wanted to be able to test the custom PropertySource in a JUnit test case - the kind of test case you would write when doing integration testing.

In the stand-alone example, the important part of the code involved registering the custom PropertySource after an application context was created, but before the beans in the context are instantiated and their properties set (including the resolving of any property placeholders in property settings). Since the code in the stand-alone example is in full control of creating and setting up the application context, adding the custom PropertySource to the context was straight-forward.

Spring provides the TestContext framework to make setting up JUnit integration test cases fast and easy. With Spring 3.1, the TestContext framework was updated to support some of the major 3.1 themes such as Java configuration and Bean Profiles. Implementations of the ContextLoader interface are responsible for setting up the application context, and the @ContextConfiguration annotation applied to the test case class gives control over how the context is loaded. Since most of the work of setting up the application context is done by a ContextLoader implementation, it takes a bit more work to manipulate the context after it is created but before it is refreshed.

The trick to making this work is to leverage a hook that is implemented in one of the classes in the ContextLoader heirarchy - the customizeContext() method. By providing your own implementation of the ContextLoader and overriding the customizeContext() method, you get the chance to manipulate the context before it is refreshed.

The attributes used with the @ContextConfiguration annotation determine the subclass of AbstractGenericContextLoader that Spring uses to load the context. Here is an example of an integration test case that uses XML configuration:

The "loader" attribute of the @ContextConfiguration is the most important part of this test case. By default, using the "locations" attribute of @ContextConfiguration causes the Spring to load the application context using a GenericXmlContextLoader. The "loader" attribute is used to specify an application-specific subclass of GenericXmlContextLoader that overrides the customizeContext() method. Using the same RedisPropertySource implementation and XML configuration file from Part 1, this ContextLoader will instantiate and register the custom PropertySource into the application context:

That's it! As usual, Spring provides just enough extension points in the just right places to get the job done.

All the code listed here is available in a runnable project in GitHub. The GitHub project also shows all the configuration using Java config in addition to the XML config shown here.

Monday, March 12, 2012

Custom PropertySource in Spring 3.1 - Part 1

One of the improvements made to the Spring Framework in the 3.1 release is in the area of property placeholders. Chris Beams explains how the new unified property management system works in a blog posting on the SpringSource community site.

Several implementations of the new PropertySource interface are provided with the framework. PropertySource implementations backed by Java system properties and operating system environment variables are registered by default. If you specify one or more properties files using the <context:property-placeholder> tag in an XML configuration file or using the @PropertySource annotation on a Java config @Configuration class, the framework registers a PropertySource implementation backed by the specified files.

As Chris described, you can also register your own custom PropertySource implementations. This would be useful if you need bean properties to be stored in an external data source so they can be controlled outside of the application deployment process, or if you need properties to be encrypted or encoded for security reasons.

I decided to develop a custom PropertySource in a sample application. This PropertySource has some non-trivial bootstrapping of its own that needs to be done before it can be used, and Spring beans and dependency injection are used to bootstrap the PropertySource. The custom PropertySource must be instantiated, configured, and registered into to the application context containing the property placeholders before the application context is refreshed to make sure the property placeholders are resolved against the custom PropertySource.

To test this, I created a trivial bean with a few String properties:

and created a Spring XML config file named "app-context.xml" to instantiate the bean and set the properties:

When the GreetingService bean is instantiated, the Spring container will resolve the ${greeting.hello} and ${greeting.welcome} property placeholders and replace them with any specified text.

I then created a very simple Java main to bootstrap a Spring application context and show the properties injected into the bean:

With all this in place, I can run the GreetingApp class and play with setting the ${greeting.hello} and ${greeting.welcome} properties in environment variables, Java system properties, and properties files.

Next comes the custom PropertySource. I decided to use Redis as a backing store for configurable properties. Since Redis is a key-value store, it is a very natural fit for this example. I also decided to use Spring Data Redis to access the Redis data store. With Spring Data Redis, the code for the custom PropertySource was very simple. The PropertySource interface expects implementations to delegate to a "source" object to encapsulate the property values, so I created a RedisPropertySource which delegates to a RedisRepository. The RedisRepository in turn uses one of the RedisTemplate classes provided by Spring Data Redis.

Here is the code for the RedisPropertySource:

and the code for the RedisRepository:

Since the PropertySource bean and all related beans must be instantiated and wired together before the application beans can be instantiated, the PropertySource configuration goes in its own Spring XML config file named property-source-context.xml:

The application bootstrapping code is changed to instantiate the PropertySource bean and register it with the application's context:

The important thing to notice in this second version of the GreetingAppXmlConfig class is in the createAppContext() method. A second parameter is passed to the ClassPathXmlApplicationContext constructor to prevent the application context from being "refreshed" when it is created. This means the XML config file will be read and validated, but the beans defined in the context will not be created yet. The custom PropertySource is then registered with the application context, and the context is manually refreshed.

Of course, a Redis server has to be running and accessible before the GreetingApp main is run. The Redis command line client can be used to set and clear "greeting.hello" and "greeting.welcome" keys in the Redis server to test the RedisPropertySource. This example assumes the Redis server is running on "localhost" on the default port, but those values can be changed by setting properties of the JedisConnectionFactory bean in the property-source-context.xml file.

In the end, the code to make a custom RedisPropertySource work is very simple. The configuration and bootstrapping is also simple once the right sequence of events is understood.

I also worked on registering a custom PropertySource in a JUnit test case, which also took some figuring to get it right. Since this post has gotten pretty long, I'm going to continue that in a Part 2 post.

All the code listed here is available in a runnable project in GitHub. The GitHub project also shows all the configuration using Java config in addition to the XML config shown here.