Kaare Nilsen

Syndicate content
Updated: 55 min 28 sec ago

Staged Spring Context project has found a home

Thu, 2008-04-10 18:08

I have gotten some positive feedbacks on the project, which I very much appreciate, and found myself in need for a place where people could read documentation and files issues. So I have created a redmine instance on my machine where you could do just that. http://projects.kaare-nilsen.com/projects/show/1

One important thing to mention is that I have changed from using Subversion to using mercurial as source control management, and the new url for the source code is now https://hg.kaare-nilsen.com/staged-spring

Categories: Tech

AspectJ maven plugin 1.0 released

Mon, 2008-04-07 21:38

I am happy to announce the release of the AspectJ plugin version 1.0 for Maven 2.

This release provides:

  • AspectJ 1.5.4 compiler support for Maven2
  • Generating LTW descriptors
  • Ajdoc reports for Maven 2

For instructions on how to use the plugin, refer to it’s web site at: http://mojo.codehaus.org/aspectj-maven-plugin

Categories: Tech

Stage aware spring contexts part II

Sun, 2008-04-06 22:37

As we have seen in the previous post with the @Stage annotation or the StagedSingletonFactoryBean, you can by using them choose between different implementation of Spring bean at runtime. But sometimes it is not the implementation you would like to switch between but the internal configuration of a particular class.

To support this, we have the StagedProperties class. It is a class in where you can register multiple property files used for looking up staged values for a given property key using stage as a prefix to separate values.

Property file layout

Each property file may have several entries for one key each prefixed by the stage it should apply. If no value found for the stage we are running in, it falls back on the key with no prefix. As shown in the following example

#
# myApp properties
#
myKey=default value
development.myKey=development value
test.myKey=test value
production.myKey=production value
custom.myKey=custom value

You are also allowed to use keys in the values, and it will be resolved and replaced with the value of the corresponding key as shown here :

#
# myApp properties
#
baseUrl=http://localhost
development.baseUrl=http://dev.arktekk.no
test.baseUrl=http://test.arktekk.no
production.baseUrl=http://arktekk.no

customerServiceEndpoint=${baseUrl}/services/customerService
orderServiceEndpoint=${baseUrl}/services/mockCustomerService

Configuring and using staged properties in Java


StagedProperties properties
  = new StagedProperties("myProperties.properties");
String myValue = properties.getProperty("myKey");

There are also constructors taking a list of property files, or you may use the registerPropertiesmethod to register more files. The StagedProperties class uses Spring resource loader to load the property files so you can use all the Spring supported urls, as e.g. classpath:myProperties.properties.

Use in Spring beans

In my opinion I do like spring beans that tries to configure them selves as much as possible. I think there are way to much use of Spring configuration files to configure ordinary properties like database url’s, service end points and so on. So what I would prefer is that we configure a StagedProperties bean in Spring, and then use the Spring autowiring support to get it injected unto other spring beans, and then use the InitializingBean inteface or the new support for the @PostConstruct annotation In this way we only need to configure our spring beans, in the case that the default values does not work in our application. This is best explained in the 2 part example below.

Configuring the StagedProperties bean

First we need to configure our properties in Spring by adding this xml snippet

<bean id="stagedProperties"
     class="no.arktekk.stagedspring.properties.StagedProperties">
  <property name="propertyFiles">
    <list>
      <value>no/arktekk/stagedspring/properties/test1.properties</value>
    </list>
  </property>
</bean>

Using in beans

Then it is time to get it injected, and utilized in a spring bean

public class SpringBean {
  @Autowired private StagedProperties properties;

