» tagged pages
» logout

sorted by: recent | see : popular
Content Tagged with Container + AOP

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!

Spring: Interface21 Team Blog

Source for demos shown at NL-JUG session June 13th 2007

Alef Arendsen

Yesterday, Joris and I gave a session at the Dutch Java Users Group. We did the session twice and had about 250 people in total attending the sessions. A lot of people asked for the code for the demos we did during the sessions. Attached you'll find the code for the AOP and Dependency Injection demos. It shows a simple aspect flushing the Hibernate session before every JDBC operation (not as robust as you'd want it in production code, but it's a start) and it also shows the CarPlant system (demo'd before in other sessions and previously attached to another blog entry) configured using the various to do Dependency Injection in Spring 2.1 (i.e. using <bean>, @Bean and @Autowired).

It's a Maven2 project, so you'll need to have Maven2 installed. To prepare an Eclipse project including all libraries, run mvn eclipse:eclipse at the command line in the carplant directory.

The sources: carplant.zip

During the session a question came up about multiple <aop:config> blocks inside one application contexts. The guy in the audience wasn't sure if two or more blocks of AOP configuration showed the expected result (advising two or more times). I don't have the guys email address, so I wanted to clarify this here a little bit. Consider the following code. The doIt() will be advised. The actual advice (for simplicity) is kept in the same class, just as the main method bootstrapping the ApplicationContext.

public class Logger {

  public void doIt() {

  }

  public void log() {
    System.out.println("Log!");
  }

  public static void main(String args[]) {
    ApplicationContext context =
      new ClassPathXmlApplicationContext(
        new String[] {"com/carplant/context1.xml", "com/carplant/context2.xml"});

    Logger logger = (Logger)context.getBean("logger");

    logger.doIt();
  }
}

Configuration 1: one simple AOP config block

The file context2.xml is empty in this case, whereas context1.xml contains the following code:

<bean id="logger" class="Logger"/>

<aop:config>
        <aop:pointcut id="doItOperation" expression="execution(* doIt(..))"/>
        <aop:aspect ref="logger">
                <aop:before pointcut-ref="doItOperation" method="log"/>
        </aop:aspect>
</aop:config>

As expected, upon calling the doIt() method we'll only get one line of output from the logger (it's only advised once).

Configuration 2: two AOP config blocks in two different files

context2.xml now is identical to context1.xml (in the example above) with the only difference that in context2.xml we don't have bean called logger. When running this scenario, we'll see two Log! output entries. The doIt() method is advised twice.

Configuration 3: two AOP config blocks in the same configuration file

context2.xml is empty again. context1.xml on the other hand now contains two <aop:config> blocks. The only difference between the two is the pointcut identifier (this is an XML ID, so should be unique in the XML file).

<bean id="logger" class="Logger"/>

<aop:config>
        <aop:pointcut id="doItOperation" expression="execution(* doIt(..))"/>
        <aop:aspect ref="logger">
                <aop:before pointcut-ref="doItOperation" method="log"/>
        </aop:aspect>
</aop:config>

<aop:config>
        <aop:pointcut id="doItOperation2" expression="execution(* doIt(..))"/>
        <aop:aspect ref="logger">
                <aop:before pointcut-ref="doItOperation2" method="log"/>
        </aop:aspect>
</aop:config>

Running this will also show that the bean will be advised twice.

Note that I'm using a 2.1 milestone release here.

Spring: Interface21 Team Blog

Source for demos shown at NL-JUG session June 13th 2007

Alef Arendsen

Yesterday, Joris and I gave a session at the Dutch Java Users Group. We did the session twice and had about 250 people in total attending the sessions. A lot of people asked for the code for the demos we did during the sessions. Attached you'll find the code for the AOP and Dependency Injection demos. It shows a simple aspect flushing the Hibernate session before every JDBC operation (not as robust as you'd want it in production code, but it's a start) and it also shows the CarPlant system (demo'd before in other sessions and previously attached to another blog entry) configured using the various to do Dependency Injection in Spring 2.1 (i.e. using <bean>, @Bean and @Autowired).

It's a Maven2 project, so you'll need to have Maven2 installed. To prepare an Eclipse project including all libraries, run mvn eclipse:eclipse at the command line in the carplant directory.

