© Marten Deinum, Daniel Rubio, and Josh Long 2017

Marten Deinum, Daniel Rubio and Josh Long, Spring 5 Recipes, https://doi.org/10.1007/978-1-4842-2790-9_2

2. Spring Core Tasks

Marten Deinum, Daniel Rubio2 and Josh Long3

(1)Meppel, Drenthe, The Netherlands

(2)F. Bahia, Ensenada, Baja California, Mexico

(3)Apartment 205, Canyon Country, California, USA

In this chapter, you’ll learn about the core tasks associated with Spring. At the heart of the Spring Framework is the Spring Inversion of Control (Io0043) container. The IoC container is used to manage and configure Plain Old Java Objects (POJOs). Because one of the primary appeals of the Spring Framework is to build Java applications with POJOs, many of Spring’s core tasks involve managing and configuring POJOs in the IoC container.

So, whether you plan to use the Spring Framework for web applications, enterprise integration, or some other type of project, working with POJOs and the IoC container is one of the first steps you need to take. The majority of the recipes in this chapter cover tasks that you’ll use throughout the book and on a daily basis to develop Spring applications.

Note

The term bean is used interchangeably with a POJO instance both in the book and in the Spring documentation. Both refer to an object instance created from a Java class. In addition, the term component is used interchangeably with a POJO class both in the book and in the Spring documentation. Both refer to the actual Java class from which object instances are created.

Tip

The source code download is organized to use Gradle (through the Gradle wrapper) to build the recipe applications. Gradle takes care of loading all the necessary Java classes and dependencies and creating an executable JAR file. Chapter 1 describes how to set up the Gradle tool. Furthermore, if a recipe illustrates more than one approach, the source code is classified with various examples with roman letters (e.g., Recipe_2_1_i, Recipe_2_1_ii, Recipe_2_1_iii, etc.).

To build each application, go in the Recipe directory (e.g., Ch2/Recipe_2_1_i/) and execute the ./gradlew build command to compile the source code. Once the source code is compiled, a build/libs subdirectory is created with the application executable. You can then run the application JAR from the command line (e.g., java -jar Recipe_2_1_i-4.0.0.jar).

2-1. Use a Java Config to Configure POJOs

Problem

You want to manage POJOs with annotations with Spring’s IoC container.

Solution

Design a POJO class. Next, create a Java config class with @Configuration and @Bean annotations to configure POJO instance values or set up Java components with @Component, @Repository, @Service, or @Controller annotations to later create POJO instance values. Next, instantiate the Spring IoC container to scan for Java classes with annotations. The POJO instances or bean instances then become accessible to put together as part of an application.

How It Works

Suppose you’re going to develop an application to generate sequence numbers and you are going to need many series of sequence numbers for different purposes. Each sequence will have its own prefix, suffix, and initial values. So, you have to create and maintain multiple generator instances for the application. Create a POJO class to create beans with a Java config.

In accordance with the requirements, you create a SequenceGenerator class that has three properties: prefix, suffix, and initial. You also create a private field counter to store the numeric value of each generator. Each time you call the getSequence() method on a generator instance, you get the last sequence number with the prefix and suffix joined.

package com.apress.springrecipes.sequence;

import java.util.concurrent.atomic.AtomicInteger;

public class SequenceGenerator {

    private String prefix;
    private String suffix;
    private int initial;
    private final AtomicInteger counter = new AtomicInteger();


    public SequenceGenerator() {
    }


    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }


    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }


    public void setInitial(int initial) {
        this.initial = initial;
    }


    public String getSequence() {
        StringBuilder builder = new StringBuilder();
        builder.append(prefix)
               .append(initial)
               .append(counter.getAndIncrement())
               .append(suffix);
        return builder.toString();
    }
}

Create a Java Config with @Configuration and @Bean to Create POJOs

To define instances of a POJO class in the Spring IoC container, you can create a Java config class with instantiation values. A Java config class with a POJO or bean definition looks like this:

package com.apress.springrecipes.sequence.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.apress.springrecipes.sequence.SequenceGenerator;


@Configuration
public class SequenceGeneratorConfiguration {


    @Bean
    public SequenceGenerator sequenceGenerator() {
        SequenceGenerator seqgen = new SequenceGenerator();
        seqgen.setPrefix("30");
        seqgen.setSuffix("A");
        seqgen.setInitial("100000");
        return seqgen;
    }
}

Notice the SequenceGeneratorConfiguration class is decorated with the @Configuration annotation; this tells Spring it’s a configuration class. When Spring encounters a class with the @Configuration annotation, it looks for bean instance definitions in the class, which are Java methods decorated with the @Bean annotation. The Java methods create and return a bean instance.

Any method definitions decorated with the @Bean annotation generates a bean name based on the method name. Alternatively, you can explicitly specify the bean name in the @Bean annotation with the name attribute. For example, @Bean(name="mys1") makes the bean available as mys1.

Note

If you explicitly specify the bean name, the method name is ignored for the purposes of bean creation.

Instantiate the Spring IoC Container to Scan for Annotations

You have to instantiate the Spring IoC container to scan for Java classes that contain annotations. In doing so, Spring detects @Configuration and @Bean annotations so you can later get bean instances from the IoC container itself.

Spring provides two types of IoC container implementations. The basic one is called a bean factory. The more advanced one is called an application context, which is compatible with the bean factory. Note the configuration files for these two types of IoC containers are identical.

The application context provides more advanced features than the bean factory while keeping the basic features compatible. Therefore, we strongly recommend using the application context for every application unless the resources of an application are restricted (e.g., such as when running Spring for an applet or a mobile device). The interfaces for the bean factory and the application context are BeanFactory and ApplicationContext, respectively. The ApplicationContext interface is a subinterface of BeanFactory for maintaining compatibility.

Since ApplicationContext is an interface, you have to instantiate an implementation of it. Spring has several application context implementations; we recommend you use AnnotationConfigApplicationContext, which is the newest and most flexible implementation. With this class you can load the Java config file.

ApplicationContext context = new AnnotationConfigApplicationContext    (SequenceGeneratorConfiguration.class);

Once the application context is instantiated, the object reference—in this case context—provides an entry point to access the POJO instances or beans.

Get POJO Instances or Beans from the IoC Container

To get a declared bean from a bean factory or an application context, you just make a call to the getBean() method and pass in the unique bean name. The return type of the getBean() method is java.lang.Object, so you have to cast it to its actual type before using it.

SequenceGenerator generator =
    (SequenceGenerator) context.getBean("sequenceGenerator");

The getBean() method also supports another variation where you can provide the bean class name to avoid making the cast.

SequenceGenerator generator = context.getBean("sequenceGenerator",SequenceGenerator.class);

If there is only a single bean, you can omit the bean name.

SequenceGenerator generator = context.getBean(SequenceGenerator.class);

Once you reach this step, you can use the POJO or bean just like any object created using a constructor outside of Spring.

A Main class to run the sequence generator application would look like the following:

package com.apress.springrecipes.sequence;

import com.apress.springrecipes.sequence.config.SequenceGeneratorConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class Main {

    public static void main(String[] args) {
        ApplicationContext context =
            new AnnotationConfigApplicationContext(SequenceGeneratorConfiguration.class);


        SequenceGenerator generator = context.getBean(SequenceGenerator.class);

        System.out.println(generator.getSequence());
        System.out.println(generator.getSequence());
    }
}

If everything is available in the Java classpath (the SequenceGenerator POJO class and the Spring JAR dependencies), you should see the following output, along with some logging messages:

30100000A
30100001A

Create POJO Class with the @Component Annotation to Create Beans with DAO

Up to this point, the Spring bean instantiations have been done by hard-coding the values in a Java config class. This was the preferred approach to simplify the Spring examples.

However, the POJO instantiation process for most applications is done from either a database or user input. So, now it’s time to move forward and use a more real-world scenario. For this section, we’ll use a Domain class and a Data Access Object (DAO) class to create POJOs. You still won’t need to set up a database—you’ll actually hard-code values in the DAO class—but familiarizing yourself with this type of application structure is important since it’s the basis for most real-world applications and future recipes.

Suppose you are asked to develop a sequence generator application like the one you did in the previous section. You’ll need to modify the class structure slightly to accommodate a Domain class and DAO pattern. First, create a domain class called Sequence containing the id, prefix, and suffix properties.

package com.apress.springrecipes.sequence;

public class Sequence {

    private final String id;
    private final String prefix;
    private final String suffix;


    public Sequence(String id, String prefix, String suffix) {
        this.id = id;
        this.prefix = prefix;
        this.suffix = suffix;
    }


    public String getId() {
        return id;
    }


    public String getPrefix() {
        return prefix;
    }


    public String getSuffix() {
        return suffix;
    }


}

Then, you create an interface for the DAO, which is responsible for accessing data from the database. The getSequence() method loads a POJO or Sequence object from a database table by its ID, while the getNextValue() method retrieves the next value of a particular database sequence.

package com.apress.springrecipes.sequence;

public interface SequenceDao {

    public Sequence getSequence(String sequenceId);
    public int getNextValue(String sequenceId);
}

In a production application, you would implement this DAO interface to use a data-access technology. But to simplify this example, you’ll implement a DAO with hard-coded values in a Map to store the sequence instances and values.

package com.apress.springrecipes.sequence;

import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;


@Component("sequenceDao")
public class SequenceDaoImpl implements SequenceDao {


    private final Map<String, Sequence> sequences = new HashMap<>();
    private final Map<String, AtomicInteger> values = new HashMap<>();


    public SequenceDaoImpl() {
        sequences.put("IT", new Sequence("IT", "30", "A"));
        values.put("IT", new AtomicInteger(10000));
    }


    public Sequence getSequence(String sequenceId) {
        return sequences.get(sequenceId);
    }


    public int getNextValue(String sequenceId) {
        AtomicInteger value = values.get(sequenceId);
        return value.getAndIncrement();
    }
}

Observe how the SequenceDaoImpl class is decorated with the @Component("sequenceDao") annotation. This marks the class so Spring can create POJOs from it. The value inside the @Component annotation defines the bean instance ID, in this case sequenceDao. If no bean value name is provided in the @Component annotation, by default the bean name is assigned as the uncapitalized nonqualified class name. For example, for the SequenceDaoImpl class, the default bean name would be sequenceDaoImpl.

A call to the getSequence method returns the value of the given sequenceID. And a call to the getNextValue method creates a new value based on the value of the given sequenceID and returns the new value.

POJOs are classified in application layers. In Spring there are three layers: persistence, service, and presentation. @Component is a general-purpose annotation to decorate POJOs for Spring detection, whereas @Repository, @Service, and @Controller are specializations of @Component for more specific cases of POJOs associated with the persistence, service, and presentation layers.

If you’re unsure about a POJO’s purpose, you can decorate it with the @Component annotation. However, it’s better to use the specialization annotations where possible because these provide extra facilities based on a POJO’s purpose (e.g., @Repository causes exceptions to be wrapped up as DataAccessExceptions, which makes debugging easier).

Instantiate the Spring IoC Container with Filters to Scan for Annotations

By default, Spring detects all classes decorated with @Configuration, @Bean, @Component, @Repository, @Service, and @Controller annotations, among others. You can customize the scan process to include one or more include/exclude filters. This is helpful when a Java package has dozens or hundreds of classes. For certain Spring application contexts, it can be necessary to exclude or include POJOs with certain annotations.

Warning

Scanning every package can slow down the startup process unnecessarily.

Spring supports four types of filter expressions. The annotation and assignable types are to specify an annotation type and a class/interface for filtering. The regex and aspectj types allow you to specify a regular expression and an AspectJ pointcut expression for matching the classes. You can also disable the default filters with the use-default-filters attribute.

For example, the following component scan includes all classes in com.apress.springrecipes.sequence whose name contains the word Dao or Service and excludes the classes with the @Controller annotation:

@ComponentScan(
    includeFilters = {
        @ComponentScan.Filter(
            type = FilterType.REGEX,
            pattern = {"com.apress.springrecipes.sequence.*Dao", "com.apress.springrecipes.sequence.*Service"})
    },
    excludeFilters = {
        @ComponentScan.Filter(
            type = FilterType.ANNOTATION,
            classes = {org.springframework.stereotype.Controller.class}) }
        )

When applying include filters to detect all classes whose name contains the word Dao or Service, even classes that don’t have annotations are autodetected.

Get POJO Instances or Beans from the IoC Container

Then, you can test the preceding components with the following Main class :

package com.apress.springrecipes.sequence;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class Main {

    public static void main(String[] args) {

        ApplicationContext context =
            new AnnotationConfigApplicationContext("com.apress.springrecipes.sequence");


        SequenceDao sequenceDao = context.getBean(SequenceDao.class);

        System.out.println(sequenceDao.getNextValue("IT"));
        System.out.println(sequenceDao.getNextValue("IT"));
    }
}

2-2. Create POJOs by Invoking a Constructor

Problem

You want to create a POJO instance or bean in the Spring IoC container by invoking its constructor, which is the most common and direct way of creating beans. It is equivalent to using the new operator to create objects in Java.

Solution

Define a POJO class with a constructor or constructors. Next, create a Java config class to configure POJO instance values with constructors for the Spring IoC container. Next, instantiate the Spring IoC container to scan for Java classes with annotations. The POJO instances or bean instances become accessible to be put together as part of an application.

How It Works

Suppose you’re going to develop a shop application to sell products online. First, you create the Product POJO class, which has several properties, such as the product name and price. As there are many types of products in your shop, you make the Product class abstract to extend it for different product subclasses.

package com.apress.springrecipes.shop;

public abstract class Product {

    private String name;
    private double price;


    public Product() {}

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }


    // Getters and Setters
    ...


    public String toString() {
        return name + " " + price;
    }
}

Create the POJO Classes with Constructors

Then you create two product subclasses, Battery and Disc. Each of them has its own properties.

package com.apress.springrecipes.shop;

public class Battery extends Product {

    private boolean rechargeable;

    public Battery() {
        super();
    }


    public Battery(String name, double price) {
        super(name, price);
    }


    // Getters and Setters
    ...
}


package com.apress.springrecipes.shop;

public class Disc extends Product {

    private int capacity;

    public Disc() {
        super();
    }


    public Disc(String name, double price) {
        super(name, price);
    }


    // Getters and Setters
    ...
}

Create a Java Config for Your POJO

To define instances of a POJO class in the Spring IoC container, you have to create a Java config class with instantiation values. A Java config class with a POJO or bean definition made by invoking constructors would look like this:

package com.apress.springrecipes.shop.config;

import com.apress.springrecipes.shop.Battery;
import com.apress.springrecipes.shop.Disc;
import com.apress.springrecipes.shop.Product;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class ShopConfiguration {


    @Bean
    public Product aaa() {
        Battery p1 = new Battery("AAA", 2.5);
        p1.setRechargeable(true);
        return p1;
    }


    @Bean
    public Product cdrw() {
        Disc p2 = new Disc("CD-RW", 1.5);
        p2.setCapacity(700);
        return p2;
    }
}

Next, you can write the following Main class to test your products by retrieving them from the Spring IoC container:

package com.apress.springrecipes.shop;

import com.apress.springrecipes.shop.config.ShopConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class Main {

    public static void main(String[] args) throws Exception {

        ApplicationContext context =
            new AnnotationConfigApplicationContext(ShopConfiguration.class);


        Product aaa = context.getBean("aaa", Product.class);
        Product cdrw = context.getBean("cdrw", Product.class);
        System.out.println(aaa);
        System.out.println(cdrw);
    }
}

