Lives in the UK. Likes blogging, cycling and eating lemon drizzle cake. Roger is a DZone MVB and is not an employee of DZone and has posted 143 posts at DZone. You can read more from them at their website. View Full User Profile

Using JSR-250's @PostConstruct Annotation to Replace Spring's InitializingBean

11.06.2011
| 18656 views |
  • submit to reddit

JSR-250 aka Common Annotations for the Java Platform was introduced as part of Java EE 5 an is usually used to annotated EJB3s. What’s not so well known is that Spring has supported three of the annotations since version 2.5. The annotations supported are:

  • @PostContruct - This annotation is applied to a method to indicate that it should be invoked after all dependency injection is complete.
  • @PreDestroy - This is applied to a method to indicate that it should be invoked before the bean is removed from the Spring context, i.e. just before it’s destroyed.
  • @Resource - This duplicates the functionality of @Autowired combined with @Qualifier as you get the additional benefit of being able to name which bean you’re injecting, without the need for two annotations.

This blog takes a quick look at the first annotation in the list @PostConstruct, demonstrating how it’s applied and comparing it to the equivalent InitializingBean interface.

InitializingBean has one method, afterPropertiesSet(), and it does what it says on the tin. The afterPropertiesSet() method is called after Spring has completed wiring things together. The code snippet below demonstrates how InitializingBean is implemented.
public class ImplementInitializingBean implements InitializingBean {

  private boolean result;

  public String businessMethod() {

    System.out.println("Inside - ImplementInitializingBean");
    return "InitializingBeanResult";
  }

  /**
   * This is part of the InitializingBean interface - called after the bean has been set-up. Use this method to check that the
   * bean has been set-up correctly. Also so use it to configure external resources such as databases etc.
   */
  @Override
  public void afterPropertiesSet() throws Exception {

    result = true;
    System.out.println("In aferPropertiesSet() - check the set-up of the bean.");
  }

  public boolean getResult() {
    return result;
  }
}

Annotations are supposed to make life easier, but do they in this case? Firstly to use the @PostConstruct annotation you need to include the following dependencies your POM file:

<!-- Required for Spring annotations -->          
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>

You also need to tell Spring to use annotations by adding the following to your Spring config file:

<?xml version="1.0" encoding="UTF-8"?>
<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"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!-- Scans the classpath of this application for @Components to deploy as beans -->
    <context:component-scan base-package="jsr250annotations" />

    <!-- Configures the @Controller programming model -->
    <mvc:annotation-driven />
</beans>

Having setup the environment, you can now use the @PostConstruct annotation.
@Component
public class ImplementPostConstruct implements MyPostConstructExample {

  private boolean result;

  @Override
  public String businessMethod() {

    System.out.println("Inside - ImplementPostConstruct");
    return "ImplementPostConstruct";
  }

  /**
   * @PostConstruct means that this is called after the bean has been set-up.
   *                Use this method to check that the bean has been set-up
   *                correctly. Also so use it to configure external resources
   *                such as databases etc.
   */
  @PostConstruct
  public void postConstruct() {

    result = true;
    System.out
        .println("In postConstruct() - check the set-up of the bean.");
  }

  @Override
  public boolean getResult() {
    return result;
  }
}

This is tested using the JUnit Test below:
  @Test
  public void postConstructTest() {

    instance1 = ctx.getBean(ImplementPostConstruct.class);

    String result = instance1.businessMethod();
    assertEquals("ImplementPostConstruct", result);

    boolean var = instance1.getResult();
    assertTrue(var);
  }

The two clumps of code above do the same thing with postConstruct() being called at the same time asafterPropertiesSet(). It's easy to see that annotations look neater, but they are also more difficult to setup? I'll let you be the judge of that. Finally, one last thing to note, the JSR-250 annotations provide useful core functionality, but are part of Spring's MVC project warranting a possible superfluous dependency on the javax.servlet-api jar, so perhaps a little refactoring may be a good idea at some point.

 

From http://www.captaindebug.com/2011/11/using-jsr-250s-postconstruct-annotation.html

Published at DZone with permission of Roger Hughes, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

Fabrizio Giudici replied on Mon, 2011/11/07 - 5:07am

 