    @PostConstruct
    public void initProperties() throws Exception {
      band = properties.getProperty("aCoolBand", "Mothers of invention");
    }

Note by using afterPropertiesSet or @PostConstruct this will override any configuration done in Spring configuration files, and the only way to change the values is by using the property files

Overriding properties

StagedProperties uses an ArrayList internally and, in the case of multiple files are registered, you are allowed to use a key in several files. When the StagedProperties class encounters several keys that match, it will always use the key registered last in the class. You may also register a file that does not yet exists, and it will be picked by the refresh mechanism.

Refreshing of property files

When a StagedProperties class is added to a Spring context, it will start a refresh thread, that runs on the schedule defined in the property refreshIntervalInSecods. The default here is 60 seconds. If you are constructing the class yourself you will need to start the refresh mechanism manually by invoking the startRefreshingCache method.

Configuring Spring beans with placeholders

In addition, those of you familiar with Spring probably know the PropertyPlaceHolderConfigurer that Spring ships with. To be able to use this kind of configuration and use stages this project provide a StagedPropertyPlaceHolderConfigurer class that are able to use the StagedProperties class to resolve the values. This functionality is best shown with an example

<bean id="stagedProperties"
     class="no.arktekk.stagedspring.properties.StagedProperties">
  <property name="propertyFiles">
    <list>
      <value>myProperties.properties</value>
    </list>
  </property>
</bean>

<bean id="placeHolderConfigurer"
     class="no.arktekk.stagedspring.properties.StagedPropertyPlaceholderConfigurer">
  <property name="stagedProperties" ref="stagedProperties" />
</bean>

<bean id="testBean" class="..TestBean">
  <property name="url" value="${aCoolUrl}" />
</bean>

of course the stagedProperties property is marked with the @Autowired annotation so the ref shown above is optional

For more information

Please check out the latest version of the code at staged-spring and run the mvn site:site command for more detailed documentation.

Categories: Tech

Stage aware spring contexts

Wed, 2008-04-02 21:34

The Spring framework has in our parts of the world become the kind of de-facto standard for almost all enterprise Java pplications. There are close to zero projects starting up in the Oslo area not using it. In my role as consultant and Spring Instructor I have over the years seen my share of Spring based projects, and one of the discussions that I see in these
projects are how should we configure our Spring applications ?

Well of course there are no one answer to that question, and the options we have when we use Spring are many, and sufficient for most use cases. But there is one use case that too often have been a kind of pain in the….

How do we manage configurations in various stages of development?

Let us say that we are going to use one implementation of a interface when we are developing our application, and another one in production. Let us say for e.g. mocking purposes. How should we configure our application to support that.

There is always the option of having your build system do it for you with ant filters, or Maven resource filtering. But hey. That often require us to build the application one time for each environment.

Then we have PropertyPlaceholderConfigurer. It is a very little know fact, that it also can be used to select bean classes using property files. But again. We would need one property file for each stage, and it can be somewhat difficult to make sure the correct one is used.

Also we have the option of having more bean xml files. one for tests, one for development and then include the right one, but that gives us the hassle of keeping them in sync.

I have also tried using special factory beans to solve this, but that gave me quite large xml files.

And there is another common complaint
There are way to much xml when using Spring!

To the rescue

In Spring 2.5 they introduced autodetection of components in the classpath by scanning for annotated classes. The annotation used for detecting components are called stereotypes, and Spring ships with the follwing out of the box :

  • @Component
  • @Service
  • @Controller
  • @Component

What the component scanner does, is looking for these stereotypes, and registers the classes as beans in the running Spring container. By default it uses the class name as bean id e.g. the class DevelopmentEnvironmentService annotated with the @Service annotation would be registered as a bean with the id developmentEnvironmentService :

@Service public class DevelopmentEnvironmentService implements EnvironmentService { public String getEnvironment() { return “development”; } }

Well all good so far. But how to get a hold of this bean, and still keep us free from xml configuration files ?

Let us say we have a service that is supposed to use the EnvironmentService interface to query for the environment we are running in. First we need to create the ConfigurationService and let it be known to the container with the @Service annotation.

@Service public class ConfigurationService { }

Then we need to inject it with an instance of the EnvironmentService. To do this, we use the @Autowired annotation. And after we have provided the dependency and implemented the business call the class may now looks like this :

@Service public class ConfigurationService { @Autowired EnvironmentService environmentService; public String getEnvironment() { return “development”; } }

That’s it. basically all you need to wire up spring applications using annotations instead of xml. ehh. well almost. You may want to add this little snippet to your xml configuration file :

<beans xmlns=“http://www.springframework.org/schema/beans” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xmlns:context=“http://www.springframework.org/schema/context” xsi:schemaLocation= “http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd”> <context:component-scan base-package=“no.arktekk.stagedspring”/> </beans>

With that said, there are other options like JavaConfig, or by creating your application context in Java, setting the correct scanners in code, but hey. the above snippet is kind a good enough for me.

Half way there

Ok now we have taken the xml configuration files out of the equation, but what happens if we have 2 instances of the EnvironmentService interface in the container ?

Well I can tell you… you get this stacktrace :

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'configurationService': Autowiring of fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: no.arktekk.stagedspring.service.EnvironmentService no.arktekk.stagedspring.service.ConfigurationService.environmentService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [no.arktekk.stagedspring.service.EnvironmentService] is defined: expected single matching bean but found 2: [developmentEnvironmentService, productionenvironmentService] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessAfterInstantiation(AutowiredAnnotationBeanPostProcessor.java:240) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:876) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:437) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:383) at java.security.AccessController.doPrivileged(Native Method) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:353) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:245) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:169) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:242) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:164) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:400) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:736) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:369) at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:123) at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:66) at no.arktekk.stagedspring.context.StagedClassPathXmlApplicationContext.(StagedClassPathXmlApplicationContext.java:37) at no.arktekk.stagedspring.StageTest.defaultStageResolve(StageTest.java:38) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:585) at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:59) at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:98) at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:79) at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:87) at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:77) at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:42) at org.junit.internal.runners.JUnit4ClassRunner.invokeTestMethod(JUnit4ClassRunner.java:88) at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:51) at org.junit.internal.runners.JUnit4ClassRunner$1.run(JUnit4ClassRunner.java:44) at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:27) at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:37) at org.junit.internal.runners.JUnit4ClassRunner.run(JUnit4ClassRunner.java:42) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:38) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196) Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: no.arktekk.stagedspring.service.EnvironmentService no.arktekk.stagedspring.service.ConfigurationService.environmentService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [no.arktekk.stagedspring.service.EnvironmentService] is defined: expected single matching bean but found 2: [developmentEnvironmentService, productionenvironmentService] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:433) at org.springframework.beans.factory.annotation.InjectionMetadata.injectFields(InjectionMetadata.java:79) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessAfterInstantiation(AutowiredAnnotationBeanPostProcessor.java:237) … 38 more Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [no.arktekk.stagedspring.service.EnvironmentService] is defined: expected single matching bean but found 2: [developmentEnvironmentService, productionenvironmentService] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:583) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:409) … 40 more