2-3. Use POJO References and Autowiring to Interact with Other POJOs

Problem

The POJO instances or beans that make up an application often need to collaborate with each other to complete the application’s functions. You want to use annotations to use POJO references and autowiring.

Solution

For POJO instances defined in a Java config class, you can use standard Java code to create references between beans. To autowire POJO references, you can mark a field, a setter method, a constructor, or even an arbitrary method with the @Autowired annotation.

How It Works

First we will introduce you to different methods of autowiring using constructors, fields and properties. Finally you will see how you could solve issues in autowiring.

Reference POJOs in a Java Config Class

When POJO instances are defined in a Java config class—as illustrated in recipe 2-1 and recipe 2-2—POJO references are straightforward to use because everything is Java code. In the following example, a bean property references another bean:

package com.apress.springrecipes.sequence.config;

import com.apress.springrecipes.sequence.DatePrefixGenerator;
import com.apress.springrecipes.sequence.SequenceGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class SequenceConfiguration {


    @Bean
    public DatePrefixGenerator datePrefixGenerator() {
        DatePrefixGenerator dpg = new DatePrefixGenerator();
        dpg.setPattern("yyyyMMdd");
        return dpg;
    }


    @Bean
    public SequenceGenerator sequenceGenerator() {
        SequenceGenerator sequence = new SequenceGenerator();
        sequence.setInitial(100000);
        sequence.setSuffix("A");
        sequence.setPrefixGenerator(datePrefixGenerator());
        return sequence;
    }
}

The prefixGenerator property of the SequenceGenerator class is an instance of a DatePrefixGenerator bean.

The first bean declaration creates a DatePrefixGenerator POJO. By convention, the bean becomes accessible with the bean name datePrefixGenerator (i.e., the method name). But since the bean instantiation logic is also a standard Java method , the bean is also accessible by making a standard Java call. When the prefixGenerator property is set—in the second bean, via a setter—a standard Java call is made to the method datePrefixGenerator() to reference the bean.

Autowire POJO Fields with the @Autowired Annotation

Next, let’s use autowiring on the SequenceDao field of the DAO SequenceDaoImpl class introduced in the second part of recipe 2-1. You’ll add a service class to the application to illustrate autowiring with the DAO class.

A service class to generate service objects is another real-world application best practice, which acts as a façade to access DAOs—instead of accessing DAOs directly. Internally, the service object interacts with the DAO to handle the sequence generation requests.

package com.apress.springrecipes.sequence;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


@Component
public class SequenceService {


    @Autowired
    private SequenceDao sequenceDao;


    public void setSequenceDao(SequenceDao sequenceDao) {
        this.sequenceDao = sequenceDao;
    }


    public String generate(String sequenceId) {
        Sequence sequence = sequenceDao.getSequence(sequenceId);
        int value = sequenceDao.getNextValue(sequenceId);
        return sequence.getPrefix() + value + sequence.getSuffix();
    }
}

The SequenceService class is decorated with the @Component annotation. This allows Spring to detect the POJO. Because the @Component annotation has no name, the default bean name is sequenceService, which is based on the class name.

The sequenceDao property of the SequenceService class is decorated with the @Autowired annotation. This allows Spring to autowire the property with the sequenceDao bean (i.e., the SequenceDaoImpl class).

The @Autowired annotation can also be applied to a property of an array type to have Spring autowire all the matching beans. For example, you can annotate a PrefixGenerator[] property with @Autowired. Then, Spring will autowire all the beans whose type is compatible with PrefixGenerator at one time.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

    @Autowired
    private PrefixGenerator[] prefixGenerators;
    ...
}

If you have multiple beans whose type is compatible with the PrefixGenerator defined in the IoC container, they will be added to the prefixGenerators array automatically.

In a similar way, you can apply the @Autowired annotation to a type-safe collection. Spring can read the type information of this collection and autowire all the beans whose type is compatible.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

    @Autowired
    private List<PrefixGenerator> prefixGenerators;
    ...
}

If Spring notices that the @Autowired annotation is applied to a type-safe java.util.Map with strings as the keys, it will add all the beans of the compatible type, with the bean names as the keys, to this map.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {

    @Autowired
    private Map<String, PrefixGenerator> prefixGenerators;
    ...
}

Autowire POJO Methods and Constructors with the @Autowired Annotation and Make Autowiring Optional

The @Autowired annotation can also be applied directly to the setter method of a POJO. As an example, you can annotate the setter method of the prefixGenerator property with @Autowired. Then, Spring attempts to wire a bean whose type is compatible with prefixGenerator.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {
    ...
    @Autowired
    public void setPrefixGenerator(PrefixGenerator prefixGenerator) {
        this.prefixGenerator = prefixGenerator;
    }
}

By default, all the properties with @Autowired are required. When Spring can’t find a matching bean to wire, it will throw an exception. If you want a certain property to be optional, set the required attribute of @Autowired to false. Then, when Spring can’t find a matching bean, it will leave this property unset.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {
    ...
    @Autowired(required=false)
    public void setPrefixGenerator(PrefixGenerator prefixGenerator) {
        this.prefixGenerator = prefixGenerator;
    }
}

You may also apply the @Autowired annotation to a method with an arbitrary name and an arbitrary number of arguments; in that case, Spring attempts to wire a bean with the compatible type for each of the method arguments.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;

public class SequenceGenerator {
    ...
    @Autowired
    public void myOwnCustomInjectionName(PrefixGenerator prefixGenerator) {
        this.prefixGenerator = prefixGenerator;
    }
}

Finally, you may also apply the @Autowired annotation to a constructor that you want to be used for autowiring. The constructor can have any number of arguments, and Spring will attempt to wire a bean with the compatible type for each of the constructor arguments.

@Service
public class SequenceService {


    private final SequenceDao sequenceDao;

    @Autowired
    public SequenceService(SequenceDao sequenceDao) {
        this.sequenceDao=sequenceDao;
    }


    public String generate(String sequenceId) {
        Sequence sequence = sequenceDao.getSequence(sequenceId);
        int value = sequenceDao.getNextValue(sequenceId);
        return sequence.getPrefix() + value + sequence.getSuffix();
    }
}
Tip

As of Spring Framework 4.3, if you have only a single constructor, Spring will automatically use that constructor for autowiring. In that case, you can omit the @Autowired annotation.

Resolve Autowire Ambiguity with Annotations

By default, autowiring by type will not work when there is more than one bean with the compatible type in the IoC container and the property isn’t a group type (e.g., array, list, map), as illustrated previously. However, there are two workarounds to autowiring by type if there’s more than one bean of the same type: the @Primary annotation and the @Qualifier annotation.

Resolve Autowire Ambiguity with the @Primary Annotation

Spring allows you to specify a candidate bean by type by decorating the candidate with the @Primary annotation. The @Primary annotation gives preference to a bean when multiple candidates are qualified to autowire a single-valued dependency.

package com.apress.springrecipes.sequence;
...
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Primary;


@Component
@Primary
public class DatePrefixGenerator implements PrefixGenerator {


    public String getPrefix() {
        DateFormat formatter = new SimpleDateFormat("yyyyMMdd");
        return formatter.format(new Date());
    }
}

Notice that the previous POJO implements the PrefixGenerator interface and is decorated with the @Primary annotation. If you attempted to autowire a bean with a PrefixGenerator type, even if Spring had more than one bean instance with the same PrefixGenerator type, Spring would autowire the DatePrefixGenerator because it’s marked with the @Primary annotation.

Resolve Autowire Ambiguity with the @Qualifier Annotation

Spring also allows you to specify a candidate bean by type by providing its name in the @Qualifier annotation.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;


public class SequenceGenerator {

    @Autowired
    @Qualifier("datePrefixGenerator")
    private PrefixGenerator prefixGenerator;
    ...
}

Once you’ve done this, Spring attempts to find a bean with that name in the IoC container and wire it into the property.

The @Qualifier annotation can also be applied to a method argument for autowiring.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;


public class SequenceGenerator {
    ...
    @Autowired
    public void myOwnCustomInjectionName(
        @Qualifier("datePrefixGenerator") PrefixGenerator prefixGenerator) {
        this.prefixGenerator = prefixGenerator;
    }
}

If you want to autowire bean properties by name, you can annotate a setter method, a constructor, or a field with the JSR-250 @Resource annotation described in the next recipe.

Resolve POJO References from Multiple Locations

As an application grows, it can become difficult to manage every POJO in a single Java configuration class. A common practice is to separate POJOs into multiple Java configuration classes according to their functionalities. When you create multiple Java configuration classes, obtaining references and autowiring POJOs that are defined in different classes isn’t as straightforward as when everything is in a single Java configuration class.

One approach is to initialize the application context with the location of each Java configuration class. In this manner, the POJOs for each Java configuration class are loaded into the context and references, and autowiring between POJOs is possible.

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext    (PrefixConfiguration.class, SequenceGeneratorConfiguration.class);

Another alternative is to use the @Import annotation so Spring makes the POJOs from one configuration file available in another.

package com.apress.springrecipes.sequence.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import com.apress.springrecipes.sequence.SequenceGenerator;
import com.apress.springrecipes.sequence.PrefixGenerator;


@Configuration
@Import(PrefixConfiguration.class)
public class SequenceConfiguration {
    @Value("#{datePrefixGenerator}")
    private PrefixGenerator prefixGenerator;


    @Bean
    public SequenceGenerator sequenceGenerator() {
        SequenceGenerator sequence= new SequenceGenerator();
        sequence.setInitial(100000);
        sequence.setSuffix("A");
        sequence.setPrefixGenerator(prefixGenerator);
        return sequence;
    }
}

The sequenceGenerator bean requires you to set a prefixGenerator bean. But notice no prefixGenerator bean is defined in the Java configuration class. The prefixGenerator bean is defined in a separate Java configuration class called PrefixConfiguration. With the @Import(PrefixConfiguration.class) annotation, Spring brings all the POJOs in the Java configuration class into the scope of the present configuration class. With the POJOs from PrefixConfiguration in scope, you use the @Value annotation and SpEL to inject the bean named datePrefixGenerator into the prefixGenerator field. Once the bean is injected, it can be used to set a prefixGenerator bean for the sequenceGenerator bean.

2-4. Autowire POJOs with the @Resource and @Inject Annotations

Problem

You want to use the Java standard @Resource and @Inject annotations to reference POJOs via autowiring, instead of using the Spring-specific @Autowired annotation.

Solution

JSR-250, or Common Annotations for the Java Platform, defines the @Resource annotation to autowire POJO references by name. JSR-330, or Standard Annotations for Injection, defines the @Inject annotations to autowire POJO references by type.

How It Works

The @Autowired annotation described in the previous recipe belongs to the Spring Framework, specifically to the org.springframework.beans.factory.annotation package. This means it can be used only in the context of the Spring Framework.

Soon after Spring added support for the @Autowired annotation, the Java language standardized various annotations to fulfill the same purpose of the @Autowired annotation. These annotations are @Resource, which belongs to the javax.annotation package, and @Inject, which belongs to the javax.inject package.

Autowire POJOs with the @Resource Annotation

By default, the @Resource annotation works like Spring’s @Autowired annotation and attempts to autowire by type. For example, the following POJO attribute is decorated with the @Resource annotation, so Spring attempts to locate a POJO that matches the PrefixGenerator type.

package com.apress.springrecipes.sequence;

import javax.annotation.Resource;

public class SequenceGenerator {

    @Resource
    private PrefixGenerator prefixGenerator;
    ...
}

However, unlike the @Autowired annotation, which requires the @Qualifier annotation to autowire a POJO by name, the @Resource ambiguity is eliminated if more than one POJO type of the same kind exists. Essentially, the @Resource annotation provides the same functionality as putting together the @Autowired annotation and the @Qualifier annotation.

Autowire POJOs with the @Inject Annotation

Also, the @Inject annotation attempts to autowire by type, like the @Resource and @Autowired annotations. For example, the following POJO attribute is decorated with the @Inject annotation, so Spring attempts to locate a POJO that matches the PrefixGenerator type:

package com.apress.springrecipes.sequence;

import javax.inject.Inject;

public class SequenceGenerator {

    @Inject
    private PrefixGenerator prefixGenerator;
    ...
}

But just like the @Resource and @Autowired annotations, a different approach has to be used to match POJOs by name or avoid ambiguity if more than one POJO type of the same kind exists. The first step to do autowiring by name with the @Inject annotation is to create a custom annotation to identify both the POJO injection class and the POJO injection point.

package com.apress.springrecipes.sequence;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


import javax.inject.Qualifier;

@Qualifier
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface DatePrefixAnnotation {
}

Notice the custom annotation makes use of the @Qualifier annotation. This annotation is different from the one used with Spring’s @Qualifier annotation, as this last class belongs to the same Java package as the @Inject annotation (i.e., javax.inject).

Once the custom annotation is done, it’s necessary to decorate the POJO injection class that generates the bean instance, which in this case is the DatePrefixGenerator class.

package com.apress.springrecipes.sequence;
...
@DatePrefixAnnotation
public class DatePrefixGenerator implements PrefixGenerator {
...
}

Finally, the POJO attribute or injection point is decorated with the same custom annotation to qualify the POJO and eliminate any ambiguity.

package com.apress.springrecipes.sequence;

import javax.inject.Inject;

public class SequenceGenerator {

    @Inject @DataPrefixAnnotation
    private PrefixGenerator prefixGenerator;
    ...
}

As you’ve seen in recipes 2-3 and 2-4, the three annotations @Autowired, @Resource, and @Inject can achieve the same result. The @Autowired annotation is a Spring-based solution, whereas the @Resource and @Inject annotations are Java standard (i.e., JSR) solutions. If you’re going to do name-based autowiring, the @Resource annotation offers the simplest syntax. For autowiring by class type, all three annotations are straightforward to use because all three require a single annotation.

2-5. Set a POJO’s Scope with the @Scope Annotation

Problem

When you declare a POJO instance with an annotation like @Component, you are actually defining a template for bean creation, not an actual bean instance. When a bean is requested by the getBean() method or referenced from other beans, Spring decides 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

A bean’s scope is set with the @Scope annotation . By default, Spring creates exactly one instance for each bean declared in the IoC container, and this instance is shared in the scope of the entire IoC container. This unique bean instance is returned for all subsequent getBean() calls and bean references. This scope is called singleton, which is the default scope of all beans. Table 2-1 lists all valid bean scopes in Spring.

Table 2-1. 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; valid only in the context of a web application

session

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

globalSession

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

How It Works

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

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


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

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


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

Then, you declare some product beans in a Java config file so they can later be added to the shopping cart.

package com.apress.springrecipes.shop.config;

import com.apress.springrecipes.shop.Battery;
import com.apress.springrecipes.shop.Disc;
import com.apress.springrecipes.shop.Product;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;


@Configuration
@ComponentScan("com.apress.springrecipes.shop")
public class ShopConfiguration {


    @Bean
    public Product aaa() {
        Battery p1 = new Battery();
        p1.setName("AAA");
        p1.setPrice(2.5);
        p1.setRechargeable(true);
        return p1;
    }


    @Bean
    public Product cdrw() {
        Disc p2 = new Disc("CD-RW", 1.5);
        p2.setCapacity(700);
        return p2;
    }


    @Bean
    public Product dvdrw() {
        Disc p2 = new Disc("DVD-RW", 3.0);
        p2.setCapacity(700);
        return p2;
    }
}

