» tagged pages
» logout

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

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

ASM version incompatibilities, using Spring @Autowired with Hibernate

Alef Arendsen

I was working on Spring 2.1 stuff this week with Joris. We were preparing a sample using all three ways of doing dependency injection. The sample does not only highlight dependency injection, but also features a back-end based on Hibernate.

Several features in Spring 2.1 require the ASM byte code manipulation framework. Hibernate also uses ASM, through CGLIB. There is a binary incompatibility between ASM 1.5.3 and 2.2.3. The former is used by Hibernate, the latter is used by Spring in various scenarios; specifically in some of the AOP functionality and the new @Autowired features.

Solution no. 1

The first solution is to explicitly replace the CGLIB jar for Hibernate with a nodep version (one is available from the Spring distribution) which contains a re-packaged version of ASM version 1.5.3. With Maven, this requires you to put in a few exclusions alongside your Hibernate dependency and to explicitly put in the ASM 2.2.3 dependency in your pom.

<dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate</artifactId>
        <version>3.2.1.ga</version>
        <exclusions>
                <exclusion>
                        <groupId>asm</groupId>
                        <artifactId>asm</artifactId>
                </exclusion>
                <exclusion>
                        <groupId>asm</groupId>
                        <artifactId>asm-attrs</artifactId>
                </exclusion>               
        </exclusions>
</dependency>
<dependency>
        <groupId>asm</groupId>
        <artifactId>asm</artifactId>
        <version>2.2.3</version>                       
</dependency>

Solution no. 2

I haven't tried this, but according to the Hibernate JIRA you can change the byte code provider for Hibernate to Javassist, as commented by Max Rydahl Andersen in the bug report.

Spring: Interface21 Team Blog

More on Java Configuration

Costin Leau

As most of you already know by now, Spring is not just about XML as lately, a number of 'official' extensions to the core offer alternatives way for configuring the container.

Spring Java Configuration 1.0 M2 was among the products released around JavaOne and, while still marked as a milestone, had an important number of updates and bugfixes:

  • the root package has changed to org.springframework.config.java
  • scoped beans are fully supported
  • the bean name generation can be customized
  • the distribution contains a 'transformed' sample (petclinic) which uses XML, JavaConfig and Groovy.

In fact, most of the work done for 1.0 M2 was incorporating the feedback received to the initial announcement; thanks a lot to everybody involved!

In this entry, I'd like to give some examples of Java Configuration, as a true IoC annotation-based configuration.
Let's start off with Mark's example, used in his entry on Spring 2.1 annotation-driven dependency injection.

To recap, below is a diagram of the interfaces and classes used by Mark:

diagram

The wiring is done through @Autowired while some methods are marked as being part of the lifecycle, through @PostConstruct and @PreDestroy.

Translating the annotation-driven configuration to Java Configuration is pretty straight forward:

@Configuration
public abstract class JavaCfg {

        @Bean (destroyMethodName = "tearDownDatabase")
        public JdbcMessageRepository messageRepo() {
                JdbcMessageRepository repo = new JdbcMessageRepository();
                repo.createTemplate(dataSource());
                // call custom init method
                repo.setUpDatabase();

                return repo;
        }
       
        @Bean
        public GreetingService greetService() {
                GreetingServiceImpl impl = new GreetingServiceImpl();
                impl.setMessageRepository(messageRepo());
                return impl;
        }

        @ExternalBean
        public abstract DataSource dataSource();
}

First, the configuration is created using a Java class marked with @Configuration. In it, 2 beans are being declared and an external one referenced.

The first bean declared is messageRepo (same as the method name) which defines also a destruction method. Notice that the custom init method is invoked through the code and thus doesn't need any annotation or declaration. You can still use Spring InitializingBean interface or the @Bean initMethodName parameter though I would recommend against that. The code above is much clearer and concise not to mention that you can pass in arguments, something unavailable when using declarative init methods.

The second bean defined is greetService which uses messageRepo as a dependency. This is where the Java Configuration magic occurs since each time greetService will be created, the Spring container will supply the bean instance behind messageRepo. That is, if messageRepo is a singleton, the same instance will be returned each time. However, if a different scope is specified, then, when a new instance has to be created, your code will be invoked. Rod already explained this so please refer to his blog entry for more information.

One addition to 1.0 M2 is the @ExternalBean annotation which references beans declared outside the current configuration while still relying on Java strong-typeness and thus, your IDE validation. @ExternalBean overrides at runtime the method it is declared on with a getBean() lookup, like this:

public DataSource dataSource() {
       return (DataSource) context.getBean("dataSource");
   }

Of course, one can do the same thing manually especially when using ConfigurationSupport class but @ExternalBean makes things a lot more easier. Note that in the initial example I have used an abstract method to emphasize externalization, however any type of non-final method can be used:

@ExternalBean
  public DataSource dataSource() {
      throw new UnsupportedOperationException("this line will NEVER execute since the method will be overridden");
  }

Now that the configuration has been created, declare it as a normal bean along with the JavaConfiguration post processor:

<?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"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.0.xsd"
>

        <bean id="config" class="blog.javaconfig.JavaCfg" />

        <bean id="processor"
                class="org.springframework.config.java.process.ConfigurationPostProcessor" />

        <bean id="dataSource"
                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 you are ready to go (if you are running Mark's test, make sure to use the Java Configuration xml file).

Since a picture is worth a thousands words, see below the same setup through SpringIDE:
springIDE view

I've used the latest SpringIDE snapshot which offers visualization, navigation and also validation for Java Configuration annotations (for example the plugin checks that destroyMethodName points to a proper method on the bean creation method return type).

Hide and seek

Java Configuration supports most of the XML declaration features, that is you can specify scopes, autowire strategies, lazyness, depends-on as well as custom metadata at bean level (through @Bean) and as defaults (through @Configuration). In 1.0 M2 you even get the @ScopedProxy annotation, a direct replacement for <aop:scoped-proxy/>.

However, one new feature that Java Configuration offers over the traditional XML container is "bean visibility" - the ability to define beans which cannot be used outside their configuration. Again, let's look at some code:

@Configuration
public class VisibilityConfiguration {

        @Bean(scope = DefaultScopes.PROTOTYPE)
        public Object publicBean() {
                List list = new ArrayList();
                list.add(hiddenBean());
                list.add(secretBean());

                System.out.println("creating public bean");
                return list;
        }

        @Bean(scope = DefaultScopes.SINGLETON)
        protected Object hiddenBean() {
                System.out.println("creating hidden bean");
                return new String("hidden bean");
        }

        @Bean(scope = DefaultScopes.PROTOTYPE)
        private Object secretBean() {
                List list = new ArrayList();
                // hidden beans can access beans defined in the 'owning' context
                list.add(hiddenBean());
                System.out.println("creating secret bean");
                return list;
        }
}

Java Configuration will use the method visibility to determine if a certain bean is public (that is if it can be used outside its declaring configuration) or private (non-public). Thus any @Bean annotated method, which is non-public, will create a hidden bean. This allows you to provide bean definition encapsulation, forbidding access whether accidental or not.
It is very important to note that hidden beans are not transformed into nested beans - they are fully featured, top-level beans: they have their own lifecycle and support custom scopes as opposed to inner beans which depend on the parent bean.

To prove this, I've marked the hiddenBean as singleton and secretBean as prototype.

Let's test the behavior with the following test:

public class VisibilityTest extends TestCase {
        private ConfigurableApplicationContext context;

        @Override
        protected void setUp() throws Exception {
                context = new AnnotationApplicationContext("**/VisibilityConfiguration.class");
        }

        @Override
        protected void tearDown() throws Exception {
                context.close();
        }

        public void testApplicationContext() {
                assertNotNull(context);
                System.out.println(Arrays.toString(context.getBeanDefinitionNames()));
                // I don't belive you container! I know you are hidding something
                context.getBean("hiddenBean");
        }
}

The test should print:

[blog.javaconfig.VisibilityConfiguration, publicBean]
creating hidden bean
creating secret bean
creating public bean
creating secret bean
creating public bean

after which should fail with something like:

org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'hiddenBean' is defined

The first line in the console shows that secretBean and hiddenBean are not defined in the context that we hold. However, the following lines, show that the hidden bean is created once (since it is a singleton) while secretBean twice, for each publicBean, as it is a prototype.

So where are the hidden beans then? Inside a child container.

The parent container (context in our case) is completely unaware of it and thus, of any beans declared inside it. Nevertheless, beans declared inside the child context can access any beans declared inside the parent but not vice-versa. Public beans (such as publicBean) on the other hand, are 'pushed' by Java Configuration inside the parent container, but since they are declared in the same configuration as the hidden bean, they can reference the 'secret' beans during instantiation.

Look Ma', no XML!

For those who want to ditch XML completely, Spring Java Configuration offers the AnnotationApplicationContext which uses classes rather then XML files, as you could see from the test case above. While my example works,it is not ideal since, without any caching, the application context will be created and destroyed for each test.
An alternative is to reuse the existing AbstractDependencyInjectionSpringContextTests and override the context creation appropriately:

public class NoXMLTest extends AbstractDependencyInjectionSpringContextTests {

        @Override
        protected ConfigurableApplicationContext createApplicationContext(String[] locations) {
                GenericApplicationContext context = new GenericApplicationContext();
                customizeBeanFactory(context.getDefaultListableBeanFactory());
                // use Java Configuration annotation-based bean definition reader
                new ConfigurationClassScanningBeanDefinitionReader(context).loadBeanDefinitions(locations);
                context.refresh();
                return context;
        }

        @Override
        protected String[] getConfigLocations() {
                return new String[] { "**/*.class" };
        }

        public void testAppCtx() {
                assertNotNull(applicationContext);
        }
}

(this can be further simplified through SPR-3550).

Which approach is better?

Some of you might wonder what is the best annotation configuration approach: annotation-driver injection or Java Configuration? My answer is: "it depends".

Java Configuration stays true to the IoC principle as the configuration resides outside your code, which means you have true POJOs (i.e. no configuration annotations inside your code).

The annotation-driven injection presented previously on this blog, allows objects to be a little more aware of their configuration. They can ask for dependencies, for autowiring and can even specify their scope. The injection still occurs (that is the objects are still managed by the container), but some parts of your configuration are now contained by your objects.

With JavaConfig you can configure your objects without any restrictions as you are using pure Java. You can use any number of arguments, of any type and can call any number of methods. Since it is Java, your configuration is refactoring friendly and you can benefit from your IDE auto-completion. This is extremely flexible and powerful!

On the other hand, with annotation-driven injection, you have fine-grained (class, method and even field-level) control over your objects as well as a lot more contextual information.

Consider the @Autowire method:

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

Spring uses the annotation not just to determine the method on which the autowiring will occur, but also the required type(s). Moreover, multi-arg methods can be used, a feature not supported by 'traditional' autowiring which uses the JavaBeans convention and thus, setters.

At the end of the day, both approaches serve one purpose: to configure the Spring container. You can use one of them, or both along with some XML and properties on top if you'd like. In fact, the Java Configuration distribution, replaces the 'traditional' XML configuration for Petclinic with an XML, annotations and Groovy based configuration. Considering this blog entry, it won't be long until JRuby will be included.

The bottom line is that you have the choice to pick whatever fits your development style better.

P.S. If you are interested in this topic, you might want to attend the following SpringOne session for an in-depth discussion )

Cheers,
Costin

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 th