Chapter 2. Advanced Spring IoC Container

In this chapter, you will learn the advanced features and internal mechanisms of the Spring IoC container, which can help you to increase your efficiency when developing Spring applications. Although these features may not be used very often, they are indispensable to a comprehensive and powerful container. They are also the foundation of other modules of the Spring framework.

The Spring IoC container itself is designed to be easily customizable and extensible. It allows you to customize the default container behaviors through configuration and extend the container's features by registering your container plug-ins that conform to the container specification.

After finishing this chapter, you will be familiar with most features of the Spring IoC container. This will give you a useful basis for learning about different topics of Spring in the subsequent chapters.

Creating Beans by Invoking a Static Factory Method

Problem

You would like to create a bean in the Spring IoC container by invoking a static factory method, whose purpose is to encapsulate the object-creation process in a static method. The client who requests an object can simply make a call to this method without knowing about the creation detail.

Solution

Spring supports creating a bean by invoking a static factory method, which should be specified in the factory-method attribute.

How It Works

For example, you can write the following createProduct() static factory method to create a product from a predefined product ID. According to the product ID, this method will decide which concrete product class to instantiate. If there is no product matching this ID, it will throw an IllegalArgumentException.

package com.apress.springrecipes.shop;

public class ProductCreator {

    public static Product createProduct(String productId) {
        if ("aaa".equals(productId)) {
            return new Battery("AAA", 2.5);
        } else if ("cdrw".equals(productId)) {
            return new Disc("CD-RW", 1.5);
        }
        throw new IllegalArgumentException("Unknown product");
    }
}

To declare a bean created by a static factory method, you specify the class hosting the factory method in the class attribute and the factory method's name in the factory-method attribute. Finally, you pass the method arguments by using the <constructor-arg> elements.

<beans ...>
    <bean id="aaa" class="com.apress.springrecipes.shop.ProductCreator"
        factory-method="createProduct">
        <constructor-arg value="aaa" />
    </bean>

    <bean id="cdrw" class="com.apress.springrecipes.shop.ProductCreator"
        factory-method="createProduct">
        <constructor-arg value="cdrw" />
    </bean>
</beans>

In case of any exception thrown by the factory method, Spring will wrap it with a BeanCreationException. The equivalent code snippet for the preceding bean configuration is shown following:

Product aaa = ProductCreator.createProduct("aaa");
Product cdrw = ProductCreator.createProduct("cdrw");

Creating Beans by Invoking an Instance Factory Method

Problem

You would like to create a bean in the Spring IoC container by invoking an instance factory method, whose purpose is to encapsulate the object-creation process in a method of another object instance. The client who requests an object can simply make a call to this method without knowing about the creation detail.

Solution

Spring supports creating a bean by invoking an instance factory method. The bean instance should be specified in the factory-bean attribute, while the factory method should be specified in the factory-method attribute.

How It Works

For example, you can write the following ProductCreator class by using a configurable map to store the predefined products. The createProduct() instance factory method finds a product by looking up the supplied productId in the map. If there is no product matching this ID, it will throw an IllegalArgumentException.

package com.apress.springrecipes.shop;
...
public class ProductCreator {

    private Map<String, Product> products;

    public void setProducts(Map<String, Product> products) {
        this.products = products;
    }

    public Product createProduct(String productId) {
        Product product = products.get(productId);
        if (product != null) {
            return product;
        }
        throw new IllegalArgumentException("Unknown product");
    }
}

To create products from this ProductCreator class, you first have to declare an instance of it in the IoC container and configure its product map. You may declare the products in the map as inner beans. To declare a bean created by an instance factory method, you specify the bean hosting the factory method in the factory-bean attribute, and the factory method's name in the factory-method attribute. Finally, you pass the method arguments by using the <constructor-arg> elements.

<beans ...>
    <bean id="productCreator"
        class="com.apress.springrecipes.shop.ProductCreator">
        <property name="products">
            <map>
                <entry key="aaa">
                    <bean class="com.apress.springrecipes.shop.Battery">
                        <property name="name" value="AAA" />
                        <property name="price" value="2.5" />
                    </bean>
                </entry>
                <entry key="cdrw">
<bean class="com.apress.springrecipes.shop.Disc">
                        <property name="name" value="CD-RW" />
                        <property name="price" value="1.5" />
                    </bean>
                </entry>
            </map>
        </property>
    </bean>

    <bean id="aaa" factory-bean="productCreator"
        factory-method="createProduct">
        <constructor-arg value="aaa" />
    </bean>

    <bean id="cdrw" factory-bean="productCreator"
        factory-method="createProduct">
        <constructor-arg value="cdrw" />
    </bean>
</beans>

If any exception is thrown by the factory method, Spring will wrap it with a BeanCreationException. The equivalent code snippet for the preceding bean configuration is shown following:

ProductCreator productCreator = new ProductCreator();
productCreator.setProducts(...);

Product aaa = productCreator.createProduct("aaa");
Product cdrw = productCreator.createProduct("cdrw");

Declaring Beans from Static Fields

Problem

You would like to declare a bean in the Spring IoC container from a static field. In Java, constant values are often declared as static fields.

Solution

To declare a bean from a static field, you can make use of either the built-in factory bean FieldRetrievingFactoryBean, or the <util:contant> tag in Spring 2.x.

How It Works

First, let's define two product constants in the Product class.

package com.apress.springrecipes.shop;

public abstract class Product {

    public static final Product AAA = new Battery("AAA", 2.5);
    public static final Product CDRW = new Disc("CD-RW", 1.5);
    ...
}

To declare a bean from a static field, you can make use of the built-in factory bean FieldRetrievingFactoryBean and specify the fully qualified field name in the staticField property.

<beans ...>
    <bean id="aaa" class="org.springframework.beans.factory.config.
How It Works
FieldRetrievingFactoryBean"> <property name="staticField"> <value>com.apress.springrecipes.shop.Product.AAA</value> </property> </bean> <bean id="cdrw" class="org.springframework.beans.factory.config.
How It Works
FieldRetrievingFactoryBean"> <property name="staticField"> <value>com.apress.springrecipes.shop.Product.CDRW</value> </property> </bean> </beans>

The preceding bean configuration is equivalent to the following code snippet:

Product aaa = com.apress.springrecipes.shop.Product.AAA;
Product cdrw = com.apress.springrecipes.shop.Product.CDRW;

As an alternative to specifying the field name in the staticField property explicitly, you can set it as the bean name of FieldRetrievingFactoryBean. The downside is that your bean name may get rather long and verbose.

<beans ...>
    <bean id="com.apress.springrecipes.shop.Product.AAA"
        class="org.springframework.beans.factory.config.
How It Works
FieldRetrievingFactoryBean" /> <bean id="com.apress.springrecipes.shop.Product.CDRW" class="org.springframework.beans.factory.config.
How It Works
FieldRetrievingFactoryBean" /> </beans>

Spring 2 and later allow you to declare a bean from a static field by using the <util:constant> tag. Compared to using FieldRetrievingFactoryBean, it is a simpler way of declaring beans from static fields. But before this tag can work, you must add the util schema definition to your <beans> root element.

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util-3.0.xsd">

    <util:constant id="aaa"
        static-field="com.apress.springrecipes.shop.Product.AAA" />

    <util:constant id="cdrw"
        static-field="com.apress.springrecipes.shop.Product.CDRW" />
</beans>

Declaring Beans from Object Properties

Problem

You would like to declare a bean in the Spring IoC container from an object property or a nested property (i.e., a property path).

Solution

To declare a bean from an object property or a property path, you can make use of either the built-in factory bean PropertyPathFactoryBean or the <util:property-path> tag in Spring 2.x.

How It Works

As an example, let's create a ProductRanking class with a bestSeller property whose type is Product.

package com.apress.springrecipes.shop;

public class ProductRanking {

    private Product bestSeller;

    public Product getBestSeller() {
        return bestSeller;
    }

    public void setBestSeller(Product bestSeller) {
        this.bestSeller = bestSeller;
    }
}

In the following bean declaration, the bestSeller property is declared by an inner bean. By definition, you cannot retrieve an inner bean by its name. However, you can retrieve it as a property of the productRanking bean. The factory bean PropertyPathFactoryBean can be used to declare a bean from an object property or a property path.

<beans ...>
    <bean id="productRanking"
        class="com.apress.springrecipes.shop.ProductRanking">
        <property name="bestSeller">
            <bean class="com.apress.springrecipes.shop.Disc">
                <property name="name" value="CD-RW" />
                <property name="price" value="1.5" />
            </bean>
        </property>
    </bean>

    <bean id="bestSeller"
        class="org.springframework.beans.factory.config.PropertyPathFactoryBean">
        <property name="targetObject" ref="productRanking" />
        <property name="propertyPath" value="bestSeller" />
    </bean>
</beans>

Note that the propertyPath property of PropertyPathFactoryBean can accept not only a single property name but also a property path with dots as the separators. The preceding bean configuration is equivalent to the following code snippet:

Product bestSeller = productRanking.getBestSeller();

In addition to specifying the targetObject and propertyPath properties explicitly, you can combine them as the bean name of PropertyPathFactoryBean. The downside is that your bean name may get rather long and verbose.

<bean id="productRanking.bestSeller"
    class="org.springframework.beans.factory.config.PropertyPathFactoryBean" />

Spring 2.x allows you to declare a bean from an object property or a property path by using the <util:property-path> tag. Compared to using PropertyPathFactoryBean, it is a simpler way of declaring beans from properties. But before this tag can work, you must add the util schema definition to your <beans> root element.

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util-3.0.xsd">
    ...
    <util:property-path id="bestSeller" path="productRanking.bestSeller" />
</beans>

You can test this property path by retrieving it from the IoC container and printing it to the console.

package com.apress.springrecipes.shop;
...
public class Main {

    public static void main(String[] args) throws Exception {
        ...
        Product bestSeller = (Product) context.getBean("bestSeller");
        System.out.println(bestSeller);
    }
}

Using the Spring Expression Language

Problem

You want to dynamically evaluate some condition or property and use it as the value configured in the IoC container. Or perhaps you need to defer evaluation of something not at design time but at runtime, as might be the case in a custom scope. Or you just need a way to add a strong expression language to your own application.

Solution

Use Spring 3.0's Spring Expression Language (SpEL), which provides functionality similar to the Unified EL from JSF and JSP, or Object Graph Navigation Language (OGNL). SpEL provides easy-to-use infrastructure that can be leveraged outside of the Spring container. Within the container, it can be used to make configuration much easier in a lot of cases.

How It Works

Today, there are many different types of expression languages in the enterprise space. If you use WebWork/Struts 2 or Tapestry 4, you've no doubt used the OGNL. If you've used JSP or JSF in recent years, you've used one or both of the expression languages that are available in those environments. If you've used JBoss Seam, you've used the expression language made available there, which is a superset of the standard expression language shipped with JSF (Unified EL).