Once you do this, you can define a Main class to test the shopping cart by adding some products to it. Suppose 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 com.apress.springrecipes.shop.config.ShopConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class Main {

    public static void main(String[] args) throws Exception {
        ApplicationContext context =            new AnnotationConfigApplicationContext(ShopConfiguration.class);


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


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


        ShoppingCart cart2 = context.getBean("shoppingCart", ShoppingCart.class);
        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.

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, the scope of the shoppingCart bean needs to be set to prototype. Then Spring creates a new bean instance for each getBean() method call.

package com.apress.springrecipes.shop;
...
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Scope;


@Component
@Scope("prototype")
public class ShoppingCart { ... }

Now if you run the Main class again, you can see 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]

2-6. Use Data from External Resources (Text Files, XML Files, Properties Files, or Image Files)

Problem

Sometimes applications 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 offers the @PropertySource annotation as a facility to load the contents of a .properties file (i.e., key-value pairs) to set up bean properties.

Spring also has a resource loader mechanism that provides a unified Resource interface to retrieve any type of external resource by a resource path. You can specify different prefixes for this path to load resources from different locations with the @Value annotation. 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 can also specify a URL in the resource path.

How It Works

To read the contents of a properties file (i.e., key-value pairs) to set up bean properties, you can use Spring’s @PropertySource annotation with PropertySourcesPlaceholderConfigurer. If you want to read the contents of any file, you can use Spring’s Resource mechanism decorated with the @Value annotation.

Use Properties File Data to Set Up POJO Instantiation Values

Let’s assume you have a series of values in a properties file you want to access to set up bean properties. Typically this can be the configuration properties of a database or some other application values composed of key values. For example, take the following key values stored in a file called discounts.properties:

specialcustomer.discount=0.1 summer.discount=0.15 endofyear.discount=0.2
Note

To read properties files for the purpose of internationalization (i18n), see the next recipe. To make the contents of the discounts.properties file accessible to set up other beans, you can use the @PropertySource annotation to convert the key values into a bean inside a Java config class.

package com.apress.springrecipes.shop.config;

import com.apress.springrecipes.shop.Battery;
import com.apress.springrecipes.shop.Disc;
import com.apress.springrecipes.shop.Product;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;


@Configuration
@PropertySource("classpath:discounts.properties")
@ComponentScan("com.apress.springrecipes.shop")
public class ShopConfiguration {


    @Value("${endofyear.discount:0}")
    private double specialEndofyearDiscountField;


    @Bean
    public static PropertySourcesPlaceholderConfigurer        propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean
    public Product dvdrw() {
        Disc p2 = new Disc("DVD-RW", 3.0, specialEndofyearDiscountField);
        p2.setCapacity(700);
        return p2;
    }
}

You define a @PropertySource annotation with a value of classpath:discounts.properties to decorate the Java config class. The classpath: prefix tells Spring to look for the discounts.properties file in the Java classpath.

Once you define the @PropertySource annotation to load the properties file, you also need to define a PropertySourcePlaceholderConfigurer bean with the @Bean annotation. Spring automatically wires the @PropertySource discounts.properties file so its properties become accessible as bean properties.

Next, you need to define Java variables to take values from the discount discounts.properties file. To define the Java variable values with these values, you make use of the @Value annotation with a placeholder expression.

The syntax is @Value("${key:default_value}"). A search is done for the key value in all the loaded application properties. If a matching key=value is found in the properties file, the corresponding value is assigned to the bean property. If no matching key=value is found in the loaded application properties, default_value (i.e., after ${key:) is assigned to the bean property.

Once a Java variable is set with a discount value, you can use it to set up bean instances for a bean’s discount property.

If you want to use properties file data for a different purpose than setting up bean properties, you should use Spring’s Resource mechanism, which is described next.

Use Data from Any External Resource File for Use in a POJO

Suppose you want to display a banner on application startup. The banner consists of the following characters and stored in a text file called banner.txt. This file can be put in the classpath of your application.

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

Next, let’s write a BannerLoader POJO class to load the banner and output it to the console.

package com.apress.springrecipes.shop;
import org.springframework.core.io.Resource;
...
import javax.annotation.PostConstruct;
public class BannerLoader {


    private Resource banner;

    public void setBanner(Resource banner) {
        this.banner = banner;
    }


    @PostConstruct
    public void showBanner() throws IOException {
        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();
    }
}

Notice the POJO banner field is a Spring Resource type. The field value will be populated through setter injection when the bean instance is created—to be explained shortly. The showBanner() method makes a call to the getInputStream() method to retrieve the input stream from the Resource field. Once you have an InputStream, you’re able to use a standard Java file manipulation class. In this case, the file contents are read line by line with BufferedReader and output to the console.

Also notice the showBanner() method is decorated with the @PostConstruct annotation. Because you want to show the banner at startup, you use this annotation to tell Spring to invoke the method automatically after creation. This guarantees the showBanner() method is one of the first methods to be run by the application and therefore ensures the banner appears at the outset.

Next, the POJO BannerLoader needs to be initialized as an instance. In addition, the banner field of the BannerLoader also needs to be injected. So, let’s create a Java config class for these tasks.

@Configuration
@PropertySource("classpath:discounts.properties")
@ComponentScan("com.apress.springrecipes.shop")
public class ShopConfiguration {


    @Value("classpath:banner.txt")
    private Resource banner;


    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }


    @Bean
    public BannerLoader bannerLoader() {
        BannerLoader bl = new BannerLoader();
        bl.setBanner(banner);
        return bl;
    }
}

See how the banner property is decorated with the @Value("classpath:banner.txt") annotation. This tells Spring to search for the banner.txt file in the classpath and inject it. Spring uses the preregistered property editor ResourceEditor to convert the file definition into a Resource object before injecting it into the bean.

Once the banner property is injected, it’s assigned to the BannerLoader bean instance via setter injection.

Because the banner file is located in the Java classpath, the resource path starts with the classpath: prefix. 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 a resource is located in Java’s 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 support to load from a file system path or the classpath, a resource can also be loaded by specifying a URL.

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

Since the bean class uses the @PostConstruct annotation on the showBanner() method, the banner is sent to output when the IoC container is set up. Because of this, there’s no need to tinker with an application’s context or explicitly call the bean to output the banner. However, sometimes it can be necessary to access an external resource to interact with an application’s context. Now suppose you want to display a legend at the end of an application. The legend consists of the discounts previously described in the discounts.properties file. To access the contents of the properties file, you can also leverage Spring’s Resource mechanism.

Next, let’s use Spring’s Resource mechanism, but this time directly inside an application’s Main class to output a legend when the application finishes.

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
...
...
public class Main {


    public static void main(String[] args) throws Exception {
        ...
        Resource resource = new ClassPathResource("discounts.properties");
        Properties props = PropertiesLoaderUtils.loadProperties(resource);
        System.out.println("And don't forget our discounts!");
        System.out.println(props);


    }
}

Spring’s ClassPathResource class is used to access the discounts.properties file, which casts the file’s contents into a Resource object. Next, the Resource object is processed into a Properties object with Spring’s PropertiesLoaderUtils class. Finally, the contents of the Properties object are sent to the console as the final output of the application.

Because the legend file (i.e., discounts.properties) is located in the Java classpath, the resource is accessed with Spring’s ClassPathResource class. If the external resource were in a file system path, the resource would be loaded with Spring’s FileSystemResource.

Resource resource = new FileSystemResource("c:/shop/banner.txt")

If the external resource were at a URL, the resource would be loaded with Spring’s UrlResource.

Resource resource = new UrlResource("http://www.apress.com/")

2-7. Resolve I18N Text Messages for Different Locales in Properties Files

Problem

You want an application to support internationalization via annotations.

Solution

MessageSource is an interface that defines several methods for resolving messages in resource bundles. ResourceBundleMessageSource is the most common MessageSource implementation that resolves messages from resource bundles for different locales. After you implement a ResourceBundleMessageSource POJO, you can use the @Bean annotation in a Java config file to make the i18n data available in an application.

How It Works

As an example, create a resource bundle called messages_en_US.properties for the English language in the United States. Resource bundles are loaded from the root of the classpath, so ensure it’s available on the Java classpath. Place the following key-value in the file:

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

To resolve messages from resource bundles, let’s create a Java config file with an instance of a ReloadableResourceBundleMessageSource bean.

package com.apress.springrecipes.shop.config;

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


@Configuration
public class ShopConfiguration {


    @Bean
    public ReloadableResourceBundleMessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource =            new ReloadableResourceBundleMessageSource();
        messageSource.setBasenames("classpath:messages");
        messageSource.setCacheSeconds(1);
        return messageSource;
    }
}

The bean instance must have the name messageSource for the application context to detect it.

Inside the bean definition you declare a String list via the setBasenames method to locate bundles for the ResourceBundleMessageSource. In this case, you just specify the default convention to look up files located in the Java classpath that start with messages. In addition, the setCacheSeconds methods sets the caching to 1 second to avoid reading stale messages. Note that a refresh attempt first checks the last-modified timestamp of the properties file before actually reloading it, so if files don’t change, the setCacheSeconds interval can be set rather low, as refresh attempts aren’t actually reloaded.

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 is considered first. If there’s no such resource bundle or the message can’t be found, then a messages_en.properties file that matches the language is considered. If a resource bundle still can’t be found, the default messages.properties for all locales is chosen. For more information on resource bundle loading, you can refer to the Javadoc of the java.util.ResourceBundle class.

Next, you can configure the application context to resolve messages with 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 com.apress.springrecipes.shop.config.ShopConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


import java.util.Date;
import java.util.Locale;


public class Main {

    public static void main(String[] args) throws Exception {

        ApplicationContext context =            new AnnotationConfigApplicationContext(ShopConfiguration.class);

        String alert = context.getMessage("alert.checkout", null, Locale.US);
        String alert_inventory = context.getMessage("alert.inventory.checkout", new Object[]{"[DVD-RW 3.0]", new Date()}, Locale.US);


        System.out.println("The I18N message for alert.checkout is: " + alert);
        System.out.println("The I18N message for alert.inventory.checkout is: " + alert_inventory);
    }
}

The second argument of the getMessage() method is an array of message parameters. In the first String statement the value is null, and in the second String statement an object array to fill in the message parameters is used.

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, you have to inject a MessageSource implementation into the bean that needs to resolve text messages. Let’s implement a Cashier class for the shopping application that illustrates how to resolve messages.

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


    @Autowired
    private MessageSource messageSource;


    public void setMessageSource(MessageSource messageSource) {
        this.messageSource = messageSource;
    }


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

Notice the POJO messageSource field is a Spring MessageSource type . The field value is decorated with the @Autowired annotation, so it’s populated through injection when the bean instance is created. Then the checkout method can access the messageSource field, which gives the bean access to the getMessage method to gain access to text messages based on i18n criteria.

2-8. Customize POJO Initialization and Destruction with Annotations

Problem

Some POJOs have to perform certain types of initialization tasks before they’re used. These tasks can include opening a file, opening a network/database connection, allocating memory, and so on. In addition, these same POJOs have to perform the corresponding destruction tasks at the end of their life cycle. Therefore, sometimes it’s necessary to customize bean initialization and destruction in the Spring IoC container.

Solution

Spring can recognize initialization and destruction callback methods by setting the initMethod and destroyMethod attributes of the @Bean definition in a Java config class. Or Spring can also recognize initialization and destruction callback methods if POJO methods are decorated with the @PostConstruct and @PreDestroy annotations, respectively. Spring can also delay the creation of a bean up until the point it’s required—a process called lazy initialization—with the @Lazy annotation. Spring can also ensure the initialization of certain beans before others with the @DependsOn annotation.

How It Works

Define methods to run before POJO initialization and destruction with @Bean. Let’s take the case of the shopping application and consider an example involving a checkout function. Let’s modify the Cashier class to record a shopping cart’s products and the checkout time to a text file.

package com.apress.springrecipes.shop;

import java.io.*;
import java.util.Date;


public class Cashier {

    private String fileName;
    private String path;
    private BufferedWriter writer;


    public void setFileName(String fileName) {
        this.fileName = fileName;
    }


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


    public void openFile() throws IOException {

        File targetDir = new File(path);
        if (!targetDir.exists()) {
            targetDir.mkdir();
        }


        File checkoutFile = new File(path, fileName + ".txt");
        if (!checkoutFile.exists()) {
            checkoutFile.createNewFile();
        }


        writer = new BufferedWriter(new OutputStreamWriter(
                 new FileOutputStream(checkoutFile, true)));
    }


    public void checkout(ShoppingCart cart) throws IOException {
        writer.write(new Date() + " " + cart.getItems() + " ");
        writer.flush();
    }


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


}

In the Cashier class, the openFile() method first verifies whether the target directory and the file to write the data exists. It then opens the text file in the specified system path and assigns it to the writer field. Then each time the checkout() method is called , the date and cart items are appended to the text file. Finally, the closeFile() method closes the file to release its system resources.

Next, let’s explore how this bean definition has to be set up in a Java config class to execute the openFile() method just before the bean is created and the closeFile() method just before it’s destroyed.

@Configuration
public class ShopConfiguration {


    @Bean(initMethod = "openFile", destroyMethod = "closeFile")
    public Cashier cashier() {


        String path = System.getProperty("java.io.tmpdir") + "/cashier";
        Cashier c1 = new Cashier();
        c1.setFileName("checkout");
        c1.setPath(path);
        return c1;
    }
}

Notice the POJO’s initialization and destruction tasks are defined with the initMethod and destroyMethod attributes of an @Bean annotation . With these two attributes set in the bean declaration, when the Cashier class is created, it first triggers the openFile() method, verifying whether the target directory and the file to write the data exist, as well as opening the file to append records. When the bean is destroyed, it triggers the closeFile() method, ensuring the file reference is closed to release system resources.

Define Methods to Run Before POJO Initialization and Destruction with @PostConstruct and @PreDestroy

Another alterative if you’re defining POJO instances outside a Java config class (e.g., with the @Component annotation) is to use the @PostConstruct and @PreDestroy annotations directly in the POJO class.

@Component
public class Cashier {


    @Value("checkout")
    private String fileName;
    @Value("c:/Windows/Temp/cashier")
    private String path;
    private BufferedWriter writer;


    public void setFileName(String fileName) {
        this.fileName = fileName;
    }


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


    @PostConstruct
    public void openFile() throws IOException {
        File targetDir = new File(path);
        if (!targetDir.exists()) {
            targetDir.mkdir();
        }
        File checkoutFile = new File(path, fileName + ".txt");
        if(!checkoutFile.exists()) {
            checkoutFile.createNewFile();
        }
        writer = new BufferedWriter(new OutputStreamWriter(
                 new FileOutputStream(checkoutFile, true)));
    }


