Spring 2.5's Comprehensive Annotation Support

Juergen Hoeller

One of the central themes behind Spring 2.5 is comprehensive annotation-based configuration. We've been talking and blogging a lot about @Autowired, about Spring MVC's @RequestMapping and also about the new support for annotated tests written with JUnit4 or TestNG. @Autowired is certainly the central one of Spring 2.5's annotations, being available for use in service components, web components, unit tests - even domain objects when using Spring's @Configurable with AspectJ weaving. Spring MVC's @RequestMapping is equally flexible, supporting many variants of handler method signatures.

Today I'd like to take a different focus, namely on the wide-ranging set of dependency injection annotations supported by Spring. The following list includes the key annotations that can be used within Spring 2.5 beans:

  • org.springframework.beans.factory.annotation.Required:
    Identifies bean property setters that must be called (as opposed to optional setters). Supported since Spring 2.0.
  • org.springframework.beans.factory.annotation.Autowired:
    Spring 2.5's central injection annotation, applying to constructors, config methods and fields. Performs injection of components by type, with supporting for "qualifier" annotations that narrow the potential set of candidates in case of multiple matches.
  • javax.annotation.PostConstruct:
    JSR-250's common annotation for what Spring calls "init methods".
  • javax.annotation.PreDestroy:
    JSR-250's common annotation for what Spring calls "destroy methods".
  • javax.annotation.Resource:
    JSR-250's common annotation for injecting an external component by name. A "resource" in JSR-250 terminology really refers to a middleware component such as a DataSource.
  • javax.xml.ws.WebServiceRef:
    @Resource-like, for JAX-WS service lookups, injecting a JAX-WS port proxy.
  • javax.ejb.EJB:
    @Resource-like, for EJB Session Bean lookups, injecting an EJB component reference.
  • javax.persistence.PersistenceUnit:
    injecting a JPA EntityManagerFactory by persistence unit name. Supported since Spring 2.0.
  • javax.persistence.PersistenceContext:
    injecting a JPA EntityManager by persistence unit name. Supported since Spring 2.0.


This set of annotations encompasses all of Java EE 5's common annotations, which means that you may use the same common annotations in e.g. Servlet 2.5 servlets, JSF 1.2 managed beans and Spring managed beans. In other words, if you have some standard JSF 1.2 managed beans with annotation usage, you can take them as-is and move their definitions from faces-config to a Spring application context, without any change in the bean classes! This was an important design goal: Spring 2.5 may serve as straightforward replacement of the standard JSF 1.2 managed bean facility, simply through choosing SpringBeanFacesELResolver as your custom JSF ELResolver.

Configuration-wise, all you need to enable the complete set of annotations above is the following simple configuration element in your Spring application context:

<context:annotation-config/>