The sources: carplant.zip

During the session a question came up about multiple <aop:config> blocks inside one application contexts. The guy in the audience wasn't sure if two or more blocks of AOP configuration showed the expected result (advising two or more times). I don't have the guys email address, so I wanted to clarify this here a little bit. Consider the following code. The doIt() will be advised. The actual advice (for simplicity) is kept in the same class, just as the main method bootstrapping the ApplicationContext.

public class Logger {

  public void doIt() {

  }

  public void log() {
    System.out.println("Log!");
  }

  public static void main(String args[]) {
    ApplicationContext context =
      new ClassPathXmlApplicationContext(
        new String[] {"com/carplant/context1.xml", "com/carplant/context2.xml"});

    Logger logger = (Logger)context.getBean("logger");

    logger.doIt();
  }
}

Configuration 1: one simple AOP config block

The file context2.xml is empty in this case, whereas context1.xml contains the following code:

<bean id="logger" class="Logger"/>

<aop:config>
        <aop:pointcut id="doItOperation" expression="execution(* doIt(..))"/>
        <aop:aspect ref="logger">
                <aop:before pointcut-ref="doItOperation" method="log"/>
        </aop:aspect>
</aop:config>

As expected, upon calling the doIt() method we'll only get one line of output from the logger (it's only advised once).

Configuration 2: two AOP config blocks in two different files

context2.xml now is identical to context1.xml (in the example above) with the only difference that in context2.xml we don't have bean called logger. When running this scenario, we'll see two Log! output entries. The doIt() method is advised twice.

Configuration 3: two AOP config blocks in the same configuration file

context2.xml is empty again. context1.xml on the other hand now contains two <aop:config> blocks. The only difference between the two is the pointcut identifier (this is an XML ID, so should be unique in the XML file).

<bean id="logger" class="Logger"/>

<aop:config>
        <aop:pointcut id="doItOperation" expression="execution(* doIt(..))"/>
        <aop:aspect ref="logger">
                <aop:before pointcut-ref="doItOperation" method="log"/>
        </aop:aspect>
</aop:config>

<aop:config>
        <aop:pointcut id="doItOperation2" expression="execution(* doIt(..))"/>
        <aop:aspect ref="logger">
                <aop:before pointcut-ref="doItOperation2" method="log"/>
        </aop:aspect>
</aop:config>

Running this will also show that the bean will be advised twice.

Note that I'm using a 2.1 milestone release here.

Spring: Interface21 Team Blog

Customizing Annotation Configuration and Component Detection in Spring 2.1

Mark Fisher

NOTE: This post has been updated as of May 31, 2007 to reflect the state of the 2.1-M2 official release