    public void checkout(ShoppingCart cart) throws IOException {
        writer.write(new Date() + " " +cart.getItems() + " ");
        writer.flush();
    }


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

The @ Component annotation tells Spring to manage the POJO, just like it’s been used in previous recipes. Two of the POJO fields’ values are set with the @Value annotation, a concept that was also explored in a previous recipe. The openFile() method is decorated with the @PostConstruct annotation, which tells Spring to execute the method right after a bean is constructed. The closeFile() method is decorated with the @PreDestroy annotation, which tells Spring to execute the method right before a bean is destroyed.

Define Lazy Initialization for POJOs with @Lazy

By default, Spring performs eager initialization on all POJOs. This means POJOs are initialized at startup. In certain circumstances, though, it can be convenient to delay the POJO initialization process until a bean is required. Delaying the initialization is called lazy initialization.

Lazy initialization helps limit resource consumption peaks at startup and save overall system resources. Lazy initialization can be particularly relevant for POJOs that perform heavyweight operations (e.g., network connections, file operations). To mark a bean with lazy initialization, you decorate a bean with the @Lazy annotation.

package com.apress.springrecipes.shop;
...
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.Lazy;


@Component
@Scope("prototype")
@Lazy
public class ShoppingCart {


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

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


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

In the previous declaration, because the POJO is decorated with the @Lazy annotation, if the POJO is never required by the application or referenced by another POJO, it’s never instantiated.

Define Initialization of POJOs Before Other POJOs with @DependsOn

As an application’s POJOs grow, so does the number of POJO initializations. This can create race conditions if POJOs reference one another and are spread out in different Java configuration classes. What happens if bean C requires the logic in bean B and bean F? If bean C is detected first and Spring hasn’t initialized bean B and bean F, you’ll get an error that can be hard to detect. To ensure that certain POJOs are initialized before other POJOs and to get a more descriptive error in case of a failed initialization process, Spring offers the @DependsOn annotation. The @DependsOn annotation ensures a given bean is initialized before another bean.

package com.apress.springrecipes.sequence.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Configuration;
import com.apress.springrecipes.sequence.DatePrefixGenerator;
import com.apress.springrecipes.sequence.NumberPrefixGenerator;
import com.apress.springrecipes.sequence.SequenceGenerator;


@Configuration
public class SequenceConfiguration {
    @Bean
    @DependsOn("datePrefixGenerator")
    public SequenceGenerator sequenceGenerator() {
        SequenceGenerator sequence= new SequenceGenerator();
        sequence.setInitial(100000);
         sequence.setSuffix("A");
         return sequence;
    }
}

In the previous snippet, the declaration @DependsOn("datePrefixGenerator") ensures the datePrefixGenerator bean is created before the sequenceGenerator bean. The @DependsOn attribute also supports defining multiple dependency beans with a CSV list surrounded by {} (e.g., @DependsOn({"datePrefixGenerator,numberPrefixGenerator,randomPrefixGenerator"})

2-9. Create Post-Processors to Validate and Modify POJOs

Problem

You want to apply tasks to all bean instances or specific types of instances during construction to validate or modify bean properties according to particular criteria.

Solution

A bean post-processor allows bean processing before and after the initialization callback method (i.e., the one assigned to the initMethod attribute of the @Bean annotation or the method decorated with the @PostConstruct annotation). The main characteristic of a bean post-processor is that it processes all the bean instances in the IoC container, not just a single bean instance. Typically, bean post-processors are used to check the validity of bean properties, alter bean properties according to particular criteria, or apply certain tasks to all bean instances.

Spring also supports the @Required annotation, which is backed by the built-in Spring post-processor RequiredAnnotationBeanPostProcessor. The RequiredAnnotationBeanPostProcessor bean post-processor checks whether all the bean properties with the @Required annotation have been set.

How It Works

Suppose you want to audit the creation of every bean. You may want to do this to debug an application, to verify the properties of every bean, or in some other scenario. A bean post-processor is an ideal choice to implement this feature because you don’t have to modify any preexisting POJO code.

Create POJO to Process Every Bean Instance

To write a bean post-processor, a class has to implement BeanPostProcessor. When Spring detects a bean that implements this class, it applies the postProcessBeforeInitialization() and postProcessAfterInitialization() methods to all bean instances managed by Spring. You can implement any logic you want in these methods to either inspect, modify, or verify the status of a bean.

package com.apress.springrecipes.shop;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;


import org.springframework.stereotype.Component;

@Component
public class AuditCheckBeanPostProcessor implements BeanPostProcessor {


    public Object postProcessBeforeInitialization(Object bean, String beanName)
        throws BeansException {
            System.out.println("In AuditCheckBeanPostProcessor.postProcessBeforeInitialization, processing bean type: " + bean.getClass());
        return bean;
    }


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

Notice the postProcessBeforeInitialization() and postProcessAfterInitialization() methods must return the original bean instance even if you don’t do anything in the method.

To register a bean post-processor in an application context, just annotate the class with the @Component annotation. The application context is able to detect which bean implements the BeanPostProcessor interface and register it to process all other bean instances in the container.

Create a POJO to Process Selected Bean Instances

During bean construction, the Spring IoC container passes all the bean instances to the bean post-processor one by one. This means if you want to apply a bean post-processor to only certain types of beans, you must filter the beans by checking their instance type. This allows you to apply logic more selectively across beans.

Suppose you now want to apply a bean post-processor but just to Product bean instances. The following example is another bean post-processor that does this:

package com.apress.springrecipes.shop;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;


import org.springframework.stereotype.Component;

@Component
public class ProductCheckBeanPostProcessor implements BeanPostProcessor {


    public Object postProcessBeforeInitialization(Object bean, String beanName)
        throws BeansException {
        if (bean instanceof Product) {
            String productName = ((Product) bean).getName();
                System.out.println("In ProductCheckBeanPostProcessor.postProcessBeforeInitialization, processing Product: " + productName);
        }
        return bean;
    }


    public Object postProcessAfterInitialization(Object bean, String beanName)
        throws BeansException {
        if (bean instanceof Product) {
            String productName = ((Product) bean).getName();
                System.out.println("In ProductCheckBeanPostProcessor.postProcessAfterInitialization, processing Product: " + productName);
        }
        return bean;
    }
}

Both the postProcessBeforeInitialization() and postProcessAfterInitialization() methods must return an instance of the bean being processed. However, this also means you can even replace the original bean instance with a new instance in your bean post-processor.

Verify POJO Properties with the @Required Annotation

In certain cases, it may be necessary to check whether particular properties have been set. Instead of creating of custom post-constructor to verify the particular properties of a bean, it’s possible to decorate a property with the @Required annotation. The @Required annotation provides access to the RequiredAnnotationBeanPostProcessor class—a Spring bean post-processor that can check whether certain bean properties have been set. Note that this processor can check only whether the properties have been set but can’t check whether their value is null or something else.

Suppose that both the prefixGenerator and suffix properties are required for a sequence generator. You can annotate their setter methods with @Required.

package com.apress.springrecipes.sequence;

import org.springframework.beans.factory.annotation.Required;

public class SequenceGenerator {

    private PrefixGenerator prefixGenerator;
    private String suffix;
    ...
    @Required
    public void setPrefixGenerator(PrefixGenerator prefixGenerator) {
        this.prefixGenerator = prefixGenerator;
    }


    @Required
    public void setSuffix(String suffix) {
        this.suffix = suffix;
    }
    ...
}

To ask Spring to check whether these properties have been set, you just need to enable scanning so Spring can detect and enforce the @Required annotation. If any properties with @Required have not been set, a BeanInitializationException error is thrown.

2-10. Create POJOs with a Factory (Static Method, Instance Method, Spring’s FactoryBean)

Problem

You want to create a POJO instance in the Spring IoC container by invoking a static factory method or instance factory method. The purpose of this approach is to encapsulate the object-creation process either in a static method or in a method of another object instance, respectively. The client who requests an object can simply make a call to this method without knowing about the creation details. You want to create a POJO instance in the Spring IoC container using Spring’s factory bean. A factory bean is a bean that serves as a factory for creating other beans within the IoC container. Conceptually, a factory bean is similar to a factory method, but it’s a Spring-specific bean that can be identified by the Spring IoC container during bean construction.

Solution

To create a POJO by invoking a static factory inside an @Bean definition of a Java configuration class, you use standard Java syntax to call the static factory method. To create a POJO by invoking an instance factory method inside an @Bean definition of a Java configuration class, you create a POJO to instantiate the factory values and another POJO to act as a façade to access the factory.

As a convenience, Spring provides an abstract template class called AbstractFactoryBean to extend Spring’s FactoryBean interface.

How It Works

You will explore the different ways of defining and using factory methods with Spring. First you will learn how to use a static factory method, next an instance based factory method and finally you will look at the Spring FactoryBean.

Create POJOs by Invoking a Static Factory Method

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 decides which concrete product class to instantiate. If there is no product matching this ID, it throws 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);
        } else if ("dvdrw".equals(productId)) {
            return new Disc("DVD-RW", 3.0);
        }
        throw new IllegalArgumentException("Unknown product");
    }
}

To create a POJO with a static factory method inside an @Bean definition of a Java configuration class, you use regular Java syntax to call the factory method.

package com.apress.springrecipes.shop.config;

import com.apress.springrecipes.shop.Product;
import com.apress.springrecipes.shop.ProductCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class ShopConfiguration {
    @Bean
    public Product aaa() {
        return ProductCreator.createProduct("aaa");
    }


    @Bean
    public Product cdrw() {
        return ProductCreator.createProduct("cdrw");
    }


    @Bean
    public Product dvdrw() {
        return ProductCreator.createProduct("dvdrw");
    }
}

Create POJOs by Invoking an Instance Factory Method

For example, you can write the following ProductCreator class by using a configurable map to store predefined products. The createProduct() instance factory method finds a product by looking up the supplied productId value 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, you first declare an @Bean to instantiate the factory values. Next, you declare a second bean to act as a façade to access the factory. Finally, you can call the factory and execute the createProduct() method to instantiate other beans.

package com.apress.springrecipes.shop.config;

import com.apress.springrecipes.shop.Battery;
import com.apress.springrecipes.shop.Disc;
import com.apress.springrecipes.shop.Product;
import com.apress.springrecipes.shop.ProductCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


import java.util.HashMap;
import java.util.Map;


@Configuration
public class ShopConfiguration {


    @Bean
    public ProductCreator productCreatorFactory() {


        ProductCreator factory = new ProductCreator();
        Map<String, Product> products = new HashMap<>();
        products.put("aaa", new Battery("AAA", 2.5));
        products.put("cdrw", new Disc("CD-RW", 1.5));
        products.put("dvdrw", new Disc("DVD-RW", 3.0));
        factory.setProducts(products);
        return factory;
    }

    @Bean
    public Product aaa() {
        return productCreatorFactory().createProduct("aaa");
    }


    @Bean
    public Product cdrw() {
        return productCreatorFactory().createProduct("cdrw");
    }


    @Bean
    public Product dvdrw() {
        return productCreatorFactory().createProduct("dvdrw");
    }


}

Create POJOs Using Spring’s Factory Bean

Although you’ll seldom have to write custom factory beans, you may find it helpful to understand their internal mechanisms through an example. For example, you can write a factory bean for creating a product with a discount applied to the price. It accepts a product property and a discount property to apply the discount to the product and return it as a new bean.

package com.apress.springrecipes.shop;

import org.springframework.beans.factory.config.AbstractFactoryBean;

public class DiscountFactoryBean extends AbstractFactoryBean<Product> {

    private Product product;
    private double discount;


    public void setProduct(Product product) {
        this.product = product;
    }


    public void setDiscount(double discount) {
        this.discount = discount;
    }


    public Class<?> getObjectType() {
        return product.getClass();
    }


    protected Product createInstance() throws Exception {
        product.setPrice(product.getPrice() * (1 - discount));
        return product;
    }
}

By extending the AbstractFactoryBean class, the factory bean can simply override the createInstance() method to create the target bean instance. In addition, you have to return the target bean’s type in the getObjectType() method for the autowiring feature to work properly.

Next, you can declare product instances using a regular @Bean annotation to apply DiscountFactoryBean.

package com.apress.springrecipes.shop.config;

import com.apress.springrecipes.shop.Battery;
import com.apress.springrecipes.shop.Disc;
import com.apress.springrecipes.shop.DiscountFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;


@Configuration
@ComponentScan("com.apress.springrecipes.shop")
public class ShopConfiguration {
    @Bean
    public Battery aaa() {
        Battery aaa = new Battery("AAA", 2.5);
        return aaa;
    }


    @Bean
    public Disc cdrw() {
        Disc aaa = new Disc("CD-RW", 1.5);
        return aaa;
    }


    @Bean
    public Disc dvdrw() {
        Disc aaa = new Disc("DVD-RW", 3.0);
        return aaa;
    }

    @Bean
    public DiscountFactoryBean discountFactoryBeanAAA() {
        DiscountFactoryBean factory = new DiscountFactoryBean();
        factory.setProduct(aaa());
        factory.setDiscount(0.2);
        return factory;
    }


    @Bean
    public DiscountFactoryBean discountFactoryBeanCDRW() {
        DiscountFactoryBean factory = new DiscountFactoryBean();
        factory.setProduct(cdrw());
        factory.setDiscount(0.1);
        return factory;
    }


    @Bean
    public DiscountFactoryBean discountFactoryBeanDVDRW() {
        DiscountFactoryBean factory = new DiscountFactoryBean();
        factory.setProduct(dvdrw());
        factory.setDiscount(0.1);
        return factory;
    }
}

2-11. Use Spring Environments and Profiles to Load Different Sets of POJOs

Problem

You want to use the same set of POJO instances or beans but with different instantiation values for different application scenarios (e.g., production and development and testing).

Solution

Create multiple Java configuration classes and group POJOs instances or beans into each of these classes. Assign a profile name to the Java configuration class with the @Profile annotation based on the purpose of the group. Get the environment for an application’s context and set the profile to load a specific group of POJOs.

How It Works

POJO instantiation values can vary depending on different application scenarios. For example, a common scenario can occur when an application goes from development to testing and on to production. In each of these scenarios, the properties for certain beans can vary slightly to accommodate environment changes (e.g., database username/password, file paths, etc.).

You can create multiple Java configuration classes each with different POJOs (e.g., ShopConfigurationGlobal, ShopConfigurationStr, and ShopConfigurationSumWin) and, in the application context, only load a given configuration class file based on the scenario.

Create a Java Configuration Class with the @Profile Annotation

Let’s create a multiple Java configuration class with an @Profile annotation for the shopping application presented in previous recipes.

package com.apress.springrecipes.shop.config;

import com.apress.springrecipes.shop.Cashier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;


@Configuration
@Profile("global")
@ComponentScan("com.apress.springrecipes.shop")
public class ShopConfigurationGlobal {


    @Bean(initMethod = "openFile", destroyMethod = "closeFile")
    public Cashier cashier() {
        final String path = System.getProperty("java.io.tmpdir") + "cashier";
        Cashier c1 = new Cashier();
        c1.setFileName("checkout");
        c1.setPath(path);
        return c1;
    }
}
package com.apress.springrecipes.shop.config;


import com.apress.springrecipes.shop.Battery;
import com.apress.springrecipes.shop.Disc;
import com.apress.springrecipes.shop.Product;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;


@Configuration
@Profile({"summer", "winter"})
public class ShopConfigurationSumWin {
    @Bean
    public Product aaa() {
        Battery p1 = new Battery();
        p1.setName("AAA");
        p1.setPrice(2.0);
        p1.setRechargeable(true);
        return p1;
    }

    @Bean
    public Product cdrw() {
        Disc p2 = new Disc("CD-RW", 1.0);
        p2.setCapacity(700);
        return p2;
    }


    @Bean
    public Product dvdrw() {
        Disc p2 = new Disc("DVD-RW", 2.5);
        p2.setCapacity(700);
        return p2;
    }
}

The @Profile annotation decorates the entire Java configuration class, so all the @Bean instances belong to the same profile. To assign an @Profile name, you just place the name inside "". Notice it’s also possible to assign multiple @Profile names using a comma-separated value (CSV) syntax surrounded by {} (e.g., {"summer","winter"}).