Note that this setting is related to dependency injection only and does not require any parameterization. (For customization, consider defining Spring's individual AnnotationBeanPostProcessors instead, e.g. CommonAnnotationBeanPostProcessor). However, the annotation-config element does not activate any kind of proxying or special exporting. For such purposes, Spring provides more specific configuration elements:

<tx:annotation-driven/>

This setting activates processing of transaction annotations, with the following two variants supported out of the box in Spring 2.5:

  • org.springframework.transaction.annotation.Transactional:
    Spring's own transaction annotation, as introduced in Spring 1.2. Allows for specifying propagation behavior (REQUIRED, REQUIRES_NEW, etc), read-only flag, custom isolation level (REPEATABLE_READ, SERIALIZABLE, etc) and custom rollback rules on a per-transaction level.
  • javax.ejb.TransactionAttribute
    EJB 3.0's transaction annotation. No customization options other than propagation behavior (REQUIRED, REQUIRES_NEW, etc).


Side note: As with all of Spring's support options, the EJB 3.0 TransactionAttribute annotation will only be available if the EJB 3.0 API is actually present in the classpath. Spring automatically adapts to the presence of that API, analogous to the JSR-250 API or the JPA API (as referenced above).

The <tx:annotation-driven> element allows for transaction-specific configuration, e.g. the Spring PlatformTransactionManager to talk to (through the "transaction-manager" attribute) and the mode to operate in:

<tx:annotation-driven transaction-manager="myTm" mode="aspectj"/>

The explicit AspectJ mode of transaction annotation processing is new in Spring 2.5, allowing to use Spring's AnnotationTransactionAspect instead of traditional AOP proxies. This requires AspectJ compile-time weaving or load-time weaving, modifying the byte code of classes that happen to use the @Transactional annotation. Such weaving allows for supporting the annotation on any kind of method: be it public, protected or private - be it an external call or a call from within the object - the transaction will always kick in as specified by the annotation. This is in sharp contrast to traditional AOP proxies, where annotation-driven transactions are limited to public method calls coming in through the proxy.

If your environment is capable of load-time weaving, then the following configuration is sufficient for enabling AspectJ-style transaction annotation processing. Note that this requires either a runtime environment with built-in weaving support (e.g. WebLogic 10, OC4J 10.1.3.1, Tomcat configured with Spring's TomcatInstrumentableClassLoader) or Spring's VM agent to be specified on JVM startup ("-javaagent:spring-agent.jar").

<context:load-time-weaver/>

<tx:annotation-driven mode="aspectj"/>

<bean id="transactionManager" class="…"/>

Finally, Spring 2.5 also provides a convenient configuration element for activating JMX exporting. The default MBeanServer will be autodetected on all common platforms, including the standard Java 5 platform MBeanServer as well as the special MBeanServers exposed by WebLogic 9/10 and WebSphere 6.

<context:mbean-export/>

Spring-managed beans may then implement standard MBean/MXBean conventions, qualifying as MBean classes according to the JMX specification, or use the following annotations to declare their management signature (as known since Spring 1.2):

  • org.springframework.jmx.export.annotation.ManagedResource:
    used at the type level to indicate a JMX-exposed component.
  • org.springframework.jmx.export.annotation.ManagedAttribute:
    used at the bean property setter/getter level to indicate an MBean attribute.
  • org.springframework.jmx.export.annotation.ManagedOperation:
    used at the public method level to indicate an exporter MBean operation.


This indicates the real power of Spring's annotation configuration model: Different configuration concerns seamlessly merge into a unified whole, with consistent configuration style and unified component lifecycle - it's all still a standard Spring bean underneath, managed by a Spring ApplicationContext!

So much for this brief tour through Spring's core configuration annotations. If you are interested in hearing more about what's new in Spring 2.5 and how it all ties together, let me invite you to this Wednesday's Spring 2.5 webinar where I will be covering all key feature areas in Spring 2.5, ranging from Java 6 support to annotation-based configuration!

 

9 responses


  1. Here's a question, since you mention JSF managed beans. We'd love to manage such beans exclusively through Spring, but can't find any substitute for the ability to inject request parameters into a bean that way, i.e an equivalent to the param.someparametername syntax in faces-config.xml. I'm sure something could be implemented with post-instantiation processors, but does Spring 2.5 already offer any way of doing that?


  2. Good point: Turning JSF-managed beans into Spring-managed beans only really works for components that are not tied to web interaction too closely. Effectively, components that can be considered a part of the service layer will end up as Spring-managed beans (potentially request-scoped or session-scoped, but still service objects at their core). On the other hand, user interaction components will typically remain defined in the faces-config XML file.

    Such UI components in faces-config are able to reference service components in the Spring application context through bean names in JSF expressions, so the overall model should still be pretty smooth. Pretty similar to what you'll find when using other web UI frameworks on top of Spring. In any case, from the perspective of general dependency injection, a high degree of consistency can be achieved between JSF-managed components and Spring-managed components.

    So Spring 2.5 doesn't provide request parameter injection for general Spring-managed beans at this point, as a deliberate choice. Request parameters are supported in Spring Web MVC in a variety of flavors, for example binding parameters to a controller's handler method arguments. This will be opened up for Spring 3.0 where we'll revise our expression language support. For the time being, the layer separation as outlined above should be a good guideline to follow.


  3. Ok, thanks for the answer. We're not yet using 2.5 anyway, so it's more an out-of-interest question than a practical one. But if we moved to 2.5 and abandoned most of our existing XML wiring, I'd certainly want to try to get rid of the equivalent in faces-config as well. And as I said, it shouldn't be too hard to solve in-house with some kind of post-processor, right?


  4. Yeah, simplest solution will be something like

    InstantiationAwareBeanPostProcessor.postProcessPropertyValues(.. {
    for propertyValues
    If propertyValue contains "#{" and "}" then
    context = FacesContext.getInstance();
    application = context.getApplication();
    evaluateValue = application.evaluateExpressionGet(context, stringExpressionValue, Object.class) //let spring convert
    return new MutablePropertyValues with modified and original values
    }


  5. Problem with the captcha ? I just tried to post a comment, and only the alt text appeared for the image…


  6. Juergen,

    Regardless of the usefulness of the various Spring annotations, I feel that annotations (Spring's or any other framework's for that matter) introduce a dependency on that particular framework/technology.

    In my opinion, an annotated POJO (e.g. Spring's @Transactional annotation) is no longer a POJO, don't you think?

    For instance, if I want to reuse parts of my domain-model in another application, which does not use Spring, I still need to include the Spring jars in that application's classpath, don't I?

    In its early days Spring used to advocate non-intrusiveness, and that was a principal differentiator between Spring and EJBs. Now, it seems to me that as Spring offers more and more annotations (which, again, are very useful) domain-specific code becomes more and more dependent on the Spring framework. I realize many people find XML configuration un-cool, but I think at least that way true separation of concerns is maintained.

    I am not trying to be polemic. I am really very interested in your thoughts on this.

    Thanks,
    Naaman


  7. Naaman,

    You do have a point, of course. For true separation of concerns, externalized metadata (such as XML) is the better choice - and still a first-class choice in Spring 2.5. We just give people more choice now, while we historically more or less enforced externalized configuration.

    Note that annotations that you use in your application classes do *not* have to present in the classpath for loading those classes. At least for recent JDK versions, non-present annotations will simply be ignored when loading your class. This arguably makes it more acceptable to embed Spring-specific annotations. And of course, with respect to the JSR 250 and JPA annotations: Those aren't Spring-specific in the first place, so shouldn't cause as much concern.

    Overall, Spring still aims to provide the most comprehensive XML component metadata format around: very flexible but also as concise as possible (given the fact of externalization to begin with). This will always remain a key differentiator between Spring and other solutions.

    Juergen


  8. This article is very interesting. I'm a Spring user since some time now. We're still using Full-XML configuration approach, but I really consider going to full annotations mode, since it simplifies the XML file.

    At this address http://www.onjava.com/pub/a/onjava/2006/01/25/spring-xml-configuration-best-practices.html, the author discourages autowiring (first point).

    I feel he has some poing about being explicit, but on the other hand Spring autowiring will always load the implementation you think since if it finds two candidates (without any @Qualifier) it will just stop.

    OTOH, in our case, using annotations&autowiring would reduce the risk of collisions between context files modifications. In fact, we already have more than one context file, but we still find ourselves modifying the same file and having to merge. With annotations-based config, the isolation would be better I think.

    I know this article is now a bit old, but I'd be very interested to know what you think about it.
    Maybe even what you
    - *thought* about it if you already knew about it before ?
    - and maybe which new Spring feature you'd think would deprecate some of the article's statements (mainly about autowiring btw, but also for some other points) ?

    Thanks and Cheers.


  9. That onjava article is OK. Its recommendations are pretty sound. (Even if some people may still e.g. prefer constructor injection etc… that's partly a question of style.)

    Anyway, @Autowired is quite different from traditional autowiring in terms of its implications on manageability of the overall configuration. In contrast to a pure convention (that's what autowiring by name or by type actually is), it specifically applies to annotated fields/methods/constructors only - being free from side effects in that respect (i.e. no accidental mismatch in the use of the convention, leading to too much or too little autowiring).

    You have a good point there that annotation-based configuration may lead to better isolation of artifacts, since you won't have to touch "global" configuration files that often anymore.

    One point in the article that doesn't really apply anymore is the following: "Remember, with powerful IDEs, such as Eclipse and IntelliJ, Java code is much easier to read, maintain, and manage than XML files!" Well, when using the Spring IDE Eclipse plugin or IntelliJ IDEA 6/7, Spring XML bean definition files are actually pretty convenient to navigate, maintain and manage… Of course, annotations in Java code are even easier maintain. In any case, well-designed XML configuration is still a viable choice as well!

    Juergen

6 trackbacks

Leave a Reply