Two weeks ago I blogged about the new annotation-driven dependency injection capabilities of Spring 2.1, and I mentioned that I would follow-up with more info "later in the week". It turns out that was a bit optimistic, but the good news is the functionality has evolved quite a bit in the meantime. Therefore, to follow along with the examples here you will need to download the 2.1-M2 official release (or if you are one of the first people to read this updated entry and M2 is not yet available, you should grab at least nightly build #115 which you can download here).

The first thing I want to demonstrate is how to create an application context without using any XML. For those who have used Spring's BeanDefinitionReader implementations, this will look very familiar. Before creating the context however, we need a few "candidate" beans on the classpath. Continuing with the example from my previous blog, I have the following two interfaces:

public interface GreetingService {
        String greet(String name);
}
public interface MessageRepository {
        String getMessage(String language);
}

…and these corresponding implementations:

@Component
public class GreetingServiceImpl implements GreetingService {

        @Autowired
        private MessageRepository messageRepository;
       
        public String greet(String name) {
                Locale locale = Locale.getDefault();
                if (messageRepository == null) {
                        return "Sorry, no messages";
                }
                String message = messageRepository.getMessage(locale.getDisplayLanguage());
                return message + " " + name;
        }
}

@Repository
public class StubMessageRepository implements MessageRepository {

        Map<String,String> messages = new HashMap<String,String>();
       
        @PostConstruct
        public void initialize() {
                messages.put("English", "Welcome");
                messages.put("Deutsch", "Willkommen");
        }
       
        public String getMessage(String language) {
                return messages.get(language);
        }
}

Now as promised… to assemble this admittedly trivial "application" without any XML:

Locale.setDefault(Locale.GERMAN);
GenericApplicationContext context = new GenericApplicationContext();
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("blog"); // the parameter is 'basePackage'
context.refresh();
GreetingService greetingService = (GreetingService) context.getBean("greetingServiceImpl");
String message = greetingService.greet("Standalone Beans");
System.out.println(message);

And the result:

Willkommen Standalone Beans

Essentially, this is the exact same behavior as when using the component-scan XML element from the new "context" namespace (as demonstrated in my previous blog). However, I want to focus on some of the newer features as well as customization options. First, I will remove the @Repository annotation from the StubMessageRepository, and rerun the tests which produces the following exception:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'greetingServiceImpl': Autowiring of fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private blog.MessageRepository blog.GreetingServiceImpl.messageRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [blog.MessageRepository] is defined: expected single bean but found 0

Clearly the @Autowired annotation indicates a required dependency by default, but this can easily be switched by adding the 'required' parameter with a value of 'false', such as:

@Component
public class GreetingServiceImpl implements GreetingService {

        @Autowired(required=false)
        private MessageRepository messageRepository;
        …

The result after this modification:

Sorry, no messages

To make things a bit more interesting, I will add the JDBC version of the MessageRepository (also from the previous post):

@Repository
public class JdbcMessageRepository implements MessageRepository {

        private SimpleJdbcTemplate jdbcTemplate;

        @Autowired
        public void createTemplate(DataSource dataSource) {
                this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
        }
       
        @PostConstruct
        public void setUpDatabase() {
                jdbcTemplate.update("create table messages (language varchar(20), message varchar(100))");
                jdbcTemplate.update("insert into messages (language, message) values ('English', 'Welcome')");
                jdbcTemplate.update("insert into messages (language, message) values ('Deutsch', 'Willkommen')");
        }
       
        @PreDestroy
        public void tearDownDatabase() {
                jdbcTemplate.update("drop table messages");
        }
       
        public String getMessage(String language) {
                return jdbcTemplate.queryForObject("select message from messages where language = ?", String.class, language);
        }
}

As long as the stub version still does not contain the @Repository annotation, rerunning the tests will now produce the following exception:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'greetingServiceImpl': Autowiring of fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private blog.MessageRepository blog.GreetingServiceImpl.messageRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'jdbcMessageRepository': Autowiring of methods failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void blog.JdbcMessageRepository.createTemplate(javax.sql.DataSource); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [javax.sql.DataSource] is defined: expected single bean but found 0

Obviously a chain reaction of autowiring failures has resulted since no DataSource is available in the context. However, as a firm believer in test-driven development, I would like to unit test my implementation prior to setting up the infrastructure. Luckily, the scanner is fairly customizable, and I can provide filters, such as:

Locale.setDefault(Locale.GERMAN);
GenericApplicationContext context = new GenericApplicationContext();

boolean useDefaultFilters = false;

ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context, useDefaultFilters);
scanner.addExcludeFilter(new AssignableTypeFilter(JdbcMessageRepository.class));
scanner.addIncludeFilter(new AnnotationTypeFilter(Component.class));
scanner.addIncludeFilter(new RegexPatternTypeFilter(Pattern.compile("blog\\.Stub.*")));
scanner.scan("blog");

context.refresh();
GreetingService greetingService =
             (GreetingService) context.getBean("greetingServiceImpl");
String message = greetingService.greet("Standalone Beans");
System.out.println(message);

As you can see, I disabled the 'defaultFilters' and explicitly added my own. In this case, that was not completely necessary since the default includes the @Component and @Repository annotations, but I wanted to show the various filtering options - including not only annotations, but also assignable types and even regular expressions. The main goal of course was to disable the JDBC version of MessageRepository in favor of the stub, and according to my result, that is exactly what happened:

Willkommen Standalone Beans

Assuming that I am now ready to incorporate the JDBC version, I will likely need to include some XML configuration for the DataSource, such as:

<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.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.1.xsd"
>

     
    <context:property-placeholder location="classpath:blog/jdbc.properties"/>
   
    <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
       
</beans>

Then, I can combine the scanning with an XmlBeanDefinitionReader (notice that I have reverted to the default filters only):

Locale.setDefault(Locale.GERMAN);
GenericApplicationContext context = new GenericApplicationContext();

ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.scan("blog");

BeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
reader.loadBeanDefinitions("classpath:/blog/dataSource.xml");

context.refresh();
GreetingService greetingService = (GreetingService) context.getBean("greetingServiceImpl");
String message = greetingService.greet("Hybrid Beans");
System.out.println(message);

The context contains both the scanned beans as well as those defined in XML, and the result is:

Willkommen Hybrid Beans

Up to this point, you've seen that 0 candidate beans will cause the autowiring to fail unless the 'required' parameter of @Autowired is set to false. Given that the autowiring is following 'by-type' semantics, more than 1 bean will cause a failure regardless of the required parameter's value. For example, after adding the @Repository annotation back to the StubMessageRepository and rerunning the previous example, I receive the following exception:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'greetingServiceImpl': Autowiring of fields failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private blog.MessageRepository blog.GreetingServiceImpl.messageRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [blog.MessageRepository] is defined: expected single bean but found 2

This can be resolved by switching to 'by-name' semantics - accomplished via Spring 2.1's support for the JSR-250 @Resource annotation:

@Component
public class GreetingServiceImpl implements GreetingService {

        @Resource(name="jdbcMessageRepository")
        private MessageRepository messageRepository;
        …

You probably noticed in the previous example that the bean name (as specified in the @Resource annotation) defaults to the decapitalized non-qualified classname. To override this behavior, it is possible to add your own implementation of the BeanNameGenerator strategy, such as:

private static class MyBeanNameGenerator implements BeanNameGenerator {

        public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
                String fqn = definition.getBeanClassName();
                return Introspector.decapitalize(fqn.replace("blog.", "").replace("Jdbc", ""));
        }
}

Then providing this strategy to the scanner overrides the default:

ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(context);
scanner.setBeanNameGenerator(new MyBeanNameGenerator());
scanner.scan("blog");

And therefore, the name specified in the @Resource annotation can be modified accordingly:

@Resource(name="messageRepository")
private MessageRepository messageRepository;

NOTE: When relying on the container for autowiring, the default naming strategy is typically sufficient (i.e. it works "behind the scenes"). Therefore the naming strategy should only be considered for cases where you will be referring to beans by name elsewhere. Even then, for isolated cases it is much simpler to explicitly provide a bean name in the 'stereotype' annotation (e.g. @Repository("messageRepository")). Providing your own strategy can be useful if you are able to take advantage of naming conventions that are used consistently throughout your application (This particular example is a little contrived, but hopefully demonstrates that the strategy is very accommodating so that you can follow your own naming conventions).

So far all of the beans have been configured with the default 'singleton' scope, but scope resolution is another customizable strategy of the scanner. The default will look for a @Scope annotation on each component. For example, to configure the GreetingServiceImpl as a 'prototype', simply add the following:

@Scope("prototype")
@Component
public class GreetingServiceImpl implements GreetingService { .. }

While the default annotation approach is quite simple, scope is almost always a deployment-specific consideration. Therefore it often does not belong at the class-level or in the source code at all. For these reasons, the following strategy interface is available and may be specified on the scanner as with the BeanNameGenerator in the previous example:

public interface ScopeMetadataResolver {
        ScopeMetadata resolveScopeMetadata(BeanDefinition definition);
}

Note that the name generation and scope resolution strategies may also be provided in the XML-based configuration, such as:

<context:component-scan base-package="blog"
                        name-generator="blog.MyBeanNameGenerator"
                        scope-resolver="blog.MyScopeMetadataResolver"/>

Likewise, custom filters can be added as sub-elements:

<context:component-scan base-package="blog" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
    <context:include-filter type="regex" expression="blog\.Stub.*"/>
    <context:exclude-filter type="assignable" expression="blog.JdbcMessageRepository"/>
</context:component-scan>

I realize this entry has already covered quite a bit of ground, but there is one last topic I would like to cover. In the previous post, I included an aspect with the <aop:aspectj-autoproxy/> element. Now I want to demonstrate how to add the autoproxy behavior with our standalone version. First, the aspect itself (same as last time):

@Aspect
public class ServiceInvocationLogger {

        private int invocationCount;
       
        @Pointcut("execution(* blog.*Service+.*(..))")
        public void serviceInvocation() {}
       
        @Before("serviceInvocation()")
        public void log() {
                invocationCount++;
                System.out.println("service invocation #" + invocationCount);
        }
}

Next, I need to add an include filter for the @Aspect annotation (it is no longer included in the default filters):

scanner.addIncludeFilter(new AnnotationTypeFilter(Aspect.class));
scanner.scan("blog");

And finally, I need to register the AspectJ annotation-based autoproxy creator (prior to calling refresh() on the context):

AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(context);
context.refresh();

The result:

service invocation #1
Willkommen Hybrid Beans

Hopefully this entry and the preceding one have provided a sufficient introduction to these new features of Spring 2.1. You should now have a decent understanding of how to combine the component scanning and annotation configuration in small doses alongside "traditional" Spring XML configuration if you prefer. Also, by providing your own filters, name generators, and scope resolvers, you can customize the configuration process. The official 2.1-M2 release contains more detailed information in the reference documentation.

Stay tuned to this Interface21 Team Blog to learn about more new features as we continue to progress from the current milestone phase toward the RC1 release of Spring 2.1, and if you are not particularly excited about the annotation-driven configuration, then you may want to keep an eye out for an upcoming blog by Costin Leau on Spring Java Configuration - which offers yet another alternative to XML but without the invasiveness of annotations in your application code.

Spring: Interface21 Team Blog

Annotation-Driven Dependency Injection in Spring 2.1

Mark Fisher

Spring 2.0 introduced annotation support and annotation-aware configuration options that can be leveraged by Spring users who are developing with Java 5 (or later versions):

@Transactional@Aspect (AspectJ) @Repository@Required
for demarcating and configuring transaction definitions
for defining aspects along with @Pointcut definitions and advice (@Before, @After, @Around)
for indicating a class that is operating as a repository (a.k.a. Data Access Object or DAO)
for enforcing annotated bean properties are provided a value

With Spring 2.1, this theme of annotation-driven configuration has been significantly extended and will continue to evolve as we progress toward the RC1 release. In fact, it is now possible to drive Spring's dependency injection via annotations. Furthermore, Spring can discover beans that need to be configured within an application context.

This blog entry will serve as a tutorial-style introduction to the basic features in 10 easy-to-follow steps. I will follow up later in the week with information on some more advanced features and customization options. If you are interested in alternative configuration options, you should also check out the Spring Java Configuration project and this blog.

This tutorial requires at least Java 5, and Java 6 is recommended (otherwise there is a single requirement at the end of step 1).

Step 1:

Grab spring-framework-2.1-m1-with-dependencies.zip. After extracting the archive, you will find the spring.jar and spring-mock.jar in the 'dist' directory. Add them to your CLASSPATH as well as the following (paths shown are relative to the 'lib' directory of the extracted 2.1-m1 archive):

  • asm/asm-2.2.3.jar
  • asm/asm-commons-2.2.3.jar
  • aspectj/aspectjweaver.jar
  • hsqldb/hsqldb.jar
  • jakarta-commons/commons-logging.jar
  • log4j/log4j-1.2.14.jar

(NOTE: If you are not running on Java 6, you will also need to add j2ee/common-annotations.jar)

Step 2:

Provide the interfaces and classes for the example. I have tried to keep it as simple as possible yet capable of demonstrating the main functionality. I am including all of the code and configuration in a single "blog" package. I would encourage following that same guideline so that the examples work as-is; otherwise, be sure to make the necessary modifications. First, the GreetingService interface:

public interface GreetingService {
    String greet(String name);
}

Then, a simple implementation:

public class GreetingServiceImpl implements GreetingService {
    private MessageRepository messageRepository;

    public void setMessageRepository(MessageRepository messageRepository) {
        this.messageRepository = messageRepository;
    }

    public String greet(String name) {
        Locale locale = Locale.getDefault();
        String message = messageRepository.getMessage(locale.getDisplayLanguage());
        return message + " " + name;
    }
}

Since the service depends upon a MessageRepository, define that interface next:

public interface MessageRepository {
    String getMessage(String language);
}

And for now, a stub implementation:

public class StubMessageRepository implements MessageRepository {
    Map<String,String> messages = new HashMap<String,String>();

    public void initialize() {
        messages.put("English", "Welcome");
        messages.put("Deutsch", "Willkommen");
    }

    public String getMessage(String language) {
        return messages.get(language);
    }
}

Step 3:

Define the beans for a Spring application context. Notice, that I am including a new 'context' namespace (NOTE: the 'aop' namespace is also included here and will be used in the final step):

<?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:aop="http://www.springframework.org/schema/aop"
       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.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.1.xsd"
>

     
    <bean class="blog.GreetingServiceImpl"/>

    <bean class="blog.StubMessageRepository"/>

</beans>

Obviously this configuration looks a little sparse. As you can probably guess, the 'context' namespace will soon play a role.

Step 4:

Provide a simple test case leveraging Spring's base support class:

public class GreetingServiceImplTests extends AbstractDependencyInjectionSpringContextTests {
    private GreetingService greetingService;

    public void setGreetingService(GreetingService greetingService) {
        this.greetingService = greetingService;
    }

    @Override
    protected String[] getConfigLocations() {
        return new String[] { "/blog/applicationContext.xml" };
    }

    public void testEnglishWelcome() {
        Locale.setDefault(Locale.ENGLISH);
        String name = "Spring Community";
        String greeting = greetingService.greet(name);
        assertEquals("Welcome " + name, greeting);
    }

    public void testGermanWelcome() {
        Locale.setDefault(Locale.GERMAN);
        String name = "Spring Community";
        String greeting = greetingService.greet(name);
        assertEquals("Willkommen " + name, greeting);
    }
}

Try running the tests and notice that they fail with a NullPointerException. This is to be expected since the GreetingServiceImpl has not been provided a MessageRepository. In the next two steps, you will add annotations to drive the dependency injection and initialization respectively.

Step 5:

Provide an @Autowired annotation on the GreetingServiceImpl's setter method, such as:

@Autowired
public void setMessageRepository(MessageRepository messageRepository) {
    this.messageRepository = messageRepository;
}

Then, add the 'annotation-config' element (from the new 'context' namespace) to your configuration:

<beans>
   
    <context:annotation-config/>

    <bean class="blog.GreetingServiceImpl"/>

    <bean class="blog.StubMessageRepository"/>

</beans>

Rerun the tests. They will still fail, but if you look closely it's a new problem. The assertions fail, because the messages being returned are null. That means that the 'messageRepository' property has been set on the greeting service! Now, the StubMessageRepository simply needs to be initialized.

Step 6:

Spring provides a couple options for initialization callbacks: Spring's InitializingBean interface or an 'init-method' declaration within XML. As of Spring 2.1, JSR-250 annotations are supported - providing yet another option: @PostConstruct (and the @PreDestroy annotation can be used for destruction callbacks as you will see shortly). In the StubMessageRepository, add the annotation to the initialize method:

@PostConstruct
public void initialize() {
    messages.put("English", "Welcome");
    messages.put("Deutsch", "Willkommen");
}

Rerun the tests. This time they should pass!

Step 7:

The @Autowired annotation can also be used for constructor-based injection. If you'd like to experiment with that option, remove the setter method from the GreetingServiceImpl and add this constructor instead (then rerun the tests):

@Autowired
public GreetingServiceImpl(MessageRepository messageRepository) {
    this.messageRepository = messageRepository;
}

If preferred, you can even use field-injection. Remove the constructor, add the annotation directly to the field, and rerun the tests. The code should look like this:

@Autowired
private MessageRepository messageRepository;

Step 8:

Add a JDBC-based repository implementation of the MessageRepository:

public class JdbcMessageRepository implements MessageRepository {

    private SimpleJdbcTemplate jdbcTemplate;

    @PostConstruct
    public void setUpDatabase() {
        jdbcTemplate.update("create table messages (language varchar(20), message varchar(100))");
        jdbcTemplate.update("insert into messages (language, message) values ('English', 'Welcome')");
        jdbcTemplate.update("insert into messages (language, message) values ('Deutsch', 'Willkommen')");
    }

    @PreDestroy
    public void tearDownDatabase() {
        jdbcTemplate.update("drop table messages");
    }

    public String getMessage(String language) {
        return jdbcTemplate.queryForObject("select message from messages where language = ?", String.class, language);
    }

}

Notice that in addition to @PostConstruct for initialization, this is using @PreDestroy to mark a method to be called on destruction. One thing is unclear from this implementation: how will the SimpleJdbcTemplate be provided? One option would be to provide a bean definition for the template. Another option would be to somehow provide a DataSource implementation to the template's constructor. Add the following (annotated) method:

@Autowired
public void createTemplate(DataSource dataSource) {
    this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
}

This demonstrates dependency injection working with an arbitrary method (not a traditional 'setter'). This will be tested in the course of the next step.

Step 9:

In Spring 2.1, "candidate" beans can even be discovered rather than provided explicitly in the XML as above. Certain annotations are recognized by default. This includes the @Repository annotation as well as a new @Component annotation. Add those two annotations to JdbcMessageRepository and GreetingServiceImpl respectively:

@Repository
public class JdbcMessageRepository implements MessageRepository {}
@Component
public class GreetingServiceImpl implements GreetingService {}

Then modify the XML file by removing the existing explicit bean definitions and simply adding a component-scan tag:

<beans>
    <context:component-scan base-package="blog"/>
</beans>

Then, add just the DataSource bean definition and the new tag for configuring property placeholders:

<beans>
    <context:component-scan base-package="blog"/>

    <context:property-placeholder location="classpath:blog/jdbc.properties"/>

    <bean class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

</beans>

… and the jdbc.properties file itself:

jdbc.driver=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:mem:blog
jdbc.username=sa
jdbc.password=

Rerun the tests, and you should see the green bar even though only the data source has been defined in XML.

Step 10:

Finally, add an aspect (the @Aspect annotations are also automatically detected by default):

@Aspect
public class ServiceInvocationLogger {

    private int invocationCount;

    @Pointcut("execution(* blog.*Service+.*(..))")
    public void serviceInvocation() {}

    @Before("serviceInvocation()")
    public void log() {
        invocationCount++;
        System.out.println("service invocation #" + invocationCount);
    }
}

And to activate automatic proxy generation, simply add the following tag to the xml:

<aop:aspectj-autoproxy/>

Rerun the tests, and you should see the log messages!

NOTE: the scanning and configuration process can be initiated without any XML and can be customized (e.g. detect your own annotations and/or types). I will discuss those features and more in the next post.

In the mean time, I hope this post will serve its purpose well - providing hands-on experience with these new Spring 2.1 features. As always, we are looking forward to feedback from the community, so please feel free to leave comments!

Spring: Interface21 Team Blog

CarPlant not accepting null CarModels

Alef Arendsen

Last Friday I finished a training session at a client of ours. Because I had some time to kill in the hotel I was staying in, I polished the sample application I coded up during the training to post it online for the guys of the training. Usually I try to find a little sample application specific to the client's domain to use during the training. This makes it a bit more lively instead of some of the HelloWorld examples.

This client is a big car brand, that have adopted Spring widely throughout their organization. That's why I created a CarPlant system capable of producing cars. Below you can find a little UML diagram displaying the (rather tiny) domain model and services in the system.

In the application, I'm using various techniques that you might not have seen that much yet. Here's a small list of what you can expect:

  • @Required dependencies - by using the RequiredAnnotationBeanPostProcessor we can check if certain dependencies are actually set. This mechanism (of course only available on Java 5) is a very nice alternative for the dependency-check attribute in XML
  • @NotNull argument checking - this is a simple aspect that I'm usually showing during training sessions. It uses a pointcut driven by annotations (which I think is a very neat way of driving your pointcuts) to check for null arguments passed to methods (so now you know what the title refers to ;-) )
  • DAOs with and without the use of HibernateTemplate - to show the flexibility of Spring's DAO facilities
  • Annotation-driven transaction management which is a feature I definitely recommend if you're on Java 5. Using annotations for transaction management is a very good fit IMO
  • Some integration testing - this Spring gem (I don't think I'm the only one with this opinion ;-) ) is not used enough yet when I visit clients so let's do a little more promotion of the AbstractTransactionalDataSourceSpringContextTests (thanks Rod for the name ) )
  • The sample uses Maven, so you have to have that installed, because I haven't included the dependencies.

    carplant.png

    The source code for the sample: CarPlant.zip

Spring: Interface21 Team Blog