Load the Profile into Environment

To load the beans from a certain profile into an application, you need to activate a profile. You can load multiple profiles at a time, and it’s also possible to load profiles programmatically, through a Java runtime flag or even as an initialization parameter of a WAR file.

To load profiles programmatically (i.e., via the application context), you get the context environment from where you can load profiles via the setActiveProfiles() method.

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.getEnvironment().setActiveProfiles("global", "winter");
context.scan("com.apress.springrecipes.shop");
context.refresh();

It’s also possible to indicate which Spring profile to load via a Java runtime flag. In this manner, you can pass the following runtime flag to load all beans that belong to the global and winter profiles:

-Dspring.profiles.active=global,winter

Set a Default Profile

To avoid the possibility of errors because no profiles are loaded into an application, you can define default profiles. Default profiles are used only when Spring can’t detect any active profiles, which are defined programmatically, via a Java runtime flag, or with a web application initialization parameter.

To set up default profiles, you can also use any of the three methods to set up active profiles. Programmatically you use the method setDefaultProfiles() instead of setActiveProfiles(), and via a Java runtime flag or web application initialization parameter , you can use the spring.profiles.default parameter instead of spring.profiles.active.

2-12. Make POJOs Aware of Spring’s IoC Container Resources

Problem

Even though a well-designed component should not have direct dependencies on Spring’s IoC container , sometimes it’s necessary for 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. Table 2-2 lists the most common ones. Spring injects the corresponding resources to beans that implement these interfaces via the setter methods defined in these interfaces.

Table 2-2. Common Aware Interfaces in Spring

Aware Interface

Target Resource Type

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

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

EnvironmentAware

The org.springframework.core.env.Environment instance associated with the ApplicationContext interface

Note

The ApplicationContext interface in fact 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 are 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. Pass the bean instance to the postProcessBeforeInitialization() method of each bean post-processor. Call the initialization callback methods.

  5. Pass the bean instance to the postProcessAfterInitialization() method of each bean post-processor. The bean is ready to be used.

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

Keep in mind that once a class implements an aware interface, they are bound to Spring and won’t work properly outside the Spring IoC container. So, consider carefully whether it’s necessary to implement such proprietary interfaces.

Note

With the newer versions of Spring, it is not strictly necessary to implement the aware interfaces. You could also use @Autowired to get, for instance, access to the ApplicationContext. However, if you are writing a framework/library, it might be better to implement the interfaces.

How It Works

For example, you can make the shopping application’s POJO instances of the Cashier class aware of their corresponding bean names by implementing the BeanNameAware interface . By implementing the interface, Spring automatically injects the bean name into the POJO instance. In addition to implementing the interface, you also need to add the necessary setter method to handle the bean name.

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


public class Cashier implements BeanNameAware {
    ...
    private String fileName;


    public void setBeanName(String beanName) {
        this.fileName = beanName;
    }
}

When a bean name is injected, you can use the value to do a related POJO task that requires the bean name. For example, you could use the value to set the file name to record a cashier’s checkout data. In this way, you can erase the configuration of the fileName property and setFileName() method .

@Bean(initMethod = "openFile", destroyMethod = "closeFile")
public Cashier cashier() {
    final String path = System.getProperty("java.io.tmpdir") + "cashier";
    Cashier cashier = new Cashier();
    cashier.setPath(path);
    return c1;
}

2-13. Use Aspect-Oriented Programming with Annotations

Problem

You want to use aspect-oriented programming with Spring and annotations.

Solution

You define an aspect by decorating a Java class with the @Aspect annotation. Each of the methods in a class can become an advice with another annotation. You can use five types of advice annotations: @Before, @After, @AfterReturning, @AfterThrowing, and @Around.

To enable annotation support in the Spring IoC container, you have to add @EnableAspectJAutoProxy to one of your configuration classes. To apply AOP, Spring creates proxies, and by default it creates JDK dynamic proxies, which are interface-based. For cases in which interfaces are not available or not used in an application’s design, it’s possible to create proxies by relying on CGLIB. To enable CGLIB, you need to set the attribute proxyTargetClass=true on the @EnableAspectJAutoProxy annotation.

How It Works

To support aspect-oriented programming with annotations, Spring uses the same annotations as AspectJ, using a library supplied by AspectJ for pointcut parsing and matching. However, the AOP runtime is still pure Spring AOP, and there is no dependency on the AspectJ compiler or weaver.

To illustrate the enablement of aspect-oriented programming with annotations, you’ll use the following calculator interfaces to define a set of sample POJOs :

package com.apress.springrecipes.calculator;

public interface ArithmeticCalculator {

    public double add(double a, double b);
    public double sub(double a, double b);
    public double mul(double a, double b);
    public double div(double a, double b);
}
package com.apress.springrecipes.calculator;


public interface UnitCalculator {

    public double kilogramToPound(double kilogram);
    public double kilometerToMile(double kilometer);
}

Next, let’s create POJO classes for each interface with println statements to know when each method is executed:

package com.apress.springrecipes.calculator;

import org.springframework.stereotype.Component;

@Component("arithmeticCalculator")
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {


    public double add(double a, double b) {
        double result = a + b;
        System.out.println(a + " + " + b + " = " + result);
        return result;
    }


    public double sub(double a, double b) {
        double result = a - b;
        System.out.println(a + " - " + b + " = " + result);
        return result;
    }
    public double mul(double a, double b) {
        double result = a * b;
        System.out.println(a + " * " + b + " = " + result);
        return result;
    }


    public double div(double a, double b) {
        if (b == 0) {
            throw new IllegalArgumentException("Division by zero");
        }
        double result = a / b;
        System.out.println(a + " / " + b + " = " + result);
        return result;
    }
}
package com.apress.springrecipes.calculator;


import org.springframework.stereotype.Component;

@Component("unitCalculator")
public class UnitCalculatorImpl implements UnitCalculator {


    public double kilogramToPound(double kilogram) {
        double pound = kilogram * 2.2;
        System.out.println(kilogram + " kilogram = " + pound + " pound");
        return pound;
    }


    public double kilometerToMile(double kilometer) {
        double mile = kilometer * 0.62;
        System.out.println(kilometer + " kilometer = " + mile + " mile");
        return mile;
    }
}

Note that each POJO implementation is decorated with the @Component annotation to create bean instances.

Declare Aspects, Advices, and Pointcuts

An aspect is a Java class that modularizes a set of concerns (e.g., logging or transaction management) that cuts across multiple types and objects. Java classes that modularize such concerns are decorated with the @Aspect annotation. In AOP terminology, aspects are also complemented by advices, which in themselves have pointcuts. An advice is a simple Java method with one of the advice annotations. AspectJ supports five types of advice annotations : @Before, @After, @AfterReturning, @AfterThrowing, and @Around. A pointcut is an expression that looks for types and objects on which to apply the aspect’s advices.

Aspect with @Before Advice

To create a before advice to handle crosscutting concerns before particular program execution points, you use the @Before annotation and include the pointcut expression as the annotation value.

package com.apress.springrecipes.calculator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;


@Aspect
@Component
public class CalculatorLoggingAspect {


    private Log log = LogFactory.getLog(this.getClass());

    @Before("execution(* ArithmeticCalculator.add(..))")
    public void logBefore() {
        log.info("The method add() begins");
    }
}

This pointcut expression matches the add() method execution of the ArithmeticCalculator interface. The preceding wildcard in this expression matches any modifier (public, protected, and private) and any return type. The two dots in the argument list match any number of arguments.

For the previous aspect to work (i.e., output its message), you need to set up logging. Specifically, create a logback.xml file with configuration properties like the following.

<?xml version="1.0" encoding="UTF-8"?>                
<configuration>


    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <Pattern>%d [%15.15t] %-5p %30.30c - %m%n</Pattern>
        </layout>
    </appender>


    <root level="INFO">
        <appender-ref ref="STDOUT" />
    </root>


</configuration>
Note

The @Aspect annotation is not sufficient for autodetection in the classpath. Therefore, you need to add a separate @Component annotation for the POJO to be detected.

Next, you create a Spring configuration to scan all POJOs, including the POJO calculator implementation and aspect and including the @EnableAspectJAutoProxy annotation.

@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class CalculatorConfiguration {
}

As the last step, you can test the aspect with the following Main class:

package com.apress.springrecipes.calculator;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class Main {

    public static void main(String[] args) {

        ApplicationContext context =
            new AnnotationConfigApplicationContext(CalculatorConfiguration.class);


        ArithmeticCalculator arithmeticCalculator =
            context.getBean("arithmeticCalculator", ArithmeticCalculator.class);
        arithmeticCalculator.add(1, 2);
        arithmeticCalculator.sub(4, 3);
        arithmeticCalculator.mul(2, 3);
        arithmeticCalculator.div(4, 2);


        UnitCalculator unitCalculator = context.getBean("unitCalculator", UnitCalculator.class);
        unitCalculator.kilogramToPound(10);
        unitCalculator.kilometerToMile(5);
    }
}

The execution points matched by a pointcut are called join points. In this term, a pointcut is an expression to match a set of join points, while an advice is the action to take at a particular join point.

For your advice to access the detail of the current join point, you can declare an argument of type JoinPoint in your advice method. Then, you can get access to join point details such as the method name and argument values. Now, you can expand your pointcut to match all methods by changing the class name and method name to wildcards.

package com.apress.springrecipes.calculator;
...
import java.util.Arrays;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;


@Aspect
@Component
public class CalculatorLoggingAspect {
    ...
    @Before("execution(* *.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        log.info("The method " + joinPoint.getSignature().getName()
            + "() begins with " + Arrays.toString(joinPoint.getArgs()));
    }
}

Use an Aspect with @After Advice

An after advice is executed after a join point finishes and is represented by a method annotated with @After, whenever it returns a result or throws an exception. The following after advice logs the calculator method ending:

package com.apress.springrecipes.calculator;
...
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;


@Aspect
public class CalculatorLoggingAspect {
    ...
    @After("execution(* *.*(..))")
    public void logAfter(JoinPoint joinPoint) {
        log.info("The method " + joinPoint.getSignature().getName()
            + "() ends");
    }
}

Use an Aspect with @AfterReturning Advice

An after advice is executed regardless of whether a join point returns normally or throws an exception . If you would like to perform logging only when a join point returns, you should replace the after advice with an after returning advice.

package com.apress.springrecipes.calculator;
...
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;


@Aspect
public class CalculatorLoggingAspect {
    ...
    @AfterReturning("execution(* *.*(..))")
    public void logAfterReturning(JoinPoint joinPoint) {
        log.info("The method {}() ends with {}", joinPoint.getSignature().getName(), result);
    }
}

In an after returning advice, you can get access to the return value of a join point by adding a returning attribute to the @AfterReturning annotation. The value of this attribute should be the argument name of this advice method for the return value to pass in. Then, you have to add an argument to the advice method signature with this name. At runtime, Spring AOP will pass in the return value through this argument. Also note that the original pointcut expression needs to be presented in the pointcut attribute instead.

package com.apress.springrecipes.calculator;
...
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;


@Aspect
public class CalculatorLoggingAspect {
    ...
    @AfterReturning(
        pointcut = "execution(* *.*(..))",
        returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        log.info("The method " + joinPoint.getSignature().getName()
            + "() ends with " + result);
    }
}

Use an Aspect with @AfterThrowing Advice

An after throwing advice is executed only when an exception is thrown by a join point.

package com.apress.springrecipes.calculator;
...
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;


@Aspect
public class CalculatorLoggingAspect {
    ...
    @AfterThrowing("execution(* *.*(..))")
    public void logAfterThrowing(JoinPoint joinPoint) {
        log.error("An exception has been thrown in {}()", joinPoint.getSignature().getName());
    }
}

Similarly, the exception thrown by the join point can be accessed by adding a throwing attribute to the @AfterThrowing annotation . The type Throwable is the superclass of all errors and exceptions in the Java language. So, the following advice will catch any of the errors and exceptions thrown by the join points:

package com.apress.springrecipes.calculator;
...
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;


@Aspect
public class CalculatorLoggingAspect {
    ...
    @AfterThrowing(
        pointcut = "execution(* *.*(..))",
        throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
        log.error("An exception {} has been thrown in {}()", e, joinPoint.getSignature().getName());
    }
}

However, if you are interested in one particular type of exception only, you can declare it as the argument type of the exception. Then your advice will be executed only when exceptions of compatible types (i.e., this type and its subtypes) are thrown.

package com.apress.springrecipes.calculator;
...
import java.util.Arrays;


import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;


@Aspect
public class CalculatorLoggingAspect {
    ...
    @AfterThrowing(
        pointcut = "execution(* *.*(..))",
        throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, IllegalArgumentException e) {
        log.error("Illegal argument {} in {}()", Arrays.toString(joinPoint.getArgs()), joinPoint.getSignature().getName());
    }
}

Use an Aspect with @Around Advice

The last type of advice is an around advice . It is the most powerful of all the advice types. It gains full control of a join point, so you can combine all the actions of the preceding advices into one single advice. You can even control when, and whether, to proceed with the original join point execution.

The following around advice is the combination of the before, after returning, and after throwing advices you created earlier. Note that for an around advice, the argument type of the join point must be ProceedingJoinPoint. It’s a subinterface of JoinPoint that allows you to control when to proceed with the original join point.

package com.apress.springrecipes.calculator;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


import java.util.Arrays;

@Aspect
@Component
public class CalculatorLoggingAspect {


    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Around("execution(* *.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {


        log.info("The method {}() begins with {}", joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
        try {
            Object result = joinPoint.proceed();
            log.info("The method {}() ends with ", joinPoint.getSignature().getName(), result);
            return result;
        } catch (IllegalArgumentException e) {
            log.error("Illegal argument {} in {}()", Arrays.toString(joinPoint.getArgs()) , joinPoint.getSignature().getName());
            throw e;
        }
    }
}

The around advice type is powerful and flexible in that you can even alter the original argument values and change the final return value. You must use this type of advice with great care, as the call to proceed with the original join point may easily be forgotten.

Tip

A common rule for choosing an advice type is to use the least powerful one that can satisfy your requirements.

2-14. Access the Join Point Information

Problem

In AOP, an advice is applied to different program execution points that are called join points. For an advice to take the correct action, it often requires detailed information about join points.

Solution

An advice can access the current join point information by declaring an argument of type org.aspectj.lang.JoinPoint in the advice method signature.

How It Works

For example, you can access the join point information through the following advice. The information includes the join point kind (only method execution in Spring AOP), the method signature (declaring type and method name), and the argument values, as well as the target object and proxy object.

package com.apress.springrecipes.calculator;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


import java.util.Arrays;

@Aspect
@Component
public class CalculatorLoggingAspect {


    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Before("execution(* *.*(..))")
    public void logJoinPoint(JoinPoint joinPoint) {


        log.info("Join point kind : {}", joinPoint.getKind());
        log.info("Signature declaring type : {}", joinPoint.getSignature().getDeclaringTypeName());
        log.info("Signature name : {}", joinPoint.getSignature().getName());
        log.info("Arguments : {}", Arrays.toString(joinPoint.getArgs()));
        log.info("Target class : {}", joinPoint.getTarget().getClass().getName());
        log.info("This class : {}", joinPoint.getThis().getClass().getName());
    }
}

The original bean that was wrapped by a proxy is called the target object , while the proxy object is the this object. They can be accessed by the join point’s getTarget() and getThis() methods. From the following outputs, you can see that the classes of these two objects are not the same:

Join point kind : method-execution
Signature declaring type : com.apress.springrecipes.calculator.ArithmeticCalculator
Signature name : add
Arguments : [1.0, 2.0]
Target class : com.apress.springrecipes.calculator.ArithmeticCalculatorImpl
This class : com.sun.proxy.$Proxy6

2-15. Specify Aspect Precedence with the @Order Annotation

Problem

When there’s more than one aspect applied to the same join point, the precedence of the aspects is undefined unless you have explicitly specified it.

Solution

The precedence of aspects can be specified either by implementing the Ordered interface or by using the @Order annotation.

How It Works

Suppose you have written another aspect to validate the calculator arguments. There’s only one before advice in this aspect.

package com.apress.springrecipes.calculator;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;


import org.springframework.stereotype.Component;

@Aspect
@Component
public class CalculatorValidationAspect {


