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.