The expression language draws its heritage from many places. Certainly, it is a superset of what's available via the Unified EL. Spring.NET has had a similar expression language for awhile, and the feedback has been very favorable. The need to evaluate certain expressions at arbitrary points in a life cycle, such as during a scoped beans initialization, contributed to some of the qualities of this expression language.

Some of these expression languages are very powerful, bordering on being scripting languages in their own right. The SpEL is no different. It's available almost everywhere you can imagine needing it from annotations to XML configuration. The SpringSource Tool Suite also provides robust support for the expression language in the way of auto-completion and lookup.

Features of the Language Syntax

The expression language supports a long list of features. Table 2-1 briefly runs through the various constructs and demonstrates their usage.

Table 2.1. Expression Language Features

Type

Use

Example

Literal expression

The simplest thing you can do in the expression language, essentially the same as if you were writing Java code. The language supports String literals as well as all sorts of numbers.

2342
'Hello Spring Enterprise Recipes'

Boolean and relational operator

The expression language provides the ability to evaluate conditionals using standard idioms from Java.

T(java.lang.Math).random()
Expression Language Features
> .5

Standard expression

You can iterate and return the properties on beans in the same way you might with Unified EL, separating each dereferenced property with a period and using JavaBean-style naming conventions. In the example to the right, the expression would be equivalent to getCat().getMate().getName().

cat.mate.name

Class expression

T() tells the expression language to act on the type of the class, not an instance. In the examples on the right, the first would yield the Class instance for java.lang.Math—equivalent to calling java.lang.Math.class. The second example calls a static method on a given type. Thus, T(java.lang.Math).random() is equivalent to calling java.lang.Math.random().

T(java.lang.Math)
T(java.lang.Math).random()

Accessing arrays, lists, maps

You can index lists, arrays, and maps using brackets and the key—which for arrays or lists is the index number, and for maps is an object. In the examples, you see a java.util.List with four chars being indexed at index 1, which returns 'b'. The second example demonstrates accessing a map by the index 'OR', yielding the value associated with that key.

T(java.util.Arrays).asList(
Expression Language Features
'a','b','c','d')[1] T(SpelExamplesDemo)
Expression Language Features
.MapOfStatesAndCapitals['OR']

Method invocation

Methods may be invoked in instances just as you would in Java. This is a marked improvement over the basic JSF or JSP expression languages.

'Hello, World'.toLowerCase()

Relational operators

You can compare or equate values, and the returned value will be a Boolean.

23 == person.age
'fala'  < 'fido'

Calling constructor

You can create objects and invoke their constructors. Here, you create simple String and Cat objects.

new String('Hello Spring
Expression Language Features
Enterprise Recipes, again!') new Cat('Felix')

Ternary operator

Ternary expressions work as you'd expect, yielding the value in the true case.

T(java.lang.Math).random() >
Expression Language Features
.5 ? 'She loves me' : 'She
Expression Language Features
loves me not'

Variable

The SpEL lets you set and evaluate variables. The variables can be installed by the context of the expression parser, and there are some implicit variables, such as #this, which always refer to the root object of the context.

#this.firstName
#customer.email

Collection projection

A very powerful feature inside of SpEL is the capability to perform very sophisticated manipulations of maps and collections. Here, you create a projection for the list cats. In this example, the returned value is a collection of as many elements being iterated that has the value for the name property on each cat in the collection. In this case, cats is a collection of Cat objects. The returned value is a collection of String objects.

cats.![name]

Collection selection

Selection lets you dynamically filter objects from a collection or map by evaluating a predicate on each item in the collection and keeping only those elements for which the predicate is true. In this case, you evaluate the java.util.Map.Entry.value property for each Entry in the Map and if the value (in this case a String), lowercased, starts with "s", then it is kept. Everything else is discarded.

mapOfStatesAndCapitals.?
Expression Language Features
[value.toLowerCase().
Expression Language Features
startsWith('s')]

Templated expression

You can use the expression language to evaluate expressions inside of string expressions. The result is returned. In this case, the result is dynamically created by evaluating the ternary expression and including 'good' or 'bad' based on the result.

Your fortune is ${T(java
Expression Language Features
.lang.Math).random()> .5 ?
Expression Language Features
'good' : 'bad'}

Uses of the Language in Your Configurations

The expression language is available via XML or annotations. The expressions are evaluated at creation time for the bean, not at the initialization of the context. This has the effect that beans created in a custom scope are not configured until the bean is in the appropriate scope. You can use them in the same way via XML or annotations.

The first example is the injection of a named expression language variable, systemProperties, which is just a special variable for the java.util.Properties instance that's available from System.getProperties(). The next example shows the injection of a system property itself directly into a String variable:

@Value("#{ systemProperties }")
           private Properties systemProperties;

           @Value("#{ systemProperties['user.region'] }")
           private String userRegion;

You can also inject the result of computations or method invocations. Here, you're injecting the value of a computation directly into a variable:

@Value("#{  T(java.lang.Math).random() * 100.0 }")
           private double randomNumber;

The next examples assume that another bean is configured in the context with the name emailUtilities. The bean, in turn, has JavaBean-style properties that are injected into the following fields:

@Value("#{ emailUtilities.email }")
           private String email;

           @Value("#{ emailUtilities.password }")
           private String password;

           @Value("#{ emailUtilities.host}")
           private String host;

You can also use the expression language to inject references to other named beans in the same context:

@Value("#{ emailUtilities }")
           private EmailUtilities emailUtilities ;

In this case, because there's only one bean in the context with the interface EmailUtilities, you could also do this:

@Autowired
           private EmailUtilities emailUtilities ;

Although there are other mechanisms for discriminating against beans of the same interface, the expression language becomes very handy here, because it lets you simply discriminate by bean id.

You can use the expression language in your XML configurations in exactly the same way as with the annotation support. Even the prefix #{ and the suffix } are the same.

<bean class="com.apress.springrecipes.spring3. spel.EmailNotificationEngine"
 p:randomNumber="#{  T(java.lang.Math).random() * 100.0 }"
...
/>

Using the Spring Expression Language Parser

The SpEL is used primarily inside the XML configuration and annotation support provided with the Spring framework, but you're free to use the expression language. The centerpiece of the functionality is provided by the expression parser, org.springframework.expression.spel.antlr.SpelAntlrExpressionParser, which you can instantiate directly:

ExpressionParser parser = new SpelAntlrExpressionParser();

Conceivably, you could build an implementation that complies with the ExpressionParser interface and builds your own integration using this API. This interface is central for evaluating expressions written using the SpEL. The simplest evaluation might look like this:

Expression exp = parser.parseExpression("'ceci n''est pas une String'" );
String val = exp.getValue(String.class);

Here, you evaluate the String literal (notice that you're escaping the single quote with another single quote, not with a backslash) and return the result. The call to getValue() is generic, based on the type of the parameter, so you don't need to cast.

A common scenario is evaluation of expressions against an object. The properties and methods of the object no longer require an instance or class and can be manipulated independently. The SpEL parser refers to it as the root object. Let's take an object named SocialNetworkingSiteContext, for example, which, in turn, has other attributes you want to traverse to iterate over the members of the site:

SocialNetworkingSiteContext socialNetworkingSiteContext = 
Using the Spring Expression Language Parser
new SocialNetworkingSiteContext(); // ... ensure it's properly initialized ... Expression firstNameExpression = parser.parseExpression("loggedInUser.firstName"); StandardEvaluationContext ctx = new StandardEvaluationContext(); ctx.setRootObject(socialNetworkingSiteContext); String valueOfLoggedInUserFirstName = firstNameExpression.getValue(ctx, String.class );

Because you set the socialNetworkingSiteContext as the root, you could enumerate any child property without qualifying the reference.

Suppose that, instead of specifying a root object, you want to specify a named variable and be able to access it from within your expression. The SpEL parser lets you provide it with variables against which expressions can be evaluated. In the following example, you provide it with a socialNetworkingSiteContext variable. Inside the expression, the variable is prefixed with a "#":

StandardEvaluationContext ctx1 = new StandardEvaluationContext ();
  SocialNetworkingSiteContext socialNetworkingSiteContext =
        new SocialNetworkingSiteContext();
  Friend myFriend = new Friend() ;
  myFriend.setFirstName("Manuel");
  socialNetworkingSiteContext.setLoggedInUser(myFriend);
  ctx1.setVariable("socialNetworkingSiteContext",socialNetworkingSiteContext );
  Expression loggedInUserFirstNameExpression =
  parser.parseExpression("#socialNetworkingSiteContext.loggedInUser.firstName");
  String loggedInUserFirstName = loggedInUserFirstNameExpression.getValue
Using the Spring Expression Language Parser
(ctx1, String.class);

Similarly, you can provide the expression language named functions that are available without any qualification inside an expression:

StandardEvaluationContext ctx1 = new StandardEvaluationContext();
  ctx1.registerFunction("empty", StringUtils.class.getDeclaredMethod(
  "isEmpty", new Class[] { String.class }));
  Expression functionEval =  parser.parseExpression(
  " #empty(null) ? 'empty' : 'not empty' ");
  String result = functionEval.getValue(ctx1, String.class );

You can use the expression language parser infrastructure to template Strings. The returned value is a String, although within the String, you can have the parser substitute the result of evaluated expressions. This could be useful in any number of scenarios, for example, in simple message preparation. You simply create an instance of org.springframework.expression.ParserContext. This class dictates to the parser which token is a prefix (the prefix token is "${") and which is a suffix (the suffix token is "}"). The following example yields "The millisecond is 1246953975093".

ParserContext pc = new ParserContext() {
   public String getExpressionPrefix() {
           return "${";
  }
  public String getExpressionSuffix() {
            return "}";
  }
  public boolean isTemplate() {
           return true;
  }
};

String templatedExample = parser.parseExpression(
    "The millisecond is ${  T(System).currentTimeMillis()  }.", pc).getValue(String.class);

Setting Bean Scopes

Problem

When you declare a bean in the configuration file, you are actually defining a template for bean creation, not an actual bean instance. When a bean is requested by the getBean() method or a reference from other beans, Spring will decide which bean instance should be returned according to the bean scope. Sometimes, you have to set an appropriate scope for a bean other than the default scope.

Solution

In Spring 2.x or later, a bean's scope is set in the scope attribute of the <bean> element. By default, Spring creates exactly one instance for each bean declared in the IoC container, and this instance will be shared in the scope of the entire IoC container. This unique bean instance will be returned for all subsequent getBean() calls and bean references. This scope is called singleton, which is the default scope of all beans. Table 2-2 lists all valid bean scopes in Spring.

Table 2.2. Valid Bean Scopes in Spring

Scope

Description

Singleton

Creates a single bean instance per Spring IoC container

Prototype

Creates a new bean instance each time when requested

Request

Creates a single bean instance per HTTP request; only valid in the context of a web application

Session

Creates a single bean instance per HTTP session; only valid in the context of a web application

GlobalSession

Creates a single bean instance per global HTTP session; only valid in the context of a portal application

In Spring 1.x, singleton and prototype are the only two valid bean scopes, and they are specified by the singleton attribute (i.e., singleton="true" or singleton="false"), not the scope attribute.

How It Works

To demonstrate the concept of bean scope, let's consider a shopping cart example in your shop application. First, you create the ShoppingCart class as follows:

package com.apress.springrecipes.shop;
...
public class ShoppingCart {

    private List<Product> items = new ArrayList<Product>();

    public void addItem(Product item) {
        items.add(item);
    }

    public List<Product> getItems() {
        return items;
    }
}

Then you declare some product beans and a shopping cart bean in the IoC container as usual:

<beans ...>
    <bean id="aaa" class="com.apress.springrecipes.shop.Battery">
        <property name="name" value="AAA" />
        <property name="price" value="2.5" />
    </bean>

    <bean id="cdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="CD-RW" />
        <property name="price" value="1.5" />
    </bean>

    <bean id="dvdrw" class="com.apress.springrecipes.shop.Disc">
        <property name="name" value="DVD-RW" />
        <property name="price" value="3.0" />
    </bean>

    <bean id="shoppingCart" class="com.apress.springrecipes.shop.ShoppingCart" />
</beans>

In the following Main class, you can test your shopping cart by adding some products to it. Suppose that there are two customers navigating in your shop at the same time. The first one gets a shopping cart by the getBean() method and adds two products to it. Then, the second customer also gets a shopping cart by the getBean() method and adds another product to it.

package com.apress.springrecipes.shop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
public static void main(String[] args) {
        ApplicationContext context =
            new ClassPathXmlApplicationContext("beans.xml");

        Product aaa = (Product) context.getBean("aaa");
        Product cdrw = (Product) context.getBean("cdrw");
        Product dvdrw = (Product) context.getBean("dvdrw");

        ShoppingCart cart1 = (ShoppingCart) context.getBean("shoppingCart");
        cart1.addItem(aaa);
        cart1.addItem(cdrw);
        System.out.println("Shopping cart 1 contains " + cart1.getItems());

        ShoppingCart cart2 = (ShoppingCart) context.getBean("shoppingCart");
        cart2.addItem(dvdrw);
        System.out.println("Shopping cart 2 contains " + cart2.getItems());
    }
}

As a result of the preceding bean declaration, you can see that the two customers get the same shopping cart instance.

Shopping cart 1 contains [AAA 2.5, CD-RW 1.5]

Shopping cart 2 contains [AAA 2.5, CD-RW 1.5, DVD-RW 3.0]

This is because Spring's default bean scope is singleton, which means Spring creates exactly one shopping cart instance per IoC container.

<bean id="shoppingCart"
    class="com.apress.springrecipes.shop.ShoppingCart"
    scope="singleton" />

In your shop application, you expect each customer to get a different shopping cart instance when the getBean() method is called. To ensure this behavior, you should change the scope of the shoppingCart bean to prototype. Then Spring will create a new bean instance for each getBean() method call and reference from the other bean.

<bean id="shoppingCart"
    class="com.apress.springrecipes.shop.ShoppingCart"
    scope="prototype" />

Now if you run the Main class again, you can see that the two customers get a different shopping cart instance.

Shopping cart 1 contains [AAA 2.5, CD-RW 1.5]

Shopping cart 2 contains [DVD-RW 3.0]

Customizing Bean Initialization and Destruction

Problem

Many real-world components have to perform certain types of initialization tasks before they are ready to be used. Such tasks include opening a file, opening a network/database connection, allocating memory, and so on. Also, they have to perform the corresponding destruction tasks at the end of their life cycle. So, you have a need to customize bean initialization and destruction in the Spring IoC container.

Solution

In addition to bean registration, the Spring IoC container is also responsible for managing the life cycle of your beans, and it allows you to perform custom tasks at particular points of their life cycle. Your tasks should be encapsulated in callback methods for the Spring IoC container to call at a suitable time.

The following list shows the steps through which the Spring IoC container manages the life cycle of a bean. This list will be expanded as more features of the IoC container are introduced.

  1. Create the bean instance either by a constructor or by a factory method.

  2. Set the values and bean references to the bean properties.

  3. Call the initialization callback methods.

  4. The bean is ready to be used.

  5. When the container is shut down, call the destruction callback methods.

There are three ways that Spring can recognize your initialization and destruction callback methods. First, your bean can implement the InitializingBean and DisposableBean life cycle interfaces and implement the afterPropertiesSet() and destroy() methods for initialization and destruction. Second, you can set the init-method and destroy-method attributes in the bean declaration and specify the callback method names. In Spring 2.5 or later, you can also annotate the initialization and destruction callback methods with the life cycle annotations @PostConstruct and @PreDestroy, which are defined in JSR-250, Common Annotations for the Java Platform. Then you can register a CommonAnnotationBeanPostProcessor instance in the IoC container to call these callback methods.

How It Works

To understand how the Spring IoC container manages the life cycle of your beans, let's consider an example involving the checkout function. The following Cashier class can be used to check out the products in a shopping cart. It records the time and the amount of each checkout in a text file.

package com.apress.springrecipes.shop;
...
public class Cashier {

    private String name;
    private String path;
    private BufferedWriter writer;

    public void setName(String name) {
        this.name = name;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public void openFile() throws IOException {
        File logFile = new File(path, name + ".txt");
        writer = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream(logFile, true)));
    }

    public void checkout(ShoppingCart cart) throws IOException {
        double total = 0;
        for (Product product : cart.getItems()) {
            total += product.getPrice();
        }
        writer.write(new Date() + "	" + total + "
");
        writer.flush();
    }

    public void closeFile() throws IOException {
        writer.close();
    }
}

In the Cashier class, the openFile() method opens the text file with the cashier name as the file name in the specified system path. Each time you call the checkout() method, a checkout record will be appended to the text file. Finally, the closeFile() method closes the file to release its system resources.

Then, you declare a cashier bean with the name cashier1 in the IoC container. This cashier's checkout records will be recorded in the file c:/cashier/cashier1.txt. You should create this directory in advance or specify another existing directory.

<beans ...>
    ...
    <bean id="cashier1" class="com.apress.springrecipes.shop.Cashier">
        <property name="name" value="cashier1" />
        <property name="path" value="c:/cashier" />
    </bean>
</beans>

However, in the Main class, if you try to check out a shopping cart with this cashier, it will result in a NullPointerException. The reason for this exception is that no one has called the openFile() method for initialization beforehand.

package com.apress.springrecipes.shop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;

public class Main {

    public static void main(String[] args) throws Exception {
        ApplicationContext context =
            new FileSystemXmlApplicationContext("beans.xml");
        Cashier cashier1 = (Cashier) context.getBean("cashier1");
        cashier1.checkout(cart1);
    }
}

Where should you make a call to the openFile() method for initialization? In Java, the initialization tasks should be performed in the constructor. But would it work here if you call the openFile() method in the default constructor of the Cashier class? No, because the openFile() method requires both the name and path properties to be set before it can determine which file to open.

package com.apress.springrecipes.shop;
...
public class Cashier {
    ...
    public void openFile() throws IOException {
        File logFile = new File(path, name + ".txt");
        writer = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream(logFile, true)));
    }
}