What have I done to end up here ?

What I did is that I added this class below to my project :

@Service public class ProductionEnvironmentService implements EnvironmentService { public String getEnvironment() { return “production”; } }

And then, suddenly I am back to square one. I know this is somewhat a strange and constructed example, but is has been quite common in projects I have been in, that we need different implementations of an interface. Most often for mocking purposes. So
what I think Spring need to have support for is to have a discriminator between stages. And in true Open Source style, I thought.. well if they do not add it. then I have to do it

Stage Enabled Spring Contexts

So what I did was to create a little addon to the Spring framework providing the neccecary hooks to make this happen. it consists of just a few classes, and one annotation.

@Stage annotation

First, the @Stage annotation. This annotation serves as the discriminator, and can be registered on types. It has a String value, and defines 3 default stages :

  • Stage.DEVELOPMENT
  • Stage.TEST
  • Stage.PRODUCTION

When this annotation is present on a Java class, it tells the new stage enabled bean factory which stage this particular class should apply to.

StagedListableBeanFactory

This is a spring bean factory that when autowiring is happening, finds all the candidate classes, checks if they have a @Stage annotation and if there are more than one candidate, select the one that have the correct stage set and gives the reference back to the running application context.

Application Context

There are 2 application contexts supplied in the 1.0 version of Staged Enabled Spring Contexts StagedClassPathXmlContext and StagedXmlWebApplicationContext. To enable stage detection in spring you will have to use one of these contexts

StagedClassPathXmlContext

Used when a set of xml based configuration file is used to assemble a context in Java code. e.g. for embedding Spring in a server application, or test cases :

@Test public void defaultStageResolve() { ApplicationContext ctx = new StagedClassPathXmlApplicationContext(“classpath:applicationContext.xml”); ConfigurationService configurationService = (ConfigurationService) ctx.getBean(“configurationService”); assertEquals(Stage.PRODUCTION, configurationService.getRunningEnvironment()); } StagedXmlWebApplicationContext

Used when you are creating a web application. To enable this context instead of the default spring context, you will need to set a context param in you web application web.xml file :

<context-param> <param-name>contextClass</param-name> <param-value>no.arktekk.stagedspring.context.StagedXmlWebApplicationContext</param-value> </context-param>

Finally, we need to know what environment we are actually running in, and that is done with a configurable StageResolver strategy.

StageResolver

This is an interface that you could use to tell the stage enabled what environment we are running in. A default strategy is supplied, and it uses simply a system property to resolve the environment, defaulting to Stage.PRODUCTION. Of course there is nothing keeping you to supply your own environment check, by simply implementing that interface and register it as a bean in the context. The bean factory will automatically choose the one supplied by you if found.

Putting it all together

Then I have shown how to use the Stage Enabled Spring Contexts project, and it is time to summarize a little :

  1. Enable the Spring component scanner in your bean xml configuration file
  2. Annotate you classes with Spring stereotypes to make them discoverable
  3. Instanciate the application context using the StagedClassPathXmlApplicationContext or StagedXmlWebApplicationContext
  4. Annotate the classes you want to be stage aware with the @Stage annotation as in the example below
  5. (optionally) supply your own StageResolver strategy
@Service @Stage(Stage.PRODUCTION) public class ProductionEnvironmentService implements EnvironmentService { public String getEnvironment() { return “production”; } } @Service @Stage(Stage.DEVELOPMENT) public class DevelopmentEnvironmentService implements EnvironmentService { public String getEnvironment() { return “development”; } } Where to get it

Stage Enabled Spring Contexts is currently only available from my own public Subversion repository at :
http://kaare-nilsen.com/subversion/public/labs/staged-spring

Is it completly finished

The short answer. Nope. But for a 1.0 release I think it is sufficient. What I would like to point out is that it currently does not work well with the @Qualifier annotation, so if you are using it, the stage may not be correctly resolved.
I aim to fix that in a 1.1 release in a short while.

So as the last ting I would say, is that I hope you find it interesting and please drop me questions and suggestions to make it even better.

Categories: Tech