    @Before("execution(* *.*(double, double))")
    public void validateBefore(JoinPoint joinPoint) {
        for (Object arg : joinPoint.getArgs()) {
            validate((Double) arg);
        }
    }


    private void validate(double a) {
        if (a < 0) {
            throw new IllegalArgumentException("Positive numbers only");
        }
    }
}

If you apply this aspect and the previous, you can’t guarantee which one is applied first. To guarantee that one aspect is applied before another, you need to specify precedence. To specify precedence, you have to make both aspects implement the Ordered interface or use the @Order annotation.

If you decide to implement the Ordered interface , the lower value returned by the getOrder method represents higher priority. So, if you prefer the validation aspect to be applied first, it should return a value lower than the logging aspect.

package com.apress.springrecipes.calculator;
...
import org.springframework.core.Ordered;


@Aspect
@Component
public class CalculatorValidationAspect implements Ordered {
    ...
    public int getOrder() {
        return 0;
    }
}
package com.apress.springrecipes.calculator;
...
import org.springframework.core.Ordered;


@Aspect
@Component
public class CalculatorLoggingAspect implements Ordered {
    ...
    public int getOrder() {
        return 1;
    }
}

Another way to specify precedence is through the @Order annotation. The order number should be presented in the annotation value.

package com.apress.springrecipes.calculator;
...
import org.springframework.core.annotation.Order;


@Aspect
@Component
@Order(0)
public class CalculatorValidationAspect { ... }
package com.apress.springrecipes.calculator;
...
import org.springframework.core.annotation.Order;

@Aspect
@Component
@Order(1)
public class CalculatorLoggingAspect { ... }

2-16. Reuse Aspect Pointcut Definitions

Problem

When writing aspects, you can directly embed a pointcut expression in an advice annotation. You want to use the same pointcut expression in multiple advices without embedding it multiple times.

Solution

You can use the @Pointcut annotation to define a pointcut independently to be reused in multiple advices.

How It Works

In an aspect, a pointcut can be declared as a simple method with the @Pointcut annotation. The method body of a pointcut is usually empty because it is unreasonable to mix a pointcut definition with application logic. The access modifier of a pointcut method controls the visibility of this pointcut as well. Other advices can refer to this pointcut by the method name.

package com.apress.springrecipes.calculator;
...
import org.aspectj.lang.annotation.Pointcut;


@Aspect
@Component
public class CalculatorLoggingAspect {
    ...
    @Pointcut("execution(* *.*(..))")
    private void loggingOperation() {}


    @Before("loggingOperation()")
    public void logBefore(JoinPoint joinPoint) {
        ...
    }


    @AfterReturning(
        pointcut = "loggingOperation()",
        returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        ...
    }


    @AfterThrowing(
        pointcut = "loggingOperation()",
        throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, IllegalArgumentException e) {
        ...
    }


    @Around("loggingOperation()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        ...
    }
}

Usually, if your pointcuts are shared between multiple aspects, it is better to centralize them in a common class. In this case, they must be declared as public.

package com.apress.springrecipes.calculator;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;


@Aspect
public class CalculatorPointcuts {


    @Pointcut("execution(* *.*(..))")
    public void loggingOperation() {}
}

When you refer to this pointcut, you have to include the class name as well. If the class is not located in the same package as the aspect, you have to include the package name also.

package com.apress.springrecipes.calculator;
...
@Aspect
public class CalculatorLoggingAspect {
    ...
    @Before("CalculatorPointcuts.loggingOperation()")
    public void logBefore(JoinPoint joinPoint) {
        ...
    }


    @AfterReturning(
        pointcut = "CalculatorPointcuts.loggingOperation()",
        returning = "result")
    public void logAfterReturning(JoinPoint joinPoint, Object result) {
        ...
    }


    @AfterThrowing(
        pointcut = "CalculatorPointcuts.loggingOperation()",
        throwing = "e")
    public void logAfterThrowing(JoinPoint joinPoint, IllegalArgumentException e) {
        ...
    }