When the default constructor is invoked, these properties have not been set yet. So you may add a constructor that accepts the two properties as arguments, and call the openFile() method at the end of this constructor. However, sometimes you may not be allowed to do so, or you might prefer to inject your properties via setter injection. Actually, the best time to call the openFile() method is after all properties have been set by the Spring IoC container.

Implementing the InitializingBean and DisposableBean Interfaces

Spring allows your bean to perform initialization and destruction tasks in the callback methods afterPropertiesSet() and destroy() by implementing the InitializingBean and DisposableBean interfaces. During bean construction, Spring will notice that your bean implements these interfaces and call the callback methods at a suitable time.

package com.apress.springrecipes.shop;
...
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class Cashier implements InitializingBean, DisposableBean {
    ...
    public void afterPropertiesSet() throws Exception {
        openFile();
    }

    public void destroy() throws Exception {
        closeFile();
    }
}

Now if you run your Main class again, you will see that a checkout record is appended to the text file c:/cashier/cashier1.txt. However, implementing such proprietary interfaces will make your beans Spring-specific and thus unable to be reused outside the Spring IoC container.

Setting the init-method and destroy-method Attributes

A better approach of specifying the initialization and destruction callback methods is by setting the init-method and destroy-method attributes in your bean declaration.

<bean id="cashier1" class="com.apress.springrecipes.shop.Cashier"
    init-method="openFile" destroy-method="closeFile">
    <property name="name" value="cashier1" />
    <property name="path" value="c:/cashier" />
</bean>

With these two attributes set in the bean declaration, your Cashier class no longer needs to implement the InitializingBean and DisposableBean interfaces. You can also delete the afterPropertiesSet() and destroy() methods as well.

Annotating the @PostConstruct and @PreDestroy Annotations

In Spring 2.5 or later, you can annotate the initialization and destruction callback methods with the JSR-250 life cycle annotations @PostConstruct and @PreDestroy.

Note

To use the JSR-250 annotations, you have to include the JSR 250 dependency. If you are using Maven, add:

<dependency>
   <groupId>javax.annotation</groupId>
   <artifactId>jsr250-api</artifactId>
   <version>1.0</version>
 </dependency>
package com.apress.springrecipes.shop;
...
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class Cashier {
    ...
    @PostConstruct
    public void openFile() throws IOException {
        File logFile = new File(path, name + ".txt");
        writer = new BufferedWriter(new OutputStreamWriter(
                new FileOutputStream(logFile, true)));
    }

    @PreDestroy
    public void closeFile() throws IOException {
        writer.close();
    }
}

Next, you register a CommonAnnotationBeanPostProcessor instance in the IoC container to call the initialization and destruction callback methods with the life cycle annotations. In this way, you no longer need to specify the init-method and destroy-method attributes for your bean.

<beans ...>
    ...
    <bean class="org.springframework.context.annotation.
Annotating the @PostConstruct and @PreDestroy Annotations
CommonAnnotationBeanPostProcessor" /> <bean id="cashier1" class="com.apress.springrecipes.shop.Cashier"> <property name="name" value="cashier1" /> <property name="path" value="c:/cashier" /> </bean> </beans>

Or you can simply include the <context:annotation-config> element in your bean configuration file, and a CommonAnnotationBeanPostProcessor instance will automatically get registered. But before this tag can work, you must add the context schema definition to your <beans> root element.

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

    <context:annotation-config />
    ...
</beans>

Reducing XML Configuration with Java Config

Problem

You enjoy the power of the DI container but want to override some of the configuration, or you simply want to move more configuration out of the XML format and into Java where you can better benefit from refactoring and type safety.