I could be wrong, but I don't think that in order to activate @PostConstruct you need Spring MVC, thus the dependencies you mentioned on Spring Web and Servlet. AFAIK,<mvc:annotation-driven> isn't the only way to go, as <context:annotation-config> is enough, and only requires depending on Spring Context.

Jonathan Fullam replied on Mon, 2011/11/07 - 10:31am

You can also simply include the "init-method" attribute in your bean declaration. This eliminates the coupling of your class with the Spring Framework (when implementing Springs InitializingBean interface).

Chris Beams replied on Mon, 2011/11/07 - 1:29pm

Roger, thanks for your post. I'll weigh in here with a couple clarifications. As other commenters have mentioned, neither spring-webmvc nor the Servlet API are required to enable processing of @PostConstruct and other annotations when using Spring.

Spring's <mvc:annotation-driven/> is used in the example. This element does in fact enable processing of JSR-250 annotations such as @PostConstruct, however for this example, it is overkill. Rather, the appropriate element to use is <context:annotation-driven/>. This latter element is a convenience utility for registering Spring's CommonAnnotationBeanPostProcessor as well as several other related BeanPostProcessors.

<context:component-scan/> is also used in the example, in order to automatically detect and register classes marked with Spring's @Component annotation. While this is a very common practice and generally recommended, it is also unnecessary for the purposes of this article.

The title of the article suggests an apples-to-apples comparison of two initialization mechanisms supported by the Spring framework: (1) InitializingBean and (2) JSR-250 @PostConstruct. In order to achieve such a straight-across comparison, the following things must be mentioned:

  • Spring's InitializingBean interface is automatically supported by the Spring container. Any Spring-managed object implementing InitializingBean will always and automatically receive an initialization callback via the afterPropertiesSet() method, immediately following construction and injection of dependencies for that object. This approach has the benefit of being well-known, having a familiar interface-based approach, being supported from the earliest versions of Spring forward, and being used extensively within Spring itself for components internal to the framework. The downside of this approach is that use by application-level (i.e. user-defined) components couples those components to the Spring API.
  • Spring's support for processing @PostConstruct, @PreDestroy and other so-called "common annotations" or "JSR-250 annotations" is not enabled by default, but rather requires the user to "switch on" the functionality*. This is typically done by declaring the <context:annotation-config/> element from the spring-context XML namespace. This approach is supported from Spring 2.5 forward and naturally requires the use of Java 5 or better for annotation support. Note that @PostConstruct and related annotations are part of the JDK from Java 6 forward, but is available as a standalone API jar for Java 5 users. The benefit of this approach is that users may mark any no-arg method with @PostConstruct and receive the same initialization callback afforded by InitializingBean without depending on a Spring-specific API.

The Spring team recommends the use of @PostConstruct over InitializingBean for typical application-level components when using Spring 2.5 or greater as this allows for the most flexibility, portability and general benefits of "plain old Java object" design.

* note that annotation processing is enabled by default when Spring 3.0's AnnotationConfigApplicationContext, which provides an alternative to the traditional XML-based application contexts such as ClassPathXmlApplicationContext

Roger Hughes replied on Mon, 2011/11/07 - 4:53pm in response to: Chris Beams

Chris 

Thanks for the comments and clarifiactions, I did think it a bit strange that it wouldn't work work out the MVC/Servlet API components. I'll update and clarify my original blog accordingly. 

Chris Beams replied on Mon, 2011/11/07 - 5:14pm in response to: Roger Hughes

Great, thanks! Also note that if you do keep <context:component-scan> in the example, that it also enables annotation processing, meaning that one would never need to declare both the component-scan and annotation-driven elements.

Roger Hughes replied on Mon, 2011/11/07 - 6:16pm in response to: Roger Hughes

An amended version of this blog is available at:
http://www.captaindebug.com/2011/11/using-jsr-250s-postconstruct-annotation.html

This takes the comments above into consideration removing mvc:annotation-driven and using only context:component-scan.  context:component-scan will activate all three annotations used in the example, however, if only @Autowired and @PostConstruct are used (and not @Component), then this could be replaced by the context:annotation-config element. 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.