    @Around("CalculatorPointcuts.loggingOperation()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        ...
    }
}

2-17. Write AspectJ Pointcut Expressions

Problem

Crosscutting concerns can happen at different program execution points called join points. Because of the variety of join points, you need a powerful expression language to help match them.

Solution

The AspectJ pointcut language is a powerful expression language that can match various kinds of join points. However, Spring AOP only supports method execution join points for beans declared in its IoC container. For this reason, only those pointcut expressions supported by Spring AOP are presented in this recipe. For a full description of the AspectJ pointcut language, please refer to the AspectJ programming guide available on AspectJ’s web site ( www.eclipse.org/aspectj/ ). Spring AOP makes use of the AspectJ pointcut language for its pointcut definition and interprets the pointcut expressions at runtime by using a library provided by AspectJ. When writing AspectJ pointcut expressions for Spring AOP, you must keep in mind that Spring AOP only supports method execution join points for the beans in its IoC container. If you use a pointcut expression out of this scope, an IllegalArgumentException is thrown.

How It Works

Lets explore the, by Spring, supported patterns for writing pointcut expression. First you will see how to write pointcuts based on message signatures, type patterns and how to use (and access) method arguments.

Use Method Signature Patterns

The most typical pointcut expressions are used to match a number of methods by their signatures . For example, the following pointcut expression matches all of the methods declared in the ArithmeticCalculator interface. The initial wildcard matches methods with any modifier (public, protected, and private) and any return type. The two dots in the argument list match any number of arguments.

execution(* com.apress.springrecipes.calculator.ArithmeticCalculator.*(..))

You can omit the package name if the target class or interface is located in the same package as the aspect.

execution(* ArithmeticCalculator.*(..))

The following pointcut expression matches all the public methods declared in the ArithmeticCalculator interface:

execution(public * ArithmeticCalculator.*(..))

You can also restrict the method return type. For example, the following pointcut matches the methods that return a double number:

execution(public double ArithmeticCalculator.*(..))

The argument list of the methods can also be restricted. For example, the following pointcut matches the methods whose first argument is of primitive double type. The two dots then match any number of followed arguments.

execution(public double ArithmeticCalculator.*(double, ..))

Or, you can specify all the argument types in the method signature for the pointcut to match.

execution(public double ArithmeticCalculator.*(double, double))

Although the AspectJ pointcut language is powerful in matching various join points, sometimes you may not be able to find any common characteristics (e.g., modifiers, return types, method name patterns, or arguments) for the methods you want to match. In such cases, you can consider providing a custom annotation for them. For instance, you can define the following marker annotation. This annotation can be applied to both method level and type level.

package com.apress.springrecipes.calculator;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


@Target( { ElementType.METHOD, ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoggingRequired {
}

Next, you can annotate all methods that require logging with this annotation or the class itself to apply the behavior to all methods. Note that the annotations must be added to the implementation class but not the interface, as they will not be inherited.

package com.apress.springrecipes.calculator;

@LoggingRequired
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {


    public double add(double a, double b) {
        ...
    }


    public double sub(double a, double b) {
        ...
    }


    ...
}

Then you can write a pointcut expression to match a class or methods with the @LoggingRequired annotation using the annotation keyword on the @Pointcut annotation.

package com.apress.springrecipes.calculator;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;


@Aspect
public class CalculatorPointcuts {


    @Pointcut("annotation(com.apress.springrecipes.calculator.LoggingRequired)")
    public void loggingOperation() {}


}

Use Type Signature Patterns

Another kind of pointcut expression matches all join points within certain types. When applied to Spring AOP, the scope of these pointcuts will be narrowed to matching all method executions within the types. For example, the following pointcut matches all the method execution join points within the com.apress.springrecipes.calculator package:

within(com.apress.springrecipes.calculator.*)

To match the join points within a package and its subpackage, you have to add one more dot before the wildcard.

within(com.apress.springrecipes.calculator..*)

The following pointcut expression matches the method execution join points within a particular class:

within(com.apress.springrecipes.calculator.ArithmeticCalculatorImpl)

Again, if the target class is located in the same package as this aspect, the package name can be omitted.

within(ArithmeticCalculatorImpl)

You can match the method execution join points within all classes that implement the ArithmeticCalculator interface by adding a plus symbol.

within(ArithmeticCalculator+)

The custom annotation @LoggingRequired can be applied to the class or method level, as illustrated previously.

package com.apress.springrecipes.calculator;

@LoggingRequired
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
    ...
}

Then you can match the join points within the classes or methods that have been annotated with @LoggingRequired using the within keyword on the @Pointcut annotation.

@Pointcut("within(com.apress.springrecipes.calculator.LoggingRequired)")
public void loggingOperation() {}

Combine Pointcut Expressions

In AspectJ, pointcut expressions can be combined with the operators && (and), || (or), and ! (not). For example, the following pointcut matches the join points within classes that implement either the ArithmeticCalculator or UnitCalculator interface:

within(ArithmeticCalculator+) || within(UnitCalculator+)

The operands of these operators can be any pointcut expressions or references to other pointcuts.

package com.apress.springrecipes.calculator;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;


@Aspect
public class CalculatorPointcuts {


    @Pointcut("within(ArithmeticCalculator+)")
    public void arithmeticOperation() {}


    @Pointcut("within(UnitCalculator+)")
    public void unitOperation() {}


    @Pointcut("arithmeticOperation() || unitOperation()")
    public void loggingOperation() {}
}

Declare Pointcut Parameters

One way to access join point information is by reflection (i.e., via an argument of type org.aspectj.lang.JoinPoint in the advice method). Besides, you can access join point information in a declarative way by using some kinds of special pointcut expressions . For example, the expressions target() and args() capture the target object and argument values of the current join point and expose them as pointcut parameters. These parameters are passed to your advice method via arguments of the same name.

package com.apress.springrecipes.calculator;
...
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;


@Aspect
public class CalculatorLoggingAspect {
    ...
    @Before("execution(* *.*(..)) && target(target) && args(a,b)")
    public void logParameter(Object target, double a, double b) {
        log.info("Target class : {}", target.getClass().getName());
        log.info("Arguments : {}, {}", a,b);
    }
}

When declaring an independent pointcut that exposes parameters, you have to include them in the argument list of the pointcut method as well.

package com.apress.springrecipes.calculator;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;


@Aspect
public class CalculatorPointcuts {
    ...
    @Pointcut("execution(* *.*(..)) && target(target) && args(a,b)")
    public void parameterPointcut(Object target, double a, double b) {}
}

Any advice that refers to this parameterized pointcut can access the pointcut parameters via method arguments of the same name.

package com.apress.springrecipes.calculator;
...
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;


@Aspect
public class CalculatorLoggingAspect {
    ...
    @Before("CalculatorPointcuts.parameterPointcut(target, a, b)")
    public void logParameter(Object target, double a, double b) {
        log.info("Target class : {}", target.getClass().getName());
        log.info("Arguments : {}, {}"a,b);
    }
}

2-18. Use AOP for introductions for POJOs

Problem

Sometimes you may have a group of classes that share a common behavior. In OOP, they must extend the same base class or implement the same interface. This issue is actually a crosscutting concern that can be modularized with AOP. In addition, the single inheritance mechanism of Java only allows a class to extend one base class at most. So, you cannot inherit behaviors from multiple implementation classes at the same time.

Solution

An introduction is a special type of advice in AOP. It allows objects to implement an interface dynamically by providing an implementation class for that interface. It seems as if objects extend an implementation class at runtime. Moreover, you are able to introduce multiple interfaces with multiple implementation classes to your objects at the same time. This can achieve the same effect as multiple inheritance.

How It Works

Suppose you have two interfaces, MaxCalculator and MinCalculator, to define the max() and min() operations.

package com.apress.springrecipes.calculator;

public interface MaxCalculator {

    public double max(double a, double b);
}
package com.apress.springrecipes.calculator;


public interface MinCalculator {

    public double min(double a, double b);
}

Then you have an implementation for each interface with println statements to let you know when the methods are executed.

package com.apress.springrecipes.calculator;

public class MaxCalculatorImpl implements MaxCalculator {

    public double max(double a, double b) {
        double result = (a >= b) ? a : b;
        System.out.println("max(" + a + ", " + b + ") = " + result);
        return result;
    }
}
package com.apress.springrecipes.calculator;


public class MinCalculatorImpl implements MinCalculator {

    public double min(double a, double b) {
        double result = (a <= b) ? a : b;
        System.out.println("min(" + a + ", " + b + ") = " + result);
        return result;
    }
}

Now, suppose you want ArithmeticCalculatorImpl to perform the max() and min() calculation also. As the Java language supports single inheritance only, it is not possible for the ArithmeticCalculatorImpl class to extend both the MaxCalculatorImpl and MinCalculatorImpl classes at the same time. The only possible way is to extend either class (e.g., MaxCalculatorImpl) and implement another interface (e.g., MinCalculator), either by copying the implementation code or by delegating the handling to the actual implementation class. In either case, you have to repeat the method declarations.

With an introduction, you can make ArithmeticCalculatorImpl dynamically implement both the MaxCalculator and MinCalculator interfaces by using the implementation classes MaxCalculatorImpl and MinCalculatorImpl. It has the same effect as multiple inheritance from MaxCalculatorImpl and MinCalculatorImpl. The idea behind an introduction is that you needn’t modify the ArithmeticCalculatorImpl class to introduce new methods. That means you can introduce methods to your existing classes even without source code available.

Tip

You may wonder how an introduction can do that in Spring AOP. The answer is a dynamic proxy. As you may recall, you can specify a group of interfaces for a dynamic proxy to implement. Introduction works by adding an interface (e.g., MaxCalculator) to the dynamic proxy. When the methods declared in this interface are called on the proxy object, the proxy will delegate the calls to the back-end implementation class (e.g., MaxCalculatorImpl).

Introductions, like advices, must be declared within an aspect. You may create a new aspect or reuse an existing aspect for this purpose. In this aspect, you can declare an introduction by annotating an arbitrary field with the @DeclareParents annotation.

package com.apress.springrecipes.calculator;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;


import org.springframework.stereotype.Component;

@Aspect
@Component
public class CalculatorIntroduction {


    @DeclareParents(
        value = "com.apress.springrecipes.calculator.ArithmeticCalculatorImpl",
        defaultImpl = MaxCalculatorImpl.class)
    public MaxCalculator maxCalculator;


    @DeclareParents(
        value = "com.apress.springrecipes.calculator.ArithmeticCalculatorImpl",
        defaultImpl = MinCalculatorImpl.class)
    public MinCalculator minCalculator;
}

The value attribute of the @DeclareParents annotation type indicates which classes are the targets for this introduction. The interface to introduce is determined by the type of the annotated field. Finally, the implementation class used for this new interface is specified in the defaultImpl attribute.

Through these two introductions, you can dynamically introduce a couple of interfaces to the ArithmeticCalculatorImpl class. Actually, you can specify an AspectJ type-matching expression in the value attribute of the @DeclareParents annotation to introduce an interface to multiple classes.

As you have introduced both the MaxCalculator and MinCalculator interfaces to your arithmetic calculator, you can cast it to the corresponding interface to perform the max() and min() calculations.

package com.apress.springrecipes.calculator;

public class Main {

    public static void main(String[] args) {
        ...
        ArithmeticCalculator arithmeticCalculator =
            (ArithmeticCalculator) context.getBean("arithmeticCalculator");
        ...
        MaxCalculator maxCalculator = (MaxCalculator) arithmeticCalculator;
        maxCalculator.max(1, 2);


        MinCalculator minCalculator = (MinCalculator) arithmeticCalculator;
        minCalculator.min(1, 2);
    }
}

2-19. Introduce States to Your POJOs with AOP

Problem

Sometimes you may want to add new states to a group of existing objects to keep track of their usage, such as the calling count, the last modified date, and so on. It should not be a solution if all the objects have the same base class. However, it’s difficult to add such states to different classes if they are not in the same class hierarchy.

Solution

You can introduce a new interface to your objects with an implementation class that holds the state field. Then, you can write another advice to change the state according to a particular condition.

How It Works

Suppose you want to keep track of the calling count of each calculator object. Since there is no field for storing the counter value in the original calculator classes, you need to introduce one with Spring AOP. First, let’s create an interface for the operations of a counter .

package com.apress.springrecipes.calculator;

public interface Counter {

    public void increase();
    public int getCount();
}

Next, just write a simple implementation class for this interface. This class has a count field for storing the counter value.

package com.apress.springrecipes.calculator;

public class CounterImpl implements Counter {

    private int count;

    public void increase() {
        count++;
    }


    public int getCount() {
        return count;
    }
}

To introduce the Counter interface to all your calculator objects with CounterImpl as the implementation, you can write the following introduction with a type-matching expression that matches all the calculator implementations:

package com.apress.springrecipes.calculator;
...
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;


@Aspect
@Component
public class CalculatorIntroduction {
    ...
    @DeclareParents(
        value = "com.apress.springrecipes.calculator.*CalculatorImpl",
        defaultImpl = CounterImpl.class)
    public Counter counter;
}

This introduction introduces CounterImpl to each of your calculator objects. However, it’s still not enough to keep track of the calling count. You have to increase the counter value each time a calculator method is called. You can write an after advice for this purpose. Note that you must get this object but not the target object, as only the proxy object implements the Counter interface.

package com.apress.springrecipes.calculator;
...
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;


@Aspect
@Component
public class CalculatorIntroduction {
    ...
    @After("execution(* com.apress.springrecipes.calculator.*Calculator.*(..))"
        + " && this(counter)")
    public void increaseCount(Counter counter) {
        counter.increase();
    }
}

In the Main class , you can output the counter value for each of the calculator objects by casting them into the Counter type.

package com.apress.springrecipes.calculator;

public class Main {

    public static void main(String[] args) {
        ...
        ArithmeticCalculator arithmeticCalculator =
            (ArithmeticCalculator) context.getBean("arithmeticCalculator");
        ...


        UnitCalculator unitCalculator =
            (UnitCalculator) context.getBean("unitCalculator");
        ...


        Counter arithmeticCounter = (Counter) arithmeticCalculator;
        System.out.println(arithmeticCounter.getCount());


        Counter unitCounter = (Counter) unitCalculator;
        System.out.println(unitCounter.getCount());
    }
}

2-20. Use Load-Time Weaving AspectJ Aspects in Spring

Problem

The Spring AOP framework supports only limited types of AspectJ pointcuts and allows aspects to apply to beans declared in the IoC container. If you want to use additional pointcut types or apply your aspects to objects created outside the Spring IoC container, you have to use the AspectJ framework in your Spring application.

Solution

Weaving is the process of applying aspects to your target objects. With Spring AOP, weaving happens at runtime through dynamic proxies. In contrast, the AspectJ framework supports both compile-time and load-time weaving.

AspectJ compile-time weaving is done through a special AspectJ compiler called ajc. It can weave aspects into your Java source files and output woven binary class files. It can also weave aspects into your compiled class files or JAR files. This process is known as post-compile-time weaving. You can perform compile-time and post-compile-time weaving for your classes before declaring them in the Spring IoC container. Spring is not involved in the weaving process at all. For more information on compile-time and post-compile-time weaving, please refer to the AspectJ documentation.

AspectJ load-time weaving (also known as LTW) happens when the target classes are loaded into JVM by a class loader. For a class to be woven, a special class loader is required to enhance the bytecode of the target class. Both AspectJ and Spring provide load-time weavers to add load-time weaving capability to the class loader. You need only simple configurations to enable these load-time weavers.

How It Works

To understand the AspectJ load-time weaving process in a Spring application, let’s consider a calculator for complex numbers. First, you create the Complex class to represent complex numbers. You define the toString() method for this class to convert a complex number into the string representation (a + bi).

package com.apress.springrecipes.calculator;

public class Complex {

    private int real;
    private int imaginary;


    public Complex(int real, int imaginary) {
        this.real = real;
        this.imaginary = imaginary;
    }


    // Getters and Setters
    ...


    public String toString() {
        return "(" + real + " + " + imaginary + "i)";
    }
}

Next, you define an interface for the operations on complex numbers. For simplicity’s sake, only add() and sub() are supported.

package com.apress.springrecipes.calculator;

public interface ComplexCalculator {

    public Complex add(Complex a, Complex b);
    public Complex sub(Complex a, Complex b);
}

The implementation code for this interface is as follows. Each time, you return a new complex object as the result.

package com.apress.springrecipes.calculator;

import org.springframework.stereotype.Component;

@Component("complexCalculator")
public class ComplexCalculatorImpl implements ComplexCalculator {


    public Complex add(Complex a, Complex b) {
        Complex result = new Complex(a.getReal() + b.getReal(),
            a.getImaginary() + b.getImaginary());
        System.out.println(a + " + " + b + " = " + result);
        return result;
    }


    public Complex sub(Complex a, Complex b) {
        Complex result = new Complex(a.getReal() - b.getReal(),
            a.getImaginary() - b.getImaginary());
        System.out.println(a + " - " + b + " = " + result);
        return result;
    }
}

Now, you can test this complex number calculator with the following code in the Main class:

package com.apress.springrecipes.calculator;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class Main {

    public static void main(String[] args) {

        ApplicationContext context =
            new AnnotationConfigApplicationContext(CalculatorConfiguration.class);


        ComplexCalculator complexCalculator =
            context.getBean("complexCalculator", ComplexCalculator.class);


        complexCalculator.add(new Complex(1, 2), new Complex(2, 3));
        complexCalculator.sub(new Complex(5, 8), new Complex(2, 3));
    }
}

So far, the complex calculator is working fine. However, you may want to improve the performance of the calculator by caching complex number objects. As caching is a well-known crosscutting concern, you can modularize it with an aspect.

package com.apress.springrecipes.calculator;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;


import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;


@Aspect
public class ComplexCachingAspect {


    private final Map<String, Complex> cache = new ConcurrentHashMap<>();

    @Around("call(public Complex.new(int, int)) && args(a,b)")
    public Object cacheAround(ProceedingJoinPoint joinPoint, int a, int b)
        throws Throwable {
        String key = a + "," + b;
        Complex complex = cache.get(key);
        if (complex == null) {
            System.out.println("Cache MISS for (" + key + ")");
            complex = (Complex) joinPoint.proceed();
            cache.put(key, complex);
        }
        else {
            System.out.println("Cache HIT for (" + key + ")");
        }
        return complex;
    }
}

In this aspect, you cache the complex objects in a map with their real and imaginary values as keys. Then, the most suitable time to look up the cache is when a complex object is created by invoking the constructor. You use the AspectJ pointcut expression call to capture the join points of calling the Complex(int,int) constructor.

Next, you need an around advice to alter the return value. If a complex object of the same value is found in the cache, you return it to the caller directly. Otherwise, you proceed with the original constructor invocation to create a new complex object. Before you return it to the caller, you cache it in the map for subsequent usages.

The call pointcut is not supported by Spring AOP , so if you attempt to let Spring scan the pointcut annotation, you’ll get the error “unsupported pointcut primitive call.

Because this type of pointcut is not supported by Spring AOP, you have to use the AspectJ framework to apply this aspect. The configuration of the AspectJ framework is done through a file named aop.xml in the META-INF directory of the classpath root.

<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN"
    "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">


<aspectj>
    <weaver>
        <include within="com.apress.springrecipes.calculator.*" />
    </weaver>


    <aspects>
        <aspect
            name="com.apress.springrecipes.calculator.ComplexCachingAspect" />
    </aspects>
</aspectj>

In this AspectJ configuration file, you have to specify the aspects and which classes you want your aspects to weave in. Here, you specify weaving ComplexCachingAspect into all the classes in the com.apress.springrecipes.calculator package.

Finally, to make this load-time weaving, you need to run the application in one of two ways, as described in the next sections.

Implement Load-Time Weaving with the AspectJ Weaver

AspectJ provides a load-time weaving agent to enable load-time weaving. You need only to add a VM argument to the command that runs your application. Then your classes will get woven when they are loaded into the JVM.

java -javaagent:lib/aspectjweaver-1.9.0.jar -jar Recipe_2_19_ii-4.0.0.jar

If you run your application with the preceding argument, you will get the following output and cache status. The AspectJ agent advises all calls to the Complex(int,int) constructor.

Cache MISS for (1,2)
Cache MISS for (2,3)
Cache MISS for (3,5)
(1 + 2i) + (2 + 3i) = (3 + 5i)
Cache MISS for (5,8)
Cache HIT for (2,3)
Cache HIT for (3,5)
(5 + 8i) - (2 + 3i) = (3 + 5i)

Implement Load-Time Weaving with Spring Load-Time Weaver

Spring has several load-time weavers for different runtime environments. To turn on a suitable load-time weaver for your Spring application, you need only to add @EnableLoadTimeWeaving to your configuration class.

Spring will be able to detect the most suitable load-time weaver for your runtime environment. Some Java EE application servers have class loaders that support the Spring load-time weaver mechanism, so there’s no need to specify a Java agent in their startup commands.

However, for a simple Java application , you still require a weaving agent provided by Spring to enable load-time weaving. You have to specify the Spring agent in the VM argument of the startup command.

java -javaagent:lib/spring-instrument-5.0.0.jar -jar Recipe_2_19_iii-4.0.0.jar

However, if you run your application, you will get the following output and cache status:

Cache MISS for (3,5)
(1 + 2i) + (2 + 3i) = (3 + 5i)
Cache HIT for (3,5)
(5 + 8i) - (2 + 3i) = (3 + 5i)

This is because the Spring agent advises only the Complex(int,int) constructor calls made by beans declared in the Spring IoC container. As the complex operands are created in the Main class, the Spring agent will not advise their constructor calls.

2-21. Configure AspectJ Aspects in Spring

Problem

Aspects used in the AspectJ framework are instantiated by the AspectJ framework itself. Therefore, you have to retrieve the aspect instances from the AspectJ framework to configure them.

Solution

Each AspectJ aspect provides a factory class called Aspects that has a static factory method called aspectOf(), which allows you to access the current aspect instance. In the Spring IoC container, you can declare a bean created by this factory method by calling Aspects.aspectOf(ComplexCachingAspect.class).

How It Works

For instance, you can allow the cache map of ComplexCachingAspect to be preconfigured via a setter method.

package com.apress.springrecipes.calculator;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;


import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


@Aspect
public class ComplexCachingAspect {


    private Map<String, Complex> cache = new ConcurrentHashMap<>();

    public void setCache(Map<String, Complex> cache) {
        this.cache.clear();
        this.cache.putAll(cache);
    }


    @Around("call(public Complex.new(int, int)) && args(a,b)")
    public Object cacheAround(ProceedingJoinPoint joinPoint, int a, int b) throws Throwable {
        String key = a + "," + b;
        Complex complex = cache.get(key);
        if (complex == null) {
            System.out.println("Cache MISS for (" + key + ")");
            complex = (Complex) joinPoint.proceed();
            cache.put(key, complex);
        } else {
            System.out.println("Cache HIT for (" + key + ")");
        }
        return complex;
    }


}

To configure the aspect, create an @Bean annotated method that calls the aforementioned factory method Aspects.aspectOf; this will give you the instance of the aspect. This instance can in turn be configured.

package com.apress.springrecipes.calculator;

import org.aspectj.lang.Aspects;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;


import java.util.HashMap;
import java.util.Map;


@Configuration
@ComponentScan
public class CalculatorConfiguration {


    @Bean
    public ComplexCachingAspect complexCachingAspect() {


        Map<String, Complex> cache = new HashMap<>();
        cache.put("2,3", new Complex(2,3));
        cache.put("3,5", new Complex(3,5));


        ComplexCachingAspect complexCachingAspect =            Aspects.aspectOf(ComplexCachingAspect.class);
        complexCachingAspect.setCache(cache);
        return complexCachingAspect;
    }
}

To run the application , you use AspectJ’s weaver.

java -javaagent:lib/aspectjweaver-1.9.0.jar -jar Recipe_2_20-4.0.0.jar

2-22. Inject POJOs into Domain Objects with AOP

Problem

Beans declared in the Spring IoC container can wire themselves to one another through Spring’s dependency injection capability. However, objects created outside the Spring IoC container cannot wire themselves to Spring beans via configuration. You have to perform the wiring manually with programming code.

Solution

Objects created outside the Spring IoC container are usually domain objects. They are often created using the new operator or from the results of database queries. To inject a Spring bean into domain objects created outside Spring, you need the help of AOP. Actually, the injection of Spring beans is also a kind of crosscutting concern. As the domain objects are not created by Spring, you cannot use Spring AOP for injection. Spring supplies an AspectJ aspect specialized for this purpose. You can enable this aspect in the AspectJ framework.

How It Works

Suppose you have a global formatter to format complex numbers. This formatter accepts a pattern for formatting and uses the standard @Component and @Value annotations to instantiate a POJO .

package com.apress.springrecipes.calculator;

@Component
public class ComplexFormatter {


    @Value("(a + bi)")
    private String pattern;


    public void setPattern(String pattern) {
        this.pattern = pattern;
    }


    public String format(Complex complex) {
        return pattern.replaceAll("a", Integer.toString(complex.getReal()))
                .replaceAll("b", Integer.toString(complex.getImaginary()));
    }
}

In the Complex class, you want to use this formatter in the toString() method to convert a complex number into a string. It exposes a setter method for ComplexFormatter.

package com.apress.springrecipes.calculator;

public class Complex {

    private int real;
    private int imaginary;
    ...
    private ComplexFormatter formatter;


    public void setFormatter(ComplexFormatter formatter) {
        this.formatter = formatter;
    }


    public String toString() {
        return formatter.format(this);
    }
}

However, because Complex objects are not instantiated by the Spring IoC container, they cannot be configured for dependency injection in the regular manner. Spring includes AnnotationBeanConfigurerAspect in its aspect library to configure the dependencies of any objects, even if they were not created by the Spring IoC container.

First, you have to annotate your object type with the @Configurable annotation to declare that this type of object is configurable.

package com.apress.springrecipes.calculator;

import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.Scope;


@Configurable
@Component
@Scope("prototype")
public class Complex {
    ...
    @Autowired
    public void setFormatter(ComplexFormatter formatter) {
        this.formatter = formatter;
    }


}

In addition to the @Configurable annotation, you decorate the POJO with the standard @Component, @Scope, and @Autowired annotations so the bean gets its standard Spring behaviors. However, the @Configurable annotation is the most important configuration piece, and for this Spring defines a convenient annotation, @EnableSpringConfigured, for you to enable the mentioned aspect.

@Configuration
@EnableSpringConfigured
@ComponentScan
public class CalculatorConfiguration {}

When a class with the @Configurable annotation is instantiated, the aspect will look for a prototype-scoped bean definition whose type is the same as this class. Then, it will configure the new instances according to this bean definition. If there are properties declared in the bean definition, the new instances will also have the same properties set by the aspect.

Finally, to run the application, you weave the aspect into your classes at load time with the AspectJ agent.

java -javaagent:lib/aspectjweaver-1.9.0.jar -jar Recipe_2_21-4.0.0.jar

2-23. Applying Concurrency with Spring and TaskExecutors

Problem

You want to build a threaded, concurrent program with Spring but don’t know what approach to use since there’s no standard approach.

Solution

Use Spring’s TaskExecutor abstraction. This abstraction provides numerous implementations for many environments, including basic Java SE Executor implementations, CommonJ WorkManager implementations, and custom implementations.

In Spring all the implementations are unified and can be cast to Java SE’s Executor interface, too.

How It Works

Threading is a difficult issue that can be particularly tedious to implement using standard threading in the Java SE environment. Concurrency is another important aspect of server-side components but has little to no standardization in the enterprise Java space. In fact, some parts of the Java Enterprise Edition specifications forbid the explicit creation and manipulation of threads.

In the Java SE landscape, many options have been introduced over the years to deal with threading and concurrency. First, there was the standard java.lang.Thread support present since 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 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 provides support to raise events to 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 in the java.util.concurrent package. What follows are several examples using Java SE classes.

The ExecutorService class provides a submit() method, which returns a Future<T> object. An instance of Future<T> can be used to track the progress of a thread that’s usually executing asynchronously. You can call Future.isDone() or Future.isCancelled() to determine whether the job is finished or cancelled, respectively. When you use ExecutorService and submit() inside a Runnable instance whose run method has no return type, calling get() on the returned Future returns null, or the value 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 this background information, you can explore some of the characteristics of the various implementations. For example, the following is a class designed to mark the passage of time using Runnable:

package com.apress.springrecipes.spring3.executors;

import java.util.Date;

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

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();


        ExecutorService cachedThreadPoolExecutorService =
            Executors.newCachedThreadPool();
        if (cachedThreadPoolExecutorService.submit(task).get() == null)
            System.out.printf("The cachedThreadPoolExecutorService "
                + "has succeeded at %s ", new Date());


        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(100);
        if (fixedThreadPool.submit(task).get() == null)
            System.out.printf("The fixedThreadPool has " +
                "succeeded at %s ",
                new Date());
        ExecutorService singleThreadExecutorService =
            Executors.newSingleThreadExecutor();
        if (singleThreadExecutorService.submit(task).get() == null)
            System.out.printf("The singleThreadExecutorService "
                + "has succeeded at %s ", new Date());


        ExecutorService es = Executors.newCachedThreadPool();
        if (es.submit(task, Boolean.TRUE).get().equals(Boolean.TRUE))
            System.out.println("Job has finished!");


        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());


        scheduledThreadExecutorService.scheduleAtFixedRate(task, 0, 5,
            TimeUnit.SECONDS);


    }
}

If you use the submit() method version of the ExecutorService subinterface that accepts Callable<T>, then submit() returns whatever was returned from the main call() method in Callable. The following is the interface for Callable:

package java.util.concurrent;

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

In the Java EE landscape, different approaches for solving these sorts of problems have been created, since Java EE by design restricts the handling of threads.

Quartz (a job scheduling framework) was among the first solutions to fill this thread feature gap with a solution that provided scheduling and concurrency. JCA 1.5 (or the J2EE Connector Architecture) is another specification that provides a primitive type of gateway for integration functionality and supports ad hoc concurrency. With JCA, components are notified about incoming messages and respond concurrently. JCA 1.5 provides a primitive, limited enterprise service bus—similar to integration features without nearly as much of the finesse of something like SpringSource’s Spring Integration framework.

The requirement for concurrency wasn’t lost on application server vendors, though. Many other initiatives came to the forefront. For example, in 2003, IBM and BEA jointly created the Timer and WorkManager APIs, which eventually became JSR-237 and was then merged with JSR-236 to focus on how to implement concurrency in a managed environment. The Service Data Object (SDO) specification, JSR-235, had a similar solution. In addition, open source implementations of the CommonJ API have sprung up in recent years to achieve the same solution.

The issue is that there’s no portable, standard, simple way of controlling threads and providing concurrency for components in a managed environment, similar to the case of Java SE solutions.

Spring provides a unified solution via the org.springframeworks.core.task.TaskExecutor interface. The TaskExecutor abstraction extends java.util.concurrent.Executor, which is part of Java 1.5.

In fact, the TaskExecutor interface is used quite a bit internally in the Spring Framework. For example, for Spring Quartz integration (which supports threading) and the message-driven POJO container support, there’s wide use of TaskExecutor.

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 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’s support for adapting an existing Java SE Executor or ExecutorService as a TaskExecutor, this isn’t so important in Spring because the base class for TaskExecutor is an Executor anyway. In this way, the TaskExecutor in Spring bridges the gap between various solutions on Java EE and Java SE.

Next, let’s see a simple example of the TaskExecutor, using the same Runnable defined previously. The client for the code is a simple Spring POJO, into which you’ve injected various instances of TaskExecutor with the sole aim of submitting Runnable.

package com.apress.springrecipes.executors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
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.stereotype.Component;


import javax.annotation.PostConstruct;

@Component
public class SpringExecutorsDemo {


    @Autowired
    private SimpleAsyncTaskExecutor asyncTaskExecutor;
    @Autowired
    private SyncTaskExecutor syncTaskExecutor;
    @Autowired
    private TaskExecutorAdapter taskExecutorAdapter;
    @Autowired
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    @Autowired
    private DemonstrationRunnable task;


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


        for (int i = 0; i < 500; i++)
            threadPoolTaskExecutor.submit(task);
    }


    public static void main(String[] args) {

        new AnnotationConfigApplicationContext(ExecutorsConfiguration.class)
            .registerShutdownHook();
    }
}

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 do you delegate to a factory bean to automatically trigger the execution , shown here:

package com.apress.springrecipes.executors;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.support.TaskExecutorAdapter;
import org.springframework.scheduling.concurrent.ScheduledExecutorFactoryBean;
import org.springframework.scheduling.concurrent.ScheduledExecutorTask;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;


import java.util.concurrent.Executors;

@Configuration
@ComponentScan
public class ExecutorsConfiguration {


    @Bean
    public TaskExecutorAdapter taskExecutorAdapter() {
        return new TaskExecutorAdapter(Executors.newCachedThreadPool());
    }


    @Bean
    public SimpleAsyncTaskExecutor simpleAsyncTaskExecutor() {
        return new SimpleAsyncTaskExecutor();
    }


    @Bean
    public SyncTaskExecutor syncTaskExecutor() {
        return new SyncTaskExecutor();
    }

    @Bean
    public ScheduledExecutorFactoryBean scheduledExecutorFactoryBean(ScheduledExecutorTask scheduledExecutorTask) {
        ScheduledExecutorFactoryBean scheduledExecutorFactoryBean = new ScheduledExecutorFactoryBean();
        scheduledExecutorFactoryBean.setScheduledExecutorTasks(scheduledExecutorTask);
        return scheduledExecutorFactoryBean;
    }


    @Bean
    public ScheduledExecutorTask scheduledExecutorTask(Runnable runnable) {
        ScheduledExecutorTask scheduledExecutorTask = new ScheduledExecutorTask();
        scheduledExecutorTask.setPeriod(1000);
        scheduledExecutorTask.setRunnable(runnable);
        return scheduledExecutorTask;
    }


    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(50);
        taskExecutor.setMaxPoolSize(100);
        taskExecutor.setAllowCoreThreadTimeOut(true);
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        return taskExecutor;
    }
}

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 you can deal with it in terms of the Spring TaskExecutor interface. 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 submitted job. 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 using join() to connect it immediately. It’s effectively the same as manually invoking the run() method in the calling thread, skipping threading altogether.

ScheduledExecutorFactoryBean automatically triggers jobs defined as ScheduledExecutorTask beans. You can specify a list of ScheduledExecutorTask instances to trigger multiple jobs simultaneously. A ScheduledExecutorTask instance can accept a period to space out the execution of tasks.

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

If you want to build applications using the CommonJ WorkManager/TimerManager support available in application servers like IBM WebSphere, you can use org.springframework.scheduling.commonj.WorkManagerTaskExecutor. This class delegates to a reference to the CommonJ Work Manager available inside of WebSphere. Usually, you’ll provide it with a JNDI reference to the appropriate resource.

In JEE 7, the javax.enterprise.concurrent package and specifically the ManagedExecutorService, was added. An instance of this ManagedExecutorService must be provided by JEE 7–compliant servers. If you want to use this mechanism with Spring TaskExecutor support, you can configure a DefaultManagedTaskExecutor, which will try to detect the default ManagedExecutorService (as mentioned by the specification), or you can explictly configure it.

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

2-24. Communicate Application Events Between POJOs

Problem

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

When using an IoC container, POJOs can communicate by interface rather than by implementation. This communication model helps reduce coupling. However, it is efficient only 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 POJO just publishes an event without knowing who the receiver is since there can actually be more than one receiver. Also, the receiver doesn’t necessarily 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.

Traditionally to listen for events, a bean has to implement the ApplicationListener interface and specify the type of events they want to be notified about by specifying the type parameter, i.e., ApplicationListener<CheckoutEvent>. Listeners of this kind can only listen to events that extend from ApplicationEvent as that is the type signature of the ApplicationListener interface.

To publish an event, a bean needs access to the ApplicationEventPublisher, and for sending, an event needs to call the publishEvent method. To get access to the ApplicationEventPublisher, a class can either implement ApplicationEventPublisherAware or use @Autowired on a field of type ApplicationEventPublisher.

How It Works

First you will write a custom ApplicationEvent then publish it and finally write a component to receive those events and act upon it.

Define Events Using ApplicationEvent

The first step of enabling event-based communication is to define the event. Suppose you want a cashier bean to publish a CheckoutEvent after the shopping cart is checked out. This event includes a checkout time property.

package com.apress.springrecipes.shop;

import org.springframework.context.ApplicationEvent;

import java.util.Date;

public class CheckoutEvent extends ApplicationEvent {

    private final ShoppingCart cart;
    private final Date time;


    public CheckoutEvent(ShoppingCart cart, Date time) {
        super(cart);
        this.cart=cart;
        this.time = time;
    }


    public ShoppingCart getCart() {
        return cart;
    }


    public Date getTime() {
        return this.time;
    }
}

Publish 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 becomes accessible by implementing the ApplicationEventPublisherAware interface.

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


public class Cashier implements ApplicationEventPublisherAware {
    ...
    private ApplicationEventPublisher applicationEventPublisher;


    public void setApplicationEventPublisher(
        ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }


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

Or you could simply autowire it on a field property.

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


public class Cashier {
    ...
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;


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

Listen to Events

Any bean defined in the application context that implements the ApplicationListener interface is notified of all type of events that match the type parameter (this way you can listen for a certain group of events such as ApplicationContextEvent).

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


@Component
public class CheckoutListener implements ApplicationListener<CheckoutEvent> {


    public void onApplicationEvent(CheckoutEvent event) {
        // Do anything you like with the checkout amount and time
        System.out.println("Checkout event [" + event.getTime() + "]");
     }
}

Newer versions of Spring also allow you to create event listeners using the @EventListener annotation instead of implementing the ApplicationListener interface.

package com.apress.springrecipes.shop;

...

@Component
public class CheckoutListener {


    @EventListener
    public void onApplicationEvent(CheckoutEvent event) {
        // Do anything you like with the checkout amount and time
        System.out.println("Checkout event [" + event.getTime() + "]");
     }
}

Next, you have to register the listener in the application context to listen for all events. The registration is as simple as declaring a bean instance of this listener or letting component scanning detect it. The application context recognizes beans that implement the ApplicationListener interface and beans that have methods annotated with @EventListener and notify them of each event they are interested in.

Using @EventListener has another nice feature, which is that the events don’t have to extend ApplicationEvent anymore. This way, your events don’t rely on Spring Framework classes but are plain POJOs again.

package com.apress.springrecipes.shop;

import java.util.Date;

public class CheckoutEvent {

    private final ShoppingCart cart;
    private final Date time;


    public CheckoutEvent(ShoppingCart cart, Date time) {
        this.cart=cart;
        this.time = time;
    }


    public ShoppingCart getCart() {
        return cart;
    }


    public Date getTime() {
        return this.time;
    }
}
Note

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

Summary

In this chapter, you learned about Spring’s core tasks. You learned how Spring supports the @Configuration and @Bean annotations to instantiate POJO via a Java config class. You also learned how to use the @Component annotation to administer POJOs with Spring. In addition, you learned about the @Repository, @Service, and @Controller annotations, which provide more specific behavior than the @Component annotation.

You also learned how to reference POJOs from other POJOs, as well as how to use the @Autowired annotation, which can automatically associate POJOs by either type or name. In addition, you explored how the standard @Resource and @Inject annotations work to reference POJOs via autowiring, instead of using the Spring-specific @Autowired annotation.

You then learned how to set a Spring POJOs scope with the @Scope annotation. You also learned how Spring can read external resources and use this data in the context of POJO configuration and creation using the @PropertySource and @Value annotations. In addition, you learned how Spring supports different languages in POJOs through the use of i18n resource bundles.

Next, you learned how to customize the initialization and destruction of POJOs with the initmethod and destroyMethod attributes of an @Bean annotation, as well as the @PostConstruct and @PreDestroy annotations. In addition, you learned how to do lazy initialization with the @PreDestroy annotation and define initialization dependencies with the @DependsOn annotation.

You then learned about Spring post-processors to validate and modify POJO values, including how to use the @Required annotation. Next, you explored how to work with Spring environments and profiles to load different sets of POJOs, including how to use the @Profile annotation.

Next, you explored aspect-oriented programming in the context of Spring and learned how to create aspects, pointcuts, and advices. This included the use of the @Aspect annotation, as well as the @Before, @After, @AfterReturning, @AfterThrowing, and @Around annotations.

Next, you learned how to access AOP join point information and apply it to different program execution points. And then you learned how specify aspect precedence with the @Order annotations, followed by how to reuse aspect pointcut definition.

In this chapter, you also learned how to write AspectJ pointcut expressions, as well as how to apply the concept of AOP introductions so a POJO can inherit behaviors from multiple implementation classes at the same time. You also learned how to introduce states to POJOs with AOP, as well as how to apply the technique of load-time weaving.

Finally, you learned how to configure AspectJ aspects in Spring, how to inject POJOs into domain objects, how to deal with concurrency with Spring and TaskExecutors, and, last but not least, how to create, publish, and listen to events in Spring.

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

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