Solution

You can use Java Config, a project which has been in incubation since early 2005 long before Google Guice hit the scene—and has recently been folded into the core framework.

How It Works

The Java Config support is powerful and represents a radically different way of doing things compared with the other configuration options, via XML or annotations. It is important to remember that the Java Config support can be used in tandem with the existing approaches. The simplest way to bootstrap Java configuration is with a plain vanilla XML configuration file. From there, Spring will take care of the rest.

ClassPathXmlApplicationContext classPathXmlApplicationContext =
    new ClassPathXmlApplicationContext("myApplicationContext.xml");

The configuration for that file looks the same as you'd expect:

...
 <context:annotation-config />
 <context:component-scan base-package="com.my.base.package" />
...

This will let Spring find any classes marked with @Configuration. @Configuration is metaannotated with @Component, which makes it eligible for annotation support. This means that it will honor injection using @Autowired, for example. Once your class is annotated with @Configuration, Spring will look for bean definitions in the class. (Bean definitions are Java methods annotated with @Bean.) Any definition is contributed to the ApplicationContext and takes its beanName from the method used to configure it. Alternatively, you can explicitly specify the bean name in the @Bean annotation. A configuration with one bean definition might look like this:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class PersonConfiguration {
        @Bean
        public Person josh() {
                      Person josh = new Person();
                      josh.setName("Josh");
                      return josh ;
           }
}

This is equivalent to an XML application context with the following definition:

<bean id="josh" class="com.apress.springrecipes.
How It Works
spring3.javaconfig.Person" p:name="Josh" />

You can access the bean from your Spring application context just as you would normally:

ApplicationContext context =  ... ;
Person person = context.getBean("josh", Person.class);

If you want to specify the id of the bean, you can do so by using the @Bean definitions id attribute:

@Bean(name="theArtistFormerlyKnownAsJosh")
        public Person josh() {
        //  ...
        }

You can access this bean as follows:

ApplicationContext context =  ... ;
Person person = context.getBean("theArtistFormerlyKnownAsJosh", Person.class);

Now, I know what you're thinking: how is that an improvement? It's five times more lines of code! But you mustn't dismiss the inherent readability of the Java example. Also, if the example compiles, you can be reasonably sure that your configuration was correct. The XML example doesn't afford you any of those benefits.

If you want to specify life cycle methods, you have choices. Life cycle methods in Spring were formerly implemented as callbacks against known interfaces, like InitializingBean and DisposableBean, which gets a callback after dependencies have been injected (public void afterPropertiesSet() throws Exception), and before the bean is destroyed and removed from the context (public void destroy() throws Exception), respectively. You may also configure the initialization and destruction methods manually in the XML configuration, using the init-method and destroy-method attributes of the bean xml element. Since Spring 2.5, you can also use JSR-250 annotations to designate methods as an initialization (@PostConstruct) and destruction method (@PreDestroy). In Java Config, you have options!

You can specify the life cycle methods using the @Bean annotation, or you can simply call the method yourself! The first option, using the initMethod and destroyMethod attributes, is straightforward:

@Bean(  initMethod = "startLife", destroyMethod = "die")
           public Person companyLawyer() {
                      Person companyLawyer = new Person();
                      companyLawyer.setName("Alan Crane");
                      return companyLawyer;
           }

However, you can readily handle initialization on your own, too:

@Bean
public Person companyLawyer() {
     Person companyLawyer = new Person();
     companyLawyer.startLife() ;
     companyLawyer.setName("Alan Crane");
     return companyLawyer;
}

Referencing other beans is as simple and very similar:

@Configuration
public class PetConfiguration {
        @Bean
        public Cat cat(){
          return new Cat();
        }

        @Bean
        public Person master(){
         Person person = new Person() ;
         person.setPet( cat() );
         return person;
        }
// ...
}

It just doesn't get any easier than that: if you need a reference to another bean, simply obtain the reference to the other bean just as you would in any other Java application. Spring will ensure that the bean is instantiated only once and that scope rules are applied if relevant.

The full gamut of configuration options for beans defined in XML is available to beans defined via Java Config.

The @Lazy, @Primary, and @DependsOn annotations work exactly like their XML counterparts. @Lazy defers construction of the bean until it's required to satisfy a dependency or it's explicitly accessed from the application context. @DependsOn specifies that the creation of a bean must come after the creation of some other bean, whose existence might be crucial to the correct creation of the bean. @Primary specifies that the bean on whose definition the annotation is placed is the one that should be returned when there are multiple beans of the same interface. Naturally, if you access beans by name from the container, this makes less sense.

The annotations sit above the bean configuration method to which it applies, like the other annotations. Here's an example:

@Bean @Lazy
public NetworkFileProcessor fileProcessor(){ ... }

Often, you'll want to partition your bean configuration into multiple configuration classes, which leaves things more maintainable and modular. Pursuant to that, Spring lets you import other beans. In XML, you do this using the import element (<import resource="someOtherElement.xml" />). In JavaConfig, similar functionality is available through the @Import annotation, which you place at the class level.

@Configuration
@Import(BusinessConfiguration.class)
public class FamilyConfiguration {
// ...
}

This has the effect of bringing into scope the beans defined in the BusinessConfiguration. From there, you can get access to the beans simply by using @Autowired or @Value if you want. If you inject the ApplicationContext using @Autowired, you can use it to obtain access to a bean. Here, the container imports the beans defined from the AttorneyConfiguration configuration class and then lets you inject them by name using the @Value annotation. Had there been only one instance of that type, you could have used @Autowired.

package com.apress.springrecipes.spring3.javaconfig;

import static java.lang.System.*;

import java.util.Arrays;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.support.ClassPathXmlApplicationContext;

@Configuration
@Import(AttorneyConfiguration.class)
public class LawFirmConfiguration {

           @Value("#{denny}")
           private Attorney denny;

           @Value("#{alan}")
           private Attorney alan;
@Value("#{shirley}")
           private Attorney shirley;

           @Bean
           public LawFirm bostonLegal() {
                      LawFirm lawFirm = new LawFirm();
                      lawFirm.setLawyers(Arrays.asList(denny, alan, shirley));
                      lawFirm.setLocation("Boston");
                      return lawFirm;
           }
}

This functionality is often overkill for defining simple beans. For example, if you want to simply let Spring instantiate the bean, and you don't have anything to contribute to that process, you can either write an @Bean method, or you can fall back and configure it in XML. Which you do is up to you, as a matter of taste. If it were an object specific to my application, I'd handle it in the Java configuration, but I would leave Spring's many FactoryBean implementations inside the XML where they could be made quick work of and where I could benefit from some of the schemas.

Making Beans Aware of the Container

Problem

A well-designed component should not have direct dependencies on its container. However, sometimes it's necessary for your beans to be aware of the container's resources.

Solution

Your beans can be aware of the Spring IoC container's resources by implementing certain "aware" interfaces, as shown in Table 2-3. Spring will inject the corresponding resources to your beans via the setter methods defined in these interfaces.

Table 2.3. Common Aware Interfaces in Spring

Aware Interface

Target Resource

BeanNameAware

The bean name of its instances configured in the IoC container

BeanFactoryAware

The current bean factory, through which you can invoke the container's services

ApplicationContextAware[a]

The current application context, through which you can invoke the container's services

MessageSourceAware

A message source, through which you can resolve text messages

ApplicationEventPublisherAware

An application event publisher, through which you can publish application events

ResourceLoaderAware

A resource loader, through which you can load external resources

[a] In fact, the ApplicationContext interface extends the MessageSource, ApplicationEventPublisher, and ResourceLoader interfaces, so you only need to be aware of the application context to access all these services. However, the best practice is to choose an aware interface with minimum scope that can satisfy your requirement.

The setter methods in the aware interfaces will be called by Spring after the bean properties have been set, but before the initialization callback methods are called, as illustrated in the following list:

  1. Create the bean instance either by a constructor or by a factory method.

  2. Set the values and bean references to the bean properties.

  3. Call the setter methods defined in the aware interfaces.

  4. Call the initialization callback methods.

  5. The bean is ready to be used.

  6. When the container is shut down, call the destruction callback methods.

Keep in mind that once your beans implement the aware interfaces, they are bound to Spring and may not work properly outside the Spring IoC container. You must consider carefully whether it's necessary to implement such proprietary interfaces.

How It Works

For example, you can make your cashier bean aware of its bean name in the IoC container by implementing the BeanNameAware interface. When this bean name is injected, you can save it as the cashier name. This can save you the trouble of setting another name property for the cashier.

package com.apress.springrecipes.shop;
...
import org.springframework.beans.factory.BeanNameAware;

public class Cashier implements BeanNameAware {
    ...
    public void setBeanName(String beanName) {
        this.name = beanName;
    }
}

You can simplify your cashier bean declaration by using the bean name as the cashier name. In this way, you can erase the configuration of the name property and perhaps the setName() method as well.

<bean id="cashier1" class="com.apress.springrecipes.shop.Cashier">
    <property name="path" value="c:/cashier" />
</bean>

Note

Do you remember that you can specify the field name and the property path as the bean names of FieldRetrievingFactoryBean and PropertyPathFactoryBean directly? In fact, both factory beans implement the BeanNameAware interface.

Loading External Resources

Problem

Sometimes, your application may need to read external resources (e.g., text files, XML files, properties file, or image files) from different locations (e.g., a file system, classpath, or URL). Usually, you have to deal with different APIs for loading resources from different locations.

Solution

Spring's resource loader provides a unified getResource() method for you to retrieve an external resource by a resource path. You can specify different prefixes for this path to load resources from different locations. To load a resource from a file system, you use the file prefix. To load a resource from the classpath, you use the classpath prefix. You may also specify a URL in this resource path.

Resource is a general interface in Spring for representing an external resource. Spring provides several implementations for the Resource interface. The resource loader's getResource() method will decide which Resource implementation to instantiate according to the resource path.

How It Works

Suppose you want to display a banner at the startup of your shop application. The banner is made up of the following characters and stored in a text file called banner.txt. This file can be put in the current path of your application.

*************************
*  Welcome to My Shop!  *
*************************

Next, you have to write the BannerLoader class to load the banner and output it to the console. Because it requires access to a resource loader for loading the resource, it has to implement either the ApplicationContextAware interface or the ResourceLoaderAware interface.

package com.apress.springrecipes.shop;
...
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

public class BannerLoader implements ResourceLoaderAware {

    private ResourceLoader resourceLoader;

    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    public void showBanner() throws IOException {
        Resource banner = resourceLoader.getResource("file:banner.txt");
        InputStream in = banner.getInputStream();

        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
        while (true) {
            String line = reader.readLine();
            if (line == null)
                break;
            System.out.println(line);
        }
        reader.close();
    }
}

By calling the getResource() method from the application context, you can retrieve an external resource specified by a resource path. Because your banner file is located in the file system, the resource path should start with the file prefix. You can call the getInputStream() method to retrieve the input stream for this resource. Then, you read the file contents line by line with BufferedReader and output them to the console.

Finally, you declare a BannerLoader instance in the bean configuration file to display the banner. Because you want to show the banner at startup, you specify the showBanner() method as the initialization method.

<bean id="bannerLoader"
    class="com.apress.springrecipes.shop.BannerLoader"
    init-method="showBanner" />

Resource Prefixes

The previous resource path specifies a resource in the relative path of the file system. You can specify an absolute path as well.

file:c:/shop/banner.txt

When your resource is located in the classpath, you have to use the classpath prefix. If there's no path information presented, it will be loaded from the root of the classpath.

classpath:banner.txt

If the resource is located in a particular package, you can specify the absolute path from the classpath root.

classpath:com/apress/springrecipes/shop/banner.txt

Besides a file system path or the classpath, a resource can also be loaded by specifying a URL.

http://springrecipes.apress.com/shop/banner.txt

If there's no prefix presented in the resource path, the resource will be loaded from a location according to the application context. For FileSystemXmlApplicationContext, the resource will be loaded from the file system. For ClassPathXmlApplicationContext, it will be loaded from the classpath.

Injecting Resources

In addition to calling the getResource() method to load a resource explicitly, you can inject it by using a setter method:

package com.apress.springrecipes.shop;
...
import org.springframework.core.io.Resource;

public class BannerLoader {

    private Resource banner;

    public void setBanner(Resource banner) {
        this.banner = banner;
    }
public void showBanner() throws IOException {
        InputStream in = banner.getInputStream();
        ...
    }
}

In the bean configuration, you can simply specify the resource path for this Resource property. Spring will use the preregistered property editor ResourceEditor to convert it into a Resource object before injecting it into your bean.

<bean id="bannerLoader"
    class="com.apress.springrecipes.shop.BannerLoader"
    init-method="showBanner">
    <property name="banner">
        <value>classpath:com/apress/springrecipes/shop/banner.txt</value>
    </property>
</bean>

Creating Bean Post Processors

Problem

You would like to register your own plug-ins in the Spring IoC container to process the bean instances during construction.

Solution

A bean post processor allows additional bean processing before and after the initialization callback method. The main characteristic of a bean post processor is that it will process all the bean instances in the IoC container one by one, not just a single bean instance. Typically, bean post processors are used for checking the validity of bean properties or altering bean properties according to particular criteria.

The basic requirement of a bean post processor is to implement the BeanPostProcessor interface. You can process every bean before and after the initialization callback method by implementing the postProcessBeforeInitialization() and postProcessAfterInitialization() methods. Then Spring will pass each bean instance to these two methods before and after calling the initialization callback method, as illustrated in the following list:

  1. Create the bean instance either by a constructor or by a factory method.

  2. Set the values and bean references to the bean properties.

  3. Call the setter methods defined in the aware interfaces.

  4. Pass the bean instance to the postProcessBeforeInitialization() method of each bean post processor.

  5. Call the initialization callback methods.

  6. Pass the bean instance to the postProcessAfterInitialization() method of each bean post processor.

  7. The bean is ready to be used.

  8. When the container is shut down, call the destruction callback methods.

When using a bean factory as your IoC container, bean post processors can only be registered programmatically, or more accurately, via the addBeanPostProcessor() method. However, if you are using an application context, the registration will be as simple as declaring an instance of the processor in the bean configuration file, and then it will get registered automatically.

How It Works

Suppose you would like to ensure that the logging path of Cashier exists before the logging file is open. This is to avoid FileNotFoundException. As this is a common requirement for all components that require storage in the file system, you had better implement it in a general and reusable manner. A bean post processor is an ideal choice to implement such a feature in Spring.

First of all, for the bean post processor to distinguish which beans should be checked, you create a marker interface, StorageConfig, for your target beans to implement. Moreover, for your bean post processor to check for path existence, it must be able to access the path property. This can be done by adding the getPath() method to this interface.

package com.apress.springrecipes.shop;

public interface StorageConfig {

    public String getPath();
}

Next, you should make the Cashier class implement this marker interface. Your bean post processor will only check the beans that implement this interface.

package com.apress.springrecipes.shop;
...
public class Cashier implements BeanNameAware, StorageConfig {
    ...
    public String getPath() {
        return path;
    }
}

Now, you are ready to write a bean post processor for path checking. As the best time to perform path checking is before the file is opened in the initialization method, you implement the postProcessBeforeInitialization() method to perform the checking.

package com.apress.springrecipes.shop;
...
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class PathCheckingBeanPostProcessor implements BeanPostProcessor {

    public Object postProcessBeforeInitialization(Object bean, String beanName)
            throws BeansException {
        if (bean instanceof StorageConfig) {
            String path = ((StorageConfig) bean).getPath();
            File file = new File(path);
            if (!file.exists()) {
                file.mkdirs();
            }
        }
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        return bean;
    }
}

During bean construction, the Spring IoC container will pass all the bean instances to your bean post processor one by one, so you must filter the beans by checking the marker interface StoreConfig. If a bean implements this interface, you can access its path property by the getPath() method and check for its existence in the file system. If that path doesn't exist, just create it with the File.mkdirs() method.

Both the postProcessBeforeInitialization() and postProcessAfterInitialization() methods must return an instance for the bean being processed. That means you may even replace the original bean instance with a brand-new instance in your bean post processor. Remember that you must return the original bean instance even though you do nothing in the method.

To register a bean post processor in an application context, just declare an instance of it in the bean configuration file. The application context will be able to detect which bean implements the BeanPostProcessor interface and register it to process all other bean instances in the container.

<beans ...>
    ...
    <bean class="com.apress.springrecipes.shop.PathCheckingBeanPostProcessor" />

    <bean id="cashier1" class="com.apress.springrecipes.shop.Cashier"
        init-method="openFile" destroy-method="closeFile">
        ...
    </bean>
</beans>

Note that if you specify the initialization callback method in the init-method attribute, or if you implement the InitializingBean interface, your PathCheckingBeanPostProcessor will work fine because it will process the cashier bean before the initialization method is called.

However, if the cashier bean relies on the JSR-250 annotations @PostConstruct and @PreDestroy, and also a CommonAnnotationBeanPostProcessor instance to call the initialization method, your PathCheckingBeanPostProcessor will not work properly. This is because your bean post processor has a lower priority than CommonAnnotationBeanPostProcessor by default. As a result, the initialization method will be called before your path checking.

<beans ...>
    ...
    <bean class="org.springframework.context.annotation.
How It Works
CommonAnnotationBeanPostProcessor" /> <bean class="com.apress.springrecipes.shop.PathCheckingBeanPostProcessor" /> <bean id="cashier1" class="com.apress.springrecipes.shop.Cashier"> ... </bean> </beans>

To define the processing order of bean post processors, you can have them implement the Ordered or PriorityOrdered interface and return their order in the getOrder() method. The lower value returned by this method represents higher priority, and the order value returned by the PriorityOrdered interface will always precede that returned by the Ordered interface.

As CommonAnnotationBeanPostProcessor implements the PriorityOrdered interface, your PathCheckingBeanPostProcessor must also implement this interface to have a chance to precede it.

package com.apress.springrecipes.shop;
...
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.PriorityOrdered;

public class PathCheckingBeanPostProcessor implements BeanPostProcessor,
        PriorityOrdered {

    private int order;

    public int getOrder() {
        return order;
    }

    public void setOrder(int order) {
        this.order = order;
    }
    ...
}

Now, in the bean configuration file, you should assign a lower order value to your PathCheckingBeanPostProcessor for it to check and create the path of the cashier bean before its initialization method is called by CommonAnnotationBeanPostProcessor. As the default order of CommonAnnotationBeanPostProcessor is Ordered.LOWEST_PRECEDENCE, you can simply assign a zero order value to your PathCheckingBeanPostProcessor.

<beans ...>
    ...
    <bean class="org.springframework.context.annotation.
How It Works
CommonAnnotationBeanPostProcessor" />
<bean class="com.apress.springrecipes.shop.PathCheckingBeanPostProcessor">
        <property name="order" value="0" />
    </bean>

    <bean id="cashier1" class="com.apress.springrecipes.shop.Cashier">
        <property name="path" value="c:/cashier" />
    </bean>
</beans>

As zero is the default order value of your PathCheckingBeanPostProcessor, you can simply omit this setting. Moreover, you can continue to use <context:annotation-config> to get CommonAnnotationBeanPostProcessor registered automatically.

<beans ...>
    ...
    <context:annotation-config />

    <bean class="com.apress.springrecipes.shop.PathCheckingBeanPostProcessor" />
</beans>

Externalizing Bean Configurations

Problem

When configuring beans in the configuration file, you must remember that it's not a good practice to mix deployment details, such as the file path, server address, username, and password, with your bean configurations. Usually, the bean configurations are written by application developers while the deployment details are matters for the deployers or system administrators.

Solution

Spring comes with a bean factory post processor called PropertyPlaceholderConfigurer for you to externalize part of the bean configurations into a properties file. You can use variables of the form ${var} in your bean configuration file and PropertyPlaceholderConfigurer will load the properties from a properties file and use them to replace the variables.

A bean factory post processor differs from a bean post processor in that its target is the IoC container—either the bean factory or the application context—not the bean instances. It will take effect on the IoC container after it loads the bean configurations but before any of the bean instances are created. The typical usage of a bean factory post processor is to alter the bean configurations before the beans are instantiated. Spring comes with several bean factory post processors for you to use. In practice, you seldom need to write your own bean factory post processors.

How It Works

Previously, you specified the logging path for a cashier in the bean configuration file. It is not a good practice to mix such deployment details with your bean configurations. A better approach is to extract the deployment details into a properties file, such as config.properties, in the root of the classpath. Then, define the logging path in this file.

cashier.path=c:/cashier

Now, you can use variables of the form ${var} in your bean configuration file. To load the external properties from a properties file and use them to replace the variables, you have to register the bean factory post processor PropertyPlaceholderConfigurer in your application context. You can specify either one properties file in the location property or multiple properties files in the locations property.

<beans ...>
    ...
    <bean class="org.springframework.beans.factory.config.
How It Works
PropertyPlaceholderConfigurer"> <property name="location"> <value>config.properties</value> </property> </bean> <bean id="cashier1" class="com.apress.springrecipes.shop.Cashier"> <property name="path" value="${cashier.path}" /> </bean> </beans>

Implemented as a bean factory post processor, PropertyPlaceholderConfigurer will replace the variables in your bean configuration file with the external properties before your beans get instantiated.

In Spring 2.5 or later, the registration of PropertyPlaceholderConfigurer can be simply through the <context:property-placeholder> element.

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

    <context:property-placeholder location="config.properties" />
    ...
</beans>

Resolving Text Messages

Problem

For an application to support internationalization (I18N for short, as there are 18 characters between the first character, "i," and the last character, "n"), it requires the capability of resolving text messages for different locales.

Solution

Spring's application context is able to resolve text messages for a target locale by their keys. Typically, the messages for one locale should be stored in one separate properties file. This properties file is called a resource bundle.

MessageSource is an interface that defines several methods for resolving messages. The ApplicationContext interface extends this interface so that all application contexts are able to resolve text messages. An application context delegates the message resolution to a bean with the exact name messageSource. ResourceBundleMessageSource is the most common MessageSource implementation that resolves messages from resource bundles for different locales.

How It Works

As an example, you can create the following resource bundle, messages_en_US.properties, for the English language in the United States. Resource bundles will be loaded from the root of the classpath.

alert.checkout=A shopping cart has been checked out.

To resolve messages from resource bundles, you use ResourceBundleMessageSource as your MessageSource implementation. This bean's name must be set to messageSource for the application context to detect it. You have to specify the base name of the resource bundles for ResourceBundleMessageSource.

<beans ...>
    ...
    <bean id="messageSource"
        class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basename">
            <value>messages</value>
        </property>
    </bean>
</beans>

For this MessageSource definition, if you look up a text message for the United States locale, whose preferred language is English, the resource bundle messages_en_US.properties, which matches both the language and country, will be considered first. If there's no such resource bundle or the message can't be found, the one messages_en.properties that matches the language only will be considered. If this resource bundle still can't be found, the default messages.properties for all locales will be chosen finally. For more information on resource bundle loading, you can refer to the Javadoc of the java.util.ResourceBundle class.

Now, you can ask the application context to resolve a message by the getMessage() method. The first argument is the key corresponding to the message, and the third is the target locale.

package com.apress.springrecipes.shop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
public class Main {

    public static void main(String[] args) throws Exception {
        ApplicationContext context =
            new FileSystemXmlApplicationContext("beans.xml");
        ...
        String alert = context.getMessage("alert.checkout", null, Locale.US);
        System.out.println(alert);
    }
}

The second argument of the getMessage() method is an array of message parameters. In the text message, you can define multiple parameters by index:

alert.checkout=A shopping cart costing {0} dollars has been checked out at {1}.

You have to pass in an object array to fill in the message parameters. The elements in this array will be converted into strings before filling in the parameters.

package com.apress.springrecipes.shop;
...
public class Main {

    public static void main(String[] args) throws Exception {
        ...
        String alert = context.getMessage("alert.checkout",
                new Object[] { 4, new Date() }, Locale.US);
        System.out.println(alert);
    }
}

In the Main class, you can resolve text messages because you can access the application context directly. But for a bean to resolve text messages, it has to implement either the ApplicationContextAware interface or the MessageSourceAware interface. Now, you can delete the message resolution from the Main class.

package com.apress.springrecipes.shop;
...
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;

public class Cashier implements BeanNameAware, MessageSourceAware,
        StorageConfig {
    ...
    private MessageSource messageSource;

    public void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }
public void checkout(ShoppingCart cart) throws IOException {
        ...
        String alert = messageSource.getMessage("alert.checkout",
                new Object[] { total, new Date() }, Locale.US);
        System.out.println(alert);
    }
}

Communicating with Application Events

Problem

In the typical communication model between components, the sender has to locate the receiver to call a method on it. In this case, the sender component must be aware of the receiver component. This kind of communication is direct and simple, but the sender and receiver components are tightly coupled.

When using an IoC container, your components can communicate by interface rather than by implementation. This communication model can help reduce coupling. However, it is only efficient when a sender component has to communicate with one receiver. When a sender needs to communicate with multiple receivers, it has to call the receivers one by one.

Solution

Spring's application context supports event-based communication between its beans. In the event-based communication model, the sender component just publishes an event without knowing who the receiver will be. Actually, there may be more than one receiver component. Also, the receiver needn't know who is publishing the event. It can listen to multiple events from different senders at the same time. In this way, the sender and receiver components are loosely coupled.

In Spring, all event classes must extend the ApplicationEvent class. In that case, any bean can publish an event by calling an application event publisher's publishEvent() method. For a bean to listen to certain events, it must implement the ApplicationListener interface and handle the events in the onApplicationEvent() method. Actually, Spring will notify a listener of all events, so you must filter the events by yourself. If you use exploit generics, however, Spring will deliver only messages that match the generic type parameter.

How It Works

Defining Events

The first step of enabling event-based communication is to define the event. Suppose you would like your cashier bean to publish a CheckoutEvent after the shopping cart has been checked out. This event includes two properties: the payment amount and the checkout time. In Spring, all events must extend the abstract class ApplicationEvent and pass the event source as a constructor argument.

package com.apress.springrecipes.shop;
...
import org.springframework.context.ApplicationEvent;

public class CheckoutEvent extends ApplicationEvent {

    private double amount;
    private Date time;

    public CheckoutEvent(Object source, double amount, Date time) {
        super(source);
        this.amount = amount;
        this.time = time;
    }

    public double getAmount() {
        return amount;
    }

    public Date getTime() {
        return time;
    }
}

Publishing Events

To publish an event, you just create an event instance and make a call to the publishEvent() method of an application event publisher, which can be accessed by implementing the ApplicationEventPublisherAware interface.

package com.apress.springrecipes.shop;
...
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;

public class Cashier implements BeanNameAware, MessageSourceAware,
        ApplicationEventPublisherAware, StorageConfig {
    ...
    private ApplicationEventPublisher applicationEventPublisher;

    public void setApplicationEventPublisher(
            ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
public void checkout(ShoppingCart cart) throws IOException {
        ...
        CheckoutEvent event = new CheckoutEvent(this, total, new Date());
        applicationEventPublisher.publishEvent(event);
    }
}

Listening to Events

Any bean defined in the application context that implements the ApplicationListener interface will be notified of all events. So in the onApplicationEvent() method, you have to filter the events that your listener wants to handle. In the following listener, suppose you would like to send an e-mail to notify the customer about the checkout. Here, we use an instanceof check to filter on the nongeneric ApplicationEvent parameter.

package com.apress.springrecipes.shop;
...
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public class CheckoutListener implements ApplicationListener {

    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof CheckoutEvent) {
            double amount = ((CheckoutEvent) event).getAmount();
            Date time = ((CheckoutEvent) event).getTime();

            // Do anything you like with the checkout amount and time
            System.out.println("Checkout event [" + amount + ", " + time + "]");
        }
    }
}

Rewritten to take advantage of the generics functionality, it's a bit briefer:

package com.apress.springrecipes.shop;
...
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;

public class CheckoutListener implements ApplicationListener<CheckoutEvent> {

    public void onApplicationEvent(CheckoutEvent event) {
            double amount = ((CheckoutEvent) event).getAmount();
            Date time = ((CheckoutEvent) event).getTime();

            // Do anything you like with the checkout amount and time
            System.out.println("Checkout event [" + amount + ", " + time + "]");
     }
}

Next, you have to register this listener in the application context to listen for all events. The registration is as simple as declaring a bean instance of this listener. The application context will recognize the beans that implement the ApplicationListener interface and notify them of each event.

<beans ...>
    ...
    <bean class="com.apress.springrecipes.shop.CheckoutListener" />
</beans>

Finally, notice that the application context itself will also publish container events such as ContextClosedEvent, ContextRefreshedEvent, and RequestHandledEvent. If any of your beans want to be notified of these events, they can implement the ApplicationListener interface.

Registering Property Editors in Spring

Problem

A property editor is a feature of the JavaBeans API for converting property values to and from text values. Each property editor is designed for a certain type of property only. You may wish to employ property editors to simplify your bean configurations.

Solution

The Spring IoC container supports using property editors to help with bean configurations. For example, with a property editor for the java.net.URL type, you can specify a URL string for a property of the URL type. Spring will automatically convert the URL string into a URL object and inject it into your property. Spring comes with several property editors for converting bean properties of common types.

Typically, you should register a property editor in the Spring IoC container before it can be used. The CustomEditorConfigurer is implemented as a bean factory post processor for you to register your custom property editors before any of the beans get instantiated.

How It Works

As an example, suppose you would like your product ranking to be based on sales for a particular period. For this change, you add the fromDate and toDate properties to your ProductRanking class.

package com.apress.springrecipes.shop;
...
public class ProductRanking {

    private Product bestSeller;
    private Date fromDate;
    private Date toDate;
// Getters and Setters
    ...
}

To specify the value for a java.util.Date property in a Java program, you can convert it from a date string of particular pattern with the help of the DateFormat.parse() method.

DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
productRanking.setFromDate(dateFormat.parse("2007-09-01"));
productRanking.setToDate(dateFormat.parse("2007-09-30"));

To write the equivalent bean configuration in Spring, you first declare a dateFormat bean with the pattern configured. As the parse() method is called for converting the date strings into date objects, you can consider it as an instance factory method to create the date beans.

<beans ...>
    ...
    <bean id="dateFormat" class="java.text.SimpleDateFormat">
        <constructor-arg value="yyyy-MM-dd" />
    </bean>

    <bean id="productRanking"
        class="com.apress.springrecipes.shop.ProductRanking">
        <property name="bestSeller">
            <bean class="com.apress.springrecipes.shop.Disc">
                <property name="name" value="CD-RW" />
                <property name="price" value="1.5" />
            </bean>
        </property>
        <property name="fromDate">
            <bean factory-bean="dateFormat" factory-method="parse">
                <constructor-arg value="2007-09-01" />
            </bean>
        </property>
        <property name="toDate">
            <bean factory-bean="dateFormat" factory-method="parse">
                <constructor-arg value="2007-09-30" />
            </bean>
        </property>
    </bean>
</beans>

As you can see, the preceding configuration is too complicated for setting date properties. Actually, the Spring IoC container is able to convert the text values for your properties by using property editors. The CustomDateEditor class that comes with Spring is for converting date strings into java.util.Date properties. First, you have to declare an instance of it in the bean configuration file.

<beans ...>
    ...
    <bean id="dateEditor"
        class="org.springframework.beans.propertyeditors.CustomDateEditor">
        <constructor-arg>
            <bean class="java.text.SimpleDateFormat">
                <constructor-arg value="yyyy-MM-dd" />
            </bean>
        </constructor-arg>
        <constructor-arg value="true" />
    </bean>
</beans>

This editor requires a DateFormat object as the first constructor argument. The second argument indicates whether this editor allows empty values.

Next, you have to register this property editor in a CustomEditorConfigurer instance so that Spring can convert properties whose type is java.util.Date. Now, you can specify a date value in text format for any java.util.Date properties:

<beans ...>
    ...
    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>
                <entry key="java.util.Date">
                    <ref local="dateEditor" />
                </entry>
            </map>
        </property>
    </bean>

    <bean id="productRanking"
        class="com.apress.springrecipes.shop.ProductRanking">
        <property name="bestSeller">
            <bean class="com.apress.springrecipes.shop.Disc">
                <property name="name" value="CD-RW" />
                <property name="price" value="1.5" />
            </bean>
        </property>
        <property name="fromDate" value="2007-09-01" />
        <property name="toDate" value="2007-09-30" />
    </bean>
</beans>

You can test whether your CustomDateEditor configuration works with the following Main class:

package com.apress.springrecipes.shop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {

    public static void main(String[] args) throws Exception {
        ApplicationContext context =
            new ClassPathXmlApplicationContext("beans.xml");
        ...
        ProductRanking productRanking =
            (ProductRanking) context.getBean("productRanking");
        System.out.println(
                "Product ranking from " + productRanking.getFromDate() +
                " to " + productRanking.getToDate());
    }
}

In addition to CustomDateEditor, Spring comes with several property editors for converting common data types, such as CustomNumberEditor, ClassEditor, FileEditor, LocaleEditor, StringArrayPropertyEditor, and URLEditor. Among them, ClassEditor, FileEditor, LocaleEditor, and URLEditor are preregistered by Spring, so you don't need to register them again. For more information on using these editors, you can consult the Javadoc of these classes in the org.springframework.beans.propertyeditors package.

Creating Custom Property Editors

Problem

In addition to registering the built-in property editors, you may want to write your own custom property editors for converting your custom data types.

Solution

You can write custom property editors by implementing the java.beans.PropertyEditor interface or extending the convenient support class java.beans.PropertyEditorSupport.

How It Works

For example, let's write a property editor for the Product class. You can design the string representation of a product as three parts, which are the concrete class name, the product name, and the price. Each part is separated by a comma. Then, you can write the following ProductEditor class for converting them:

package com.apress.springrecipes.shop;

import java.beans.PropertyEditorSupport;

public class ProductEditor extends PropertyEditorSupport {

    public String getAsText() {
        Product product = (Product) getValue();
        return product.getClass().getName() + "," + product.getName() + ","
                + product.getPrice();
    }

    public void setAsText(String text) throws IllegalArgumentException {
        String[] parts = text.split(",");
        try {
            Product product = (Product) Class.forName(parts[0]).newInstance();
            product.setName(parts[1]);
            product.setPrice(Double.parseDouble(parts[2]));
            setValue(product);
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
    }
}

The getAsText() method converts a property into a string value, while the setAsText() method converts a string back into a property. The property value is retrieved and set by calling the getValue() and setValue() methods.

Next, you have to register your custom editor in a CustomEditorConfigurer instance before it can be used. Registration is the same as for the built-in editors. Now, you can specify a product in text format for any property whose type is Product.

<beans ...>
    ...
    <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
        <property name="customEditors">
            <map>
                ...
                <entry key="com.apress.springrecipes.shop.Product">
                    <bean class="com.apress.springrecipes.shop.ProductEditor" />
                </entry>
            </map>
        </property>
    </bean>
<bean id="productRanking"
        class="com.apress.springrecipes.shop.ProductRanking">
        <property name="bestSeller">
            <value>com.apress.springrecipes.shop.Disc,CD-RW,1.5</value>
        </property>
        ...
    </bean>
</beans>

In fact, the JavaBeans API will automatically search a property editor for a class. For a property editor to be searched correctly, it must be located in the same package as the target class, and the name must be the target class name with Editor as its suffix. If your property editor is provided in this convention, such as in the preceding ProductEditor, there's no need to register it again in the Spring IoC container.

Concurrency with TaskExecutors

Problem

Options for building threaded, concurrent programs are myriad, but there's no standard approach. What's more, building such programs tends to involve creating lots of utility classes to support common use cases.

Solution

Use Spring's TaskExecutor abstraction. This abstraction provides numerous implementations for many environments, including basic Java SE Executor implementations, The CommonJ WorkManager implementations, and custom implementations. In Spring 3.0, all the implementations are unified and can be cast to Java SE's Executor interface, too.

How It Works

Threading is a difficult issue, and several difficult use cases remain unapproachable without a sizable amount of effort; others are at least very tedious to implement using standard threading in the Java SE environment. Concurrency is an important aspect of architectures when implementing server-side components and enjoys no standardization in the Java EE space. In fact, it's quite the contrary: some parts of the Java EE specifications forbid the explicit creation and manipulation of threads!

Java SE

In the Java SE landscape, myriad options have been introduced over the years. First, there's the standard java.lang.Thread support present since day one and Java Development Kit (JDK) 1.0. Java 1.3 saw the introduction of java.util.TimerTask to support doing some sort of work periodically. Java 5 debuted the java.util.concurrent package as well as a reworked hierarchy for building thread pools, oriented around the java.util.concurrent.Executor.

The application programming interface (API) for Executor is simple:

package java.util.concurrent;
public interface Executor {
    void execute(Runnable command);
}

ExecutorService, a subinterface, provides more functionality for managing threads and providing support for raising events to the threads, such as shutdown(). There are several implementations that have shipped with the JDK since Java SE 5.0. Many of them are available via static factory methods on the java.util.concurrent.Executors class, in much the same way that utility methods for manipulating java.util.Collection instances are offered on the java.util.Collections class. What follows are examples. ExecutorService also provides a submit() method, which returns a Future<T>. An instance of Future<T> can be used to track the progress of a thread that's executing—usually asynchronously. You can call Future.isDone() or Future.isCancelled() to determine whether the job is finished or cancelled, respectively. When you use the ExecutorService and submit() a Runnable, whose run method has no return type, calling get() on the returned Future will return null, or the value you specified on submission:

Runnable task = new Runnable(){
  public void run(){
    try{
        Thread.sleep( 1000 * 60 ) ;
        System.out.println("Done sleeping for a minute, returning! " );
    } catch (Exception ex) { /* ... */ }
  }
};
ExecutorService executorService  = Executors.newCachedThreadPool() ;
if(executorService.submit(task, Boolean.TRUE).get().equals( Boolean.TRUE ))
     System.out.println( "Job has finished!");

With that in hand, you can explore some the characteristics of the various implementations. For example, you'll use the following Runnable instance:

package com.apress.springrecipes.spring3.executors;

import java.util.Date;
import org.apache.commons.lang.exception.ExceptionUtils;

public class DemonstrationRunnable implements Runnable {
  public void run() {
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          System.out.println(
                ExceptionUtils.getFullStackTrace(e));
        }
        System.out.println(Thread.currentThread().getName());
        System.out.printf("Hello at %s 
", new Date());
  }
}

The class is designed only to mark the passage of time. You'll use the same instance when you explore Java SE Executors and Spring's TaskExecutor support:

package com.apress.springrecipes.spring3.executors;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ExecutorsDemo {

   public static void main(String[] args) throws Throwable {
      Runnable task = new DemonstrationRunnable();

      // will create a pool of threads and attempt to
      // reuse previously created ones if possible
      ExecutorService cachedThreadPoolExecutorService = Executors
            .newCachedThreadPool();
      if (cachedThreadPoolExecutorService.submit(task).get() == null)
         System.out.printf("The cachedThreadPoolExecutorService "
               + "has succeeded at %s 
", new Date());

      // limits how many new threads are created, queueing the rest
      ExecutorService fixedThreadPool = Executors.newFixedThreadPool(100);
      if (fixedThreadPool.submit(task).get() == null)
         System.out.printf("The fixedThreadPool has " +
               "succeeded at %s 
",
               new Date());

      // doesn't use more than one thread at a time
      ExecutorService singleThreadExecutorService = Executors
            .newSingleThreadExecutor();
      if (singleThreadExecutorService.submit(task).get() == null)
         System.out.printf("The singleThreadExecutorService "
               + "has succeeded at %s 
", new Date());

      // support sending a job with a known result
      ExecutorService es = Executors.newCachedThreadPool();
      if (es.submit(task, Boolean.TRUE).get().equals(Boolean.TRUE))
         System.out.println("Job has finished!");

      // mimic TimerTask
      ScheduledExecutorService scheduledThreadExecutorService = Executors
            .newScheduledThreadPool(10);
      if (scheduledThreadExecutorService.schedule(
            task, 30, TimeUnit.SECONDS).get() == null)
         System.out.printf("The scheduledThreadExecutorService "
               + "has succeeded at %s 
", new Date());
// this doesn't stop until it encounters
      // an exception or its cancel()ed
      scheduledThreadExecutorService.scheduleAtFixedRate(task, 0, 5,
            TimeUnit.SECONDS);

   }
}

If you use the version of the submit() method on the ExecutorService that accepts a Callable<T>, then submit() return whatever was returned from the Callable main method call(). The interface for Callable is as follows:

package java.util.concurrent;

public interface Callable<V> {
     V call() throws Exception;
}

Java EE

In the Java EE landscape, different approaches for solving these sorts of problems have been created, often missing the point. Java EE has offered no threading issue help for a long time.

There are other solutions for these sorts of problems. Quartz (a job scheduling framework) filled the gap by providing a solution that provided scheduling and concurrency. JCA 1.5 (or the J2EE Connector Architecture; the JCA acronym is most used when referring to this technology, even though it was supposed to be the acronym for the Java Cryptography Architecture) is a specification that supports concurrency in that it provides a primitive type of gateway for integration functionality. Components can be notified about incoming messages and respond concurrently. JCA 1.5 provides primitive, limited enterprise service bus—similar to integration features, without nearly as much of the finesse of something like SpringSource's Spring Integration framework. That said, if you had to tie a legacy application written in C to a Java EE application server and let it optionally participate in container services, and wanted to do it in a reasonably portable way before 2006, it worked well.

The requirement for concurrency wasn't lost on application server vendors, though. In 2003, IBM and BEA jointly created the Timer and WorkManager APIs. The APIs eventually became JSR-237, which was subsequently withdrawn and merged with JSR-236 with the focus being on how to implement concurrency in a managed (usually Java EE) environment. JSR-236 is still not final. The Service Data Object (SDO) Specification, JSR-235, also had a similar solution in the works, although it is not final. Both SDO and the WorkManager API were targeted for Java EE 1.4, although they've both progressed independently since. The Timer and WorkManager APIs, also known as the CommonJ WorkManager API, enjoys support on both WebLogic (9.0 or later) and WebSphere (6.0 or later), although they're not necessarily portable. Finally, open source implementations of the CommonJ API have sprung up in recent years.

Confused yet?

The issue is that there's no portable, standard, simple way of controlling threads and providing concurrency for components in a managed environment (or a nonmanaged environment!). Even if the discussion is framed in terms of Java SE–specific solutions, you have an overwhelming plethora of choices to make.

Spring's Solution

In Spring 2.0, a unifying solution was introduced in the org.springframework.core.task.TaskExecutor interface. The TaskExecutor abstraction served all requirements pretty well. Because Spring supported Java 1.4, TaskExecutor didn't implement the java.util.concurrent.Executor interface, introduced in Java 1.5, although its interface was compatible. And any class implementing TaskExecutor could also implement the Executor interface because it defines the exact same method signature. This interface exists even in Spring 3.0 for backward compatibility with JDK 1.4 in Spring 2.x. This meant that people stuck on older JDKs could build applications with this sophisticated functionality without JDK 5. In Spring 3.0, with Java 5 the baseline, the TaskExecutor interface now extends Executor, which means that all the support provided by Spring now works with the core JDK support, too.

The TaskExecutor interface is used quite a bit internally in the Spring framework. For example, the Quartz integration (which has threading, of course) and the message-driven POJO container support make use of TaskExecutor:

// the Spring abstraction
package org.springframework.core.task;

import java.util.concurrent.Executor;

public interface TaskExecutor extends Executor {
  void execute(Runnable task);
}

In some places, the various solutions mirror the functionality provided by the core JDK options. In others, they're quite unique and provide integrations with other frameworks such as with a CommonJ WorkManager. These integrations usually take the form of a class that can exist in the target framework but that you can manipulate just like any other TaskExecutor abstraction. Although there is support for adapting an existing Java SE Executor or ExecutorService as a TaskExecutor, this isn't so important in Spring 3.0 because the base class for TaskExecutor is Executor, anyway. In this way, the TaskExecutor in Spring bridges the gap between various solutions on Java EE and Java SE.

Let's see some of the simple support for the TaskExecutor first, using the same Runnable defined previously. The client for the code is a simple Spring bean, into which you've injected various instances of TaskExecutor with the sole aim of submitting the Runnable:

package com.apress.springrecipes.spring3.executors;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.support.TaskExecutorAdapter;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.timer.TimerTaskExecutor;
public class SpringExecutorsDemo {
           public static void main(String[] args) {
                ClassPathXmlApplicationContext ctx =
                  new ClassPathXmlApplicationContext("context2.xml");
                SpringExecutorsDemo demo = ctx.getBean(
                     "springExecutorsDemo", SpringExecutorsDemo.class);
                demo.submitJobs();
           }

           @Autowired
           private SimpleAsyncTaskExecutor asyncTaskExecutor;

           @Autowired
           private SyncTaskExecutor syncTaskExecutor;

           @Autowired
           private TaskExecutorAdapter taskExecutorAdapter;

           /*  No need, since the scheduling is already configured,
               in the application context
            @Resource(name = "timerTaskExecutorWithScheduledTimerTasks")
           private TimerTaskExecutor timerTaskExecutorWithScheduledTimerTasks;
           */

           @Resource(name = "timerTaskExecutorWithoutScheduledTimerTasks")
           private TimerTaskExecutor timerTaskExecutorWithoutScheduledTimerTasks;

           @Autowired
           private ThreadPoolTaskExecutor threadPoolTaskExecutor;

           @Autowired
           private DemonstrationRunnable task;

           public void submitJobs() {
                    syncTaskExecutor.execute(task);
                    taskExecutorAdapter.submit(task);
                    asyncTaskExecutor.submit(task);

                    timerTaskExecutorWithoutScheduledTimerTasks.submit(task);

                      /* will do 100 at a time,
                             then queue the rest, ie,
                             should take round 5 seconds total
                         */
                    for (int i = 0; i < 500; i++)
                      threadPoolTaskExecutor.submit(task);
           }
}

The application context demonstrates the creation of these various TaskExecutor implementations. Most are so simple that you could create them manually. Only in one case (the timerTaskExecutor) do you delegate to a factory bean:

<?xml version="1.0" encoding="UTF-8"?>
<beans
 xmlns="http://www.springframework.org/schema/beans"
 xmlns:p="http://www.springframework.org/schema/p"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:util="http://www.springframework.org/schema/util"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="
  http://www.springframework.org/schema/context
  http://www.springframework.org/schema/context/spring-context-3.0.xsd
  http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
  http://www.springframework.org/schema/util
  http://www.springframework.org/schema/util/spring-util-3.0.xsd">

 <context:annotation-config />

 <!--  sample Runnable -->
 <bean
  id="task"  class="com.apress.springrecipes.spring3.
Spring's Solution
executors.DemonstrationRunnable" /> <!-- TaskExecutors --> <bean class="org.springframework.core.task.support.TaskExecutorAdapter"> <constructor-arg> <bean class="java.util.concurrent.Executors" factory-method="newCachedThreadPool" /> </constructor-arg> </bean> <bean class="org.springframework.core.task.SimpleAsyncTaskExecutor" p:daemon="false" /> <bean class="org.springframework.core.task.SyncTaskExecutor" /> <bean id="timerTaskExecutorWithScheduledTimerTasks" class="org.springframework.scheduling.timer.TimerTaskExecutor"> <property name="timer"> <bean class="org.springframework.scheduling.timer.TimerFactoryBean"> <property name="scheduledTimerTasks"> <list> <bean class="org.springframework.scheduling.timer.ScheduledTimerTask"
p:delay="10"
       p:fixedRate="true"
       p:period="10000"
       p:runnable-ref="task" />
     </list>
    </property>
   </bean>
  </property>

 </bean>

 <bean
  id="timerTaskExecutorWithoutScheduledTimerTasks"
  class="org.springframework.scheduling.timer.TimerTaskExecutor"
  p:delay="10000" />

 <bean
  class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"
  p:corePoolSize="50"
  p:daemon="false"
  p:waitForTasksToCompleteOnShutdown="true"
  p:maxPoolSize="100"
  p:allowCoreThreadTimeOut="true" />

 <!--  client bean  -->
 <bean
  id="springExecutorsDemo"
  class="com.apress.springrecipes.spring3.
Spring's Solution
executors.SpringExecutorsDemo" /> </beans>

The previous code shows different implementations of the TaskExecutor interface. The first bean, the TaskExecutorAdapter instance, is a simple wrapper around a java.util.concurrence.Executors instance so that you can deal with in terms of the Spring TaskExecutor interface. This is only slightly useful because you could conceptually deal in terms of the Executor interface now because Spring 3.0 updates the TaskExecutor interface to extend Executor. You use Spring here to configure an instance of an Executor and pass it in as the constructor argument.

SimpleAsyncTaskExecutor provides a new Thread for each job submitted. It does no thread pooling or reuse. Each job submitted runs asynchronously in a thread.

SyncTaskExecutor is the simplest of the implementations of TaskExecutor. Submission of a job is synchronous and tantamount to launching a Thread, running it, and then use join() to connect it immediately. It's effectively the same as manually invoking the run() method in the calling thread, skipping threading all together.

TimerTaskExecutor uses a java.util.Timer instance and manages jobs (java.util.concurrent.Callable<T> or java.lang.Runnable instances) for you by running them on the Timer. You can specify a delay when creating the TimerTaskExecutor, after which all submitted jobs will start running. Internally, the TimerTaskExecutor converts Callable<T> instances or Runnable instances that are submitted into TimerTasks, which it then schedules on the Timer. If you schedule multiple jobs, they will be run serialized on the same thread with the same Timer. If you don't specify a Timer explicitly, a default one will be created. If you want to explicitly register TimerTasks on the Timer, use the org.springframework.scheduling.timer.TimerFactoryBean's scheduledTimerTasks property. The TimerTaskExecutor doesn't surface methods for more advanced scheduling like the Timer class does. If you want to schedule at fixed intervals, at a certain Date (point in time) or for a certain period, you need to manipulate the TimerTask itself. You can do this with the org.springframework.scheduling.timer.ScheduledTimerTask class, which provides a readily configured TimerTask that the TimerFactoryBean will schedule appropriately.

To submit jobs just as you have with other TaskExecutors, after a delay simply configure a TimerFactoryBean and then submit as usual:

<bean id="timerTaskExecutorWithoutScheduledTimerTasks"
class="org.springframework.scheduling.timer.TimerTaskExecutor" p:delay="10000" />

More complex scheduling, such as fixed interval execution, requires that you set the TimerTask explicitly. Here, it does little good to actually submit jobs manually. For more advanced functionality, you'll want to use something like Quartz, which can support cron expressions.

<bean
  id="timerTaskExecutorWithScheduledTimerTasks"
  class="org.springframework.scheduling.timer.TimerTaskExecutor">
  <property
   name="timer">
   <bean
    class="org.springframework.scheduling.timer.TimerFactoryBean">
    <property
     name="scheduledTimerTasks">
     <list>
      <bean
       class="org.springframework.scheduling.timer.ScheduledTimerTask"
       p:delay="10"
       p:fixedRate="true"
       p:period="10000"
       p:runnable-ref="task" />
     </list>
    </property>
   </bean>
  </property>
 </bean>

The last example is ThreadPoolTaskExecutor, which is a full on thread pool implementation building on java.util.concurrent.ThreadPoolExecutor.

If you want to build applications using the CommonJ WorkManager/TimerManager support available in IBM WebSphere 6.0 and BEA WebLogic 9.0, you can use org.springframework.scheduling.commonj.WorkManagerTaskExecutor. This class delegates to a reference to the CommonJ Work Manager available inside of WebSphere or WebLogic. Usually, you'll provide it with a JNDI reference to the appropriate resource. This works well enough (such as with Geronimo), but extra effort is required with JBoss or GlassFish. Spring provides classes that delegate to the JCA support provided on those servers: for GlassFish, use org.springframework.jca.work.glassfish.GlassFishWorkManagerTaskExecutor; for JBoss, use org.springframework.jca.work.jboss.JBossWorkManagerTaskExecutor.

The TaskExecutor support provides a powerful way to access scheduling services on your application server via a unified interface. If you're looking for more robust (albeit much more heavyweight) support that can be deployed on any server (even Tomcat and Jetty!), you might consider Spring's Quartz support.

Summary

In this chapter, you have learned various ways of creating a bean, which include invoking a constructor, invoking a static/instance factory method, using a factory bean, and retrieving it from a static field/object property. The Spring IoC container makes it easy to create beans in these ways. In Spring, you can specify the bean scope to control which bean instance should be returned when requested. The default bean scope is singleton—Spring creates a single and shared bean instance per Spring IoC container. Another common scope is prototype—Spring creates a new bean instance each time when requested.

You can customize the initialization and destruction of your beans by specifying the corresponding callback methods. In addition, your beans can implement certain aware interfaces to be made aware of the container's configurations and infrastructures. The Spring IoC container will call these methods at particular points of a bean's life cycle.

Spring supports registering bean post processors in the IoC container to perform additional bean processing before and after the initialization callback methods. Bean post processors can process all the beans in the IoC container. Typically, bean post processors are used for checking the validity of bean properties or altering the bean properties according to particular criteria.

You have also learned about certain advanced IoC container features, such as externalizing bean configuration into properties files, resolving text messages from resource bundles, publishing and listening to application events, using property editors to convert property values from text values, and loading external resources. You will find these features very useful when developing applications with Spring. Finally, you learned about more exotic features available to you for managing concurrency with Spring's Executor implementations.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset