10. Spring AOP APIs

10.1 Introduction

The previous chapter described the Spring’s support for AOP using @AspectJ and schema-based aspect definitions. In this chapter we discuss the lower-level Spring AOP APIs and the AOP support used in Spring 1.2 applications. For new applications, we recommend the use of the Spring 2.0 and later AOP support described in the previous chapter, but when working with existing applications, or when reading books and articles, you may come across Spring 1.2 style examples. Spring 4.0 is backwards compatible with Spring 1.2 and everything described in this chapter is fully supported in Spring 4.0.

10.2 Pointcut API in Spring

Let’s look at how Spring handles the crucial pointcut concept.

10.2.1 Concepts

Spring’s pointcut model enables pointcut reuse independent of advice types. It’s possible to target different advice using the same pointcut.

The org.springframework.aop.Pointcut interface is the central interface, used to target advices to particular classes and methods. The complete interface is shown below:

public interface Pointcut {

    ClassFilter getClassFilter();

    MethodMatcher getMethodMatcher();

}

Splitting the Pointcut interface into two parts allows reuse of class and method matching parts, and fine-grained composition operations (such as performing a "union" with another method matcher).

The ClassFilter interface is used to restrict the pointcut to a given set of target classes. If the matches() method always returns true, all target classes will be matched:

public interface ClassFilter {

    boolean matches(Class clazz);
}

The MethodMatcher interface is normally more important. The complete interface is shown below:

public interface MethodMatcher {

    boolean matches(Method m, Class targetClass);

    boolean isRuntime();

    boolean matches(Method m, Class targetClass, Object[] args);
}

The matches(Method, Class) method is used to test whether this pointcut will ever match a given method on a target class. This evaluation can be performed when an AOP proxy is created, to avoid the need for a test on every method invocation. If the 2-argument matches method returns true for a given method, and the isRuntime() method for the MethodMatcher returns true, the 3-argument matches method will be invoked on every method invocation. This enables a pointcut to look at the arguments passed to the method invocation immediately before the target advice is to execute.

Most MethodMatchers are static, meaning that their isRuntime() method returns false. In this case, the 3-argument matches method will never be invoked.

[Tip]Tip

If possible, try to make pointcuts static, allowing the AOP framework to cache the results of pointcut evaluation when an AOP proxy is created.

10.2.2 Operations on pointcuts

Spring supports operations on pointcuts: notably, union and intersection.

  • Union means the methods that either pointcut matches.
  • Intersection means the methods that both pointcuts match.
  • Union is usually more useful.
  • Pointcuts can be composed using the static methods in the org.springframework.aop.support.Pointcuts class, or using the ComposablePointcut class in the same package. However, using AspectJ pointcut expressions is usually a simpler approach.

10.2.3 AspectJ expression pointcuts

Since 2.0, the most important type of pointcut used by Spring is org.springframework.aop.aspectj.AspectJExpressionPointcut. This is a pointcut that uses an AspectJ supplied library to parse an AspectJ pointcut expression string.

See the previous chapter for a discussion of supported AspectJ pointcut primitives.

10.2.4 Convenience pointcut implementations

Spring provides several convenient pointcut implementations. Some can be used out of the box; others are intended to be subclassed in application-specific pointcuts.

Static pointcuts

Static pointcuts are based on method and target class, and cannot take into account the method’s arguments. Static pointcuts are sufficient - and best - for most usages. It’s possible for Spring to evaluate a static pointcut only once, when a method is first invoked: after that, there is no need to evaluate the pointcut again with each method invocation.

Let’s consider some static pointcut implementations included with Spring.

Regular expression pointcuts

One obvious way to specify static pointcuts is regular expressions. Several AOP frameworks besides Spring make this possible. org.springframework.aop.support.JdkRegexpMethodPointcut is a generic regular expression pointcut, using the regular expression support in JDK 1.4+.

Using the JdkRegexpMethodPointcut class, you can provide a list of pattern Strings. If any of these is a match, the pointcut will evaluate to true. (So the result is effectively the union of these pointcuts.)

The usage is shown below:

<bean id="settersAndAbsquatulatePointcut"
        class="org.springframework.aop.support.JdkRegexpMethodPointcut">
    <property name="patterns">
        <list>
            <value>.*set.*</value>
            <value>.*absquatulate</value>
        </list>
    </property>
</bean>

Spring provides a convenience class, RegexpMethodPointcutAdvisor, that allows us to also reference an Advice (remember that an Advice can be an interceptor, before advice, throws advice etc.). Behind the scenes, Spring will use a JdkRegexpMethodPointcut. Using RegexpMethodPointcutAdvisor simplifies wiring, as the one bean encapsulates both pointcut and advice, as shown below:

<bean id="settersAndAbsquatulateAdvisor"
        class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <property name="advice">
        <ref bean="beanNameOfAopAllianceInterceptor"/>
    </property>
    <property name="patterns">
        <list>
            <value>.*set.*</value>
            <value>.*absquatulate</value>
        </list>
    </property>
</bean>

RegexpMethodPointcutAdvisor can be used with any Advice type.

Attribute-driven pointcuts

An important type of static pointcut is a metadata-driven pointcut. This uses the values of metadata attributes: typically, source-level metadata.

Dynamic pointcuts

Dynamic pointcuts are costlier to evaluate than static pointcuts. They take into account method arguments, as well as static information. This means that they must be evaluated with every method invocation; the result cannot be cached, as arguments will vary.

The main example is the control flow pointcut.

Control flow pointcuts

Spring control flow pointcuts are conceptually similar to AspectJ cflow pointcuts, although less powerful. (There is currently no way to specify that a pointcut executes below a join point matched by another pointcut.) A control flow pointcut matches the current call stack. For example, it might fire if the join point was invoked by a method in the com.mycompany.web package, or by the SomeCaller class. Control flow pointcuts are specified using the org.springframework.aop.support.ControlFlowPointcut class.

[Note]Note

Control flow pointcuts are significantly more expensive to evaluate at runtime than even other dynamic pointcuts. In Java 1.4, the cost is about 5 times that of other dynamic pointcuts.

10.2.5 Pointcut superclasses

Spring provides useful pointcut superclasses to help you to implement your own pointcuts.

Because static pointcuts are most useful, you’ll probably subclass StaticMethodMatcherPointcut, as shown below. This requires implementing just one abstract method (although it’s possible to override other methods to customize behavior):

class TestStaticPointcut extends StaticMethodMatcherPointcut {

    public boolean matches(Method m, Class targetClass) {
        // return true if custom criteria match
    }
}

There are also superclasses for dynamic pointcuts.

You can use custom pointcuts with any advice type in Spring 1.0 RC2 and above.

10.2.6 Custom pointcuts

Because pointcuts in Spring AOP are Java classes, rather than language features (as in AspectJ) it’s possible to declare custom pointcuts, whether static or dynamic. Custom pointcuts in Spring can be arbitrarily complex. However, using the AspectJ pointcut expression language is recommended if possible.

[Note]Note

Later versions of Spring may offer support for "semantic pointcuts" as offered by JAC: for example, "all methods that change instance variables in the target object."

10.3 Advice API in Spring

Let’s now look at how Spring AOP handles advice.

10.3.1 Advice lifecycles

Each advice is a Spring bean. An advice instance can be shared across all advised objects, or unique to each advised object. This corresponds to per-class or per-instance advice.

Per-class advice is used most often. It is appropriate for generic advice such as transaction advisors. These do not depend on the state of the proxied object or add new state; they merely act on the method and arguments.

Per-instance advice is appropriate for introductions, to support mixins. In this case, the advice adds state to the proxied object.

It’s possible to use a mix of shared and per-instance advice in the same AOP proxy.

10.3.2 Advice types in Spring

Spring provides several advice types out of the box, and is extensible to support arbitrary advice types. Let us look at the basic concepts and standard advice types.

Interception around advice

The most fundamental advice type in Spring is interception around advice.

Spring is compliant with the AOP Alliance interface for around advice using method interception. MethodInterceptors implementing around advice should implement the following interface:

public interface MethodInterceptor extends Interceptor {

    Object invoke(MethodInvocation invocation) throws Throwable;
}

The MethodInvocation argument to the invoke() method exposes the method being invoked; the target join point; the AOP proxy; and the arguments to the method. The invoke() method should return the invocation’s result: the return value of the join point.

A simple MethodInterceptor implementation looks as follows:

public class DebugInterceptor implements MethodInterceptor {

    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("Before: invocation=[" + invocation + "]");
        Object rval = invocation.proceed();
        System.out.println("Invocation returned");
        return rval;
    }
}

Note the call to the MethodInvocation’s proceed() method. This proceeds down the interceptor chain towards the join point. Most interceptors will invoke this method, and return its return value. However, a MethodInterceptor, like any around advice, can return a different value or throw an exception rather than invoke the proceed method. However, you don’t want to do this without good reason!

[Note]Note

MethodInterceptors offer interoperability with other AOP Alliance-compliant AOP implementations. The other advice types discussed in the remainder of this section implement common AOP concepts, but in a Spring-specific way. While there is an advantage in using the most specific advice type, stick with MethodInterceptor around advice if you are likely to want to run the aspect in another AOP framework. Note that pointcuts are not currently interoperable between frameworks, and the AOP Alliance does not currently define pointcut interfaces.

Before advice

A simpler advice type is a before advice. This does not need a MethodInvocation object, since it will only be called before entering the method.

The main advantage of a before advice is that there is no need to invoke the proceed() method, and therefore no possibility of inadvertently failing to proceed down the interceptor chain.

The MethodBeforeAdvice interface is shown below. (Spring’s API design would allow for field before advice, although the usual objects apply to field interception and it’s unlikely that Spring will ever implement it).

public interface MethodBeforeAdvice extends BeforeAdvice {

    void before(Method m, Object[] args, Object target) throws Throwable;
}

Note the return type is void. Before advice can insert custom behavior before the join point executes, but cannot change the return value. If a before advice throws an exception, this will abort further execution of the interceptor chain. The exception will propagate back up the interceptor chain. If it is unchecked, or on the signature of the invoked method, it will be passed directly to the client; otherwise it will be wrapped in an unchecked exception by the AOP proxy.

An example of a before advice in Spring, which counts all method invocations:

public class CountingBeforeAdvice implements MethodBeforeAdvice {

    private int count;

    public void before(Method m, Object[] args, Object target) throws Throwable {
        ++count;
    }

    public int getCount() {
        return count;
    }
}
[Tip]Tip

Before advice can be used with any pointcut.

Throws advice

Throws advice is invoked after the return of the join point if the join point threw an exception. Spring offers typed throws advice. Note that this means that the org.springframework.aop.ThrowsAdvice interface does not contain any methods: It is a tag interface identifying that the given object implements one or more typed throws advice methods. These should be in the form of:

afterThrowing([Method, args, target], subclassOfThrowable)

Only the last argument is required. The method signatures may have either one or four arguments, depending on whether the advice method is interested in the method and arguments. The following classes are examples of throws advice.

The advice below is invoked if a RemoteException is thrown (including subclasses):

public class RemoteThrowsAdvice implements ThrowsAdvice {

    public void afterThrowing(RemoteException ex) throws Throwable {
        // Do something with remote exception
    }
}

The following advice is invoked if a ServletException is thrown. Unlike the above advice, it declares 4 arguments, so that it has access to the invoked method, method arguments and target object:

public class ServletThrowsAdviceWithArguments implements ThrowsAdvice {

    public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) {
        // Do something with all arguments
    }
}

The final example illustrates how these two methods could be used in a single class, which handles both RemoteException and ServletException. Any number of throws advice methods can be combined in a single class.

public static class CombinedThrowsAdvice implements ThrowsAdvice {

    public void afterThrowing(RemoteException ex) throws Throwable {
        // Do something with remote exception
    }

    public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) {
        // Do something with all arguments
    }
}
[Note]Note

If a throws-advice method throws an exception itself, it will override the original exception (i.e. change the exception thrown to the user). The overriding exception will typically be a RuntimeException; this is compatible with any method signature. However, if a throws-advice method throws a checked exception, it will have to match the declared exceptions of the target method and is hence to some degree coupled to specific target method signatures. Do not throw an undeclared checked exception that is incompatible with the target method’s signature!

[Tip]Tip

Throws advice can be used with any pointcut.

After Returning advice

An after returning advice in Spring must implement the org.springframework.aop.AfterReturningAdvice interface, shown below:

public interface AfterReturningAdvice extends Advice {

    void afterReturning(Object returnValue, Method m, Object[] args, Object target)
            throws Throwable;
}

An after returning advice has access to the return value (which it cannot modify), invoked method, methods arguments and target.

The following after returning advice counts all successful method invocations that have not thrown exceptions:

public class CountingAfterReturningAdvice implements AfterReturningAdvice {

    private int count;

    public void afterReturning(Object returnValue, Method m, Object[] args, Object target)
            throws Throwable {
        ++count;
    }

    public int getCount() {
        return count;
    }
}

This advice doesn’t change the execution path. If it throws an exception, this will be thrown up the interceptor chain instead of the return value.

[Tip]Tip

After returning advice can be used with any pointcut.

Introduction advice

Spring treats introduction advice as a special kind of interception advice.

Introduction requires an IntroductionAdvisor, and an IntroductionInterceptor, implementing the following interface:

public interface IntroductionInterceptor extends MethodInterceptor {

    boolean implementsInterface(Class intf);
}

The invoke() method inherited from the AOP Alliance MethodInterceptor interface must implement the introduction: that is, if the invoked method is on an introduced interface, the introduction interceptor is responsible for handling the method call - it cannot invoke proceed().

Introduction advice cannot be used with any pointcut, as it applies only at class, rather than method, level. You can only use introduction advice with the IntroductionAdvisor, which has the following methods:

public interface IntroductionAdvisor extends Advisor, IntroductionInfo {

    ClassFilter getClassFilter();

    void validateInterfaces() throws IllegalArgumentException;
}

public interface IntroductionInfo {

    Class[] getInterfaces();
}

There is no MethodMatcher, and hence no Pointcut, associated with introduction advice. Only class filtering is logical.

The getInterfaces() method returns the interfaces introduced by this advisor.

The validateInterfaces() method is used internally to see whether or not the introduced interfaces can be implemented by the configured IntroductionInterceptor.

Let’s look at a simple example from the Spring test suite. Let’s suppose we want to introduce the following interface to one or more objects:

public interface Lockable {
    void lock();
    void unlock();
    boolean locked();
}

This illustrates a mixin. We want to be able to cast advised objects to Lockable, whatever their type, and call lock and unlock methods. If we call the lock() method, we want all setter methods to throw a LockedException. Thus we can add an aspect that provides the ability to make objects immutable, without them having any knowledge of it: a good example of AOP.

Firstly, we’ll need an IntroductionInterceptor that does the heavy lifting. In this case, we extend the org.springframework.aop.support.DelegatingIntroductionInterceptor convenience class. We could implement IntroductionInterceptor directly, but using DelegatingIntroductionInterceptor is best for most cases.

The DelegatingIntroductionInterceptor is designed to delegate an introduction to an actual implementation of the introduced interface(s), concealing the use of interception to do so. The delegate can be set to any object using a constructor argument; the default delegate (when the no-arg constructor is used) is this. Thus in the example below, the delegate is the LockMixin subclass of DelegatingIntroductionInterceptor. Given a delegate (by default itself), a DelegatingIntroductionInterceptor instance looks for all interfaces implemented by the delegate (other than IntroductionInterceptor), and will support introductions against any of them. It’s possible for subclasses such as LockMixin to call the suppressInterface(Class intf) method to suppress interfaces that should not be exposed. However, no matter how many interfaces an IntroductionInterceptor is prepared to support, the IntroductionAdvisor used will control which interfaces are actually exposed. An introduced interface will conceal any implementation of the same interface by the target.

Thus LockMixin extends DelegatingIntroductionInterceptor and implements Lockable itself. The superclass automatically picks up that Lockable can be supported for introduction, so we don’t need to specify that. We could introduce any number of interfaces in this way.

Note the use of the locked instance variable. This effectively adds additional state to that held in the target object.

public class LockMixin extends DelegatingIntroductionInterceptor implements Lockable {

    private boolean locked;

    public void lock() {
        this.locked = true;
    }

    public void unlock() {
        this.locked = false;
    }

    public boolean locked() {
        return this.locked;
    }

    public Object invoke(MethodInvocation invocation) throws Throwable {
        if (locked() && invocation.getMethod().getName().indexOf("set") == 0) {
            throw new LockedException();
        }
        return super.invoke(invocation);
    }

}

Often it isn’t necessary to override the invoke() method: the DelegatingIntroductionInterceptor implementation - which calls the delegate method if the method is introduced, otherwise proceeds towards the join point - is usually sufficient. In the present case, we need to add a check: no setter method can be invoked if in locked mode.

The introduction advisor required is simple. All it needs to do is hold a distinct LockMixin instance, and specify the introduced interfaces - in this case, just Lockable. A more complex example might take a reference to the introduction interceptor (which would be defined as a prototype): in this case, there’s no configuration relevant for a LockMixin, so we simply create it using new.

public class LockMixinAdvisor extends DefaultIntroductionAdvisor {

    public LockMixinAdvisor() {
        super(new LockMixin(), Lockable.class);
    }
}

We can apply this advisor very simply: it requires no configuration. (However, it is necessary: It’s impossible to use an IntroductionInterceptor without an IntroductionAdvisor.) As usual with introductions, the advisor must be per-instance, as it is stateful. We need a different instance of LockMixinAdvisor, and hence LockMixin, for each advised object. The advisor comprises part of the advised object’s state.

We can apply this advisor programmatically, using the Advised.addAdvisor() method, or (the recommended way) in XML configuration, like any other advisor. All proxy creation choices discussed below, including "auto proxy creators," correctly handle introductions and stateful mixins.

10.4 Advisor API in Spring

In Spring, an Advisor is an aspect that contains just a single advice object associated with a pointcut expression.

Apart from the special case of introductions, any advisor can be used with any advice. org.springframework.aop.support.DefaultPointcutAdvisor is the most commonly used advisor class. For example, it can be used with a MethodInterceptor, BeforeAdvice or ThrowsAdvice.

It is possible to mix advisor and advice types in Spring in the same AOP proxy. For example, you could use a interception around advice, throws advice and before advice in one proxy configuration: Spring will automatically create the necessary interceptor chain.

10.5 Using the ProxyFactoryBean to create AOP proxies

If you’re using the Spring IoC container (an ApplicationContext or BeanFactory) for your business objects - and you should be! - you will want to use one of Spring’s AOP FactoryBeans. (Remember that a factory bean introduces a layer of indirection, enabling it to create objects of a different type.)

[Note]Note

The Spring AOP support also uses factory beans under the covers.

The basic way to create an AOP proxy in Spring is to use the org.springframework.aop.framework.ProxyFactoryBean. This gives complete control over the pointcuts and advice that will apply, and their ordering. However, there are simpler options that are preferable if you don’t need such control.

10.5.1 Basics

The ProxyFactoryBean, like other Spring FactoryBean implementations, introduces a level of indirection. If you define a ProxyFactoryBean with name foo, what objects referencing foo see is not the ProxyFactoryBean instance itself, but an object created by the ProxyFactoryBean's implementation of the getObject() method. This method will create an AOP proxy wrapping a target object.

One of the most important benefits of using a ProxyFactoryBean or another IoC-aware class to create AOP proxies, is that it means that advices and pointcuts can also be managed by IoC. This is a powerful feature, enabling certain approaches that are hard to achieve with other AOP frameworks. For example, an advice may itself reference application objects (besides the target, which should be available in any AOP framework), benefiting from all the pluggability provided by Dependency Injection.

10.5.2 JavaBean properties

In common with most FactoryBean implementations provided with Spring, the ProxyFactoryBean class is itself a JavaBean. Its properties are used to:

Some key properties are inherited from org.springframework.aop.framework.ProxyConfig (the superclass for all AOP proxy factories in Spring). These key properties include:

  • proxyTargetClass: true if the target class is to be proxied, rather than the target class' interfaces. If this property value is set to true, then CGLIB proxies will be created (but see also Section 10.5.3, “JDK- and CGLIB-based proxies”).
  • optimize: controls whether or not aggressive optimizations are applied to proxies created via CGLIB. One should not blithely use this setting unless one fully understands how the relevant AOP proxy handles optimization. This is currently used only for CGLIB proxies; it has no effect with JDK dynamic proxies.
  • frozen: if a proxy configuration is frozen, then changes to the configuration are no longer allowed. This is useful both as a slight optimization and for those cases when you don’t want callers to be able to manipulate the proxy (via the Advised interface) after the proxy has been created. The default value of this property is false, so changes such as adding additional advice are allowed.
  • exposeProxy: determines whether or not the current proxy should be exposed in a ThreadLocal so that it can be accessed by the target. If a target needs to obtain the proxy and the exposeProxy property is set to true, the target can use the AopContext.currentProxy() method.

Other properties specific to ProxyFactoryBean include:

  • proxyInterfaces: array of String interface names. If this isn’t supplied, a CGLIB proxy for the target class will be used (but see also Section 10.5.3, “JDK- and CGLIB-based proxies”).
  • interceptorNames: String array of Advisor, interceptor or other advice names to apply. Ordering is significant, on a first come-first served basis. That is to say that the first interceptor in the list will be the first to be able to intercept the invocation.

The names are bean names in the current factory, including bean names from ancestor factories. You can’t mention bean references here since doing so would result in the ProxyFactoryBean ignoring the singleton setting of the advice.

You can append an interceptor name with an asterisk ( *). This will result in the application of all advisor beans with names starting with the part before the asterisk to be applied. An example of using this feature can be found in Section 10.5.6, “Using global advisors”.

  • singleton: whether or not the factory should return a single object, no matter how often the getObject() method is called. Several FactoryBean implementations offer such a method. The default value is true. If you want to use stateful advice - for example, for stateful mixins - use prototype advices along with a singleton value of false.

10.5.3 JDK- and CGLIB-based proxies

This section serves as the definitive documentation on how the ProxyFactoryBean chooses to create one of either a JDK- and CGLIB-based proxy for a particular target object (that is to be proxied).

[Note]Note

The behavior of the ProxyFactoryBean with regard to creating JDK- or CGLIB-based proxies changed between versions 1.2.x and 2.0 of Spring. The ProxyFactoryBean now exhibits similar semantics with regard to auto-detecting interfaces as those of the TransactionProxyFactoryBean class.

If the class of a target object that is to be proxied (hereafter simply referred to as the target class) doesn’t implement any interfaces, then a CGLIB-based proxy will be created. This is the easiest scenario, because JDK proxies are interface based, and no interfaces means JDK proxying isn’t even possible. One simply plugs in the target bean, and specifies the list of interceptors via the interceptorNames property. Note that a CGLIB-based proxy will be created even if the proxyTargetClass property of the ProxyFactoryBean has been set to false. (Obviously this makes no sense, and is best removed from the bean definition because it is at best redundant, and at worst confusing.)

If the target class implements one (or more) interfaces, then the type of proxy that is created depends on the configuration of the ProxyFactoryBean.

If the proxyTargetClass property of the ProxyFactoryBean has been set to true, then a CGLIB-based proxy will be created. This makes sense, and is in keeping with the principle of least surprise. Even if the proxyInterfaces property of the ProxyFactoryBean has been set to one or more fully qualified interface names, the fact that the proxyTargetClass property is set to true will cause CGLIB-based proxying to be in effect.

If the proxyInterfaces property of the ProxyFactoryBean has been set to one or more fully qualified interface names, then a JDK-based proxy will be created. The created proxy will implement all of the interfaces that were specified in the proxyInterfaces property; if the target class happens to implement a whole lot more interfaces than those specified in the proxyInterfaces property, that is all well and good but those additional interfaces will not be implemented by the returned proxy.

If the proxyInterfaces property of the ProxyFactoryBean has not been set, but the target class does implement one (or more) interfaces, then the ProxyFactoryBean will auto-detect the fact that the target class does actually implement at least one interface, and a JDK-based proxy will be created. The interfaces that are actually proxied will be all of the interfaces that the target class implements; in effect, this is the same as simply supplying a list of each and every interface that the target class implements to the proxyInterfaces property. However, it is significantly less work, and less prone to typos.

10.5.4 Proxying interfaces

Let’s look at a simple example of ProxyFactoryBean in action. This example involves:

  • A target bean that will be proxied. This is the "personTarget" bean definition in the example below.
  • An Advisor and an Interceptor used to provide advice.
  • An AOP proxy bean definition specifying the target object (the personTarget bean) and the interfaces to proxy, along with the advices to apply.
<bean id="personTarget" class="com.mycompany.PersonImpl">
    <property name="name" value="Tony"/>
    <property name="age" value="51"/>
</bean>

<bean id="myAdvisor" class="com.mycompany.MyAdvisor">
    <property name="someProperty" value="Custom string property value"/>
</bean>

<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor">
</bean>

<bean id="person"
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces" value="com.mycompany.Person"/>

    <property name="target" ref="personTarget"/>
    <property name="interceptorNames">
        <list>
            <value>myAdvisor</value>
            <value>debugInterceptor</value>
        </list>
    </property>
</bean>

Note that the interceptorNames property takes a list of String: the bean names of the interceptor or advisors in the current factory. Advisors, interceptors, before, after returning and throws advice objects can be used. The ordering of advisors is significant.

[Note]Note

You might be wondering why the list doesn’t hold bean references. The reason for this is that if the ProxyFactoryBean’s singleton property is set to false, it must be able to return independent proxy instances. If any of the advisors is itself a prototype, an independent instance would need to be returned, so it’s necessary to be able to obtain an instance of the prototype from the factory; holding a reference isn’t sufficient.

The "person" bean definition above can be used in place of a Person implementation, as follows:

Person person = (Person) factory.getBean("person");

Other beans in the same IoC context can express a strongly typed dependency on it, as with an ordinary Java object:

<bean id="personUser" class="com.mycompany.PersonUser">
    <property name="person"><ref bean="person"/></property>
</bean>

The PersonUser class in this example would expose a property of type Person. As far as it’s concerned, the AOP proxy can be used transparently in place of a "real" person implementation. However, its class would be a dynamic proxy class. It would be possible to cast it to the Advised interface (discussed below).

It’s possible to conceal the distinction between target and proxy using an anonymous inner bean, as follows. Only the ProxyFactoryBean definition is different; the advice is included only for completeness:

<bean id="myAdvisor" class="com.mycompany.MyAdvisor">
    <property name="someProperty" value="Custom string property value"/>
</bean>

<bean id="debugInterceptor" class="org.springframework.aop.interceptor.DebugInterceptor"/>

<bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="proxyInterfaces" value="com.mycompany.Person"/>
    <!-- Use inner bean, not local reference to target -->
    <property name="target">
        <bean class="com.mycompany.PersonImpl">
            <property name="name" value="Tony"/>
            <property name="age" value="51"/>
        </bean>
    </property>
    <property name="interceptorNames">
        <list>
            <value>myAdvisor</value>
            <value>debugInterceptor</value>
        </list>
    </property>
</bean>

This has the advantage that there’s only one object of type Person: useful if we want to prevent users of the application context from obtaining a reference to the un-advised object, or need to avoid any ambiguity with Spring IoC autowiring. There’s also arguably an advantage in that the ProxyFactoryBean definition is self-contained. However, there are times when being able to obtain the un-advised target from the factory might actually be an advantage: for example, in certain test scenarios.

10.5.5 Proxying classes

What if you need to proxy a class, rather than one or more interfaces?

Imagine that in our example above, there was no Person interface: we needed to advise a class called Person that didn’t implement any business interface. In this case, you can configure Spring to use CGLIB proxying, rather than dynamic proxies. Simply set the proxyTargetClass property on the ProxyFactoryBean above to true. While it’s best to program to interfaces, rather than classes, the ability to advise classes that don’t implement interfaces can be useful when working with legacy code. (In general, Spring isn’t prescriptive. While it makes it easy to apply good practices, it avoids forcing a particular approach.)

If you want to, you can force the use of CGLIB in any case, even if you do have interfaces.

CGLIB proxying works by generating a subclass of the target class at runtime. Spring configures this generated subclass to delegate method calls to the original target: the subclass is used to implement the Decorator pattern, weaving in the advice.

CGLIB proxying should generally be transparent to users. However, there are some issues to consider:

  • Final methods can’t be advised, as they can’t be overridden.
  • There is no need to add CGLIB to your classpath. As of Spring 3.2, CGLIB is repackaged and included in the spring-core JAR. In other words, CGLIB-based AOP will work "out of the box" just as do JDK dynamic proxies.

There’s little performance difference between CGLIB proxying and dynamic proxies. As of Spring 1.0, dynamic proxies are slightly faster. However, this may change in the future. Performance should not be a decisive consideration in this case.

10.5.6 Using global advisors

By appending an asterisk to an interceptor name, all advisors with bean names matching the part before the asterisk, will be added to the advisor chain. This can come in handy if you need to add a standard set of global advisors:

<bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="target" ref="service"/>
    <property name="interceptorNames">
        <list>
            <value>global*</value>
        </list>
    </property>
</bean>

<bean id="global_debug" class="org.springframework.aop.interceptor.DebugInterceptor"/>
<bean id="global_performance" class="org.springframework.aop.interceptor.PerformanceMonitorInterceptor"/>

10.6 Concise proxy definitions

Especially when defining transactional proxies, you may end up with many similar proxy definitions. The use of parent and child bean definitions, along with inner bean definitions, can result in much cleaner and more concise proxy definitions.

First a parent, template, bean definition is created for the proxy:

<bean id="txProxyTemplate" abstract="true"
        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
    <property name="transactionManager" ref="transactionManager"/>
    <property name="transactionAttributes">
        <props>
            <prop key="*">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
</bean>

This will never be instantiated itself, so may actually be incomplete. Then each proxy which needs to be created is just a child bean definition, which wraps the target of the proxy as an inner bean definition, since the target will never be used on its own anyway.

<bean id="myService" parent="txProxyTemplate">
    <property name="target">
        <bean class="org.springframework.samples.MyServiceImpl">
        </bean>
    </property>
</bean>

It is of course possible to override properties from the parent template, such as in this case, the transaction propagation settings:

<bean id="mySpecialService" parent="txProxyTemplate">
    <property name="target">
        <bean class="org.springframework.samples.MySpecialServiceImpl">
        </bean>
    </property>
    <property name="transactionAttributes">
        <props>
            <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
            <prop key="store*">PROPAGATION_REQUIRED</prop>
        </props>
    </property>
</bean>

Note that in the example above, we have explicitly marked the parent bean definition as abstract by using the abstract attribute, as described previously, so that it may not actually ever be instantiated. Application contexts (but not simple bean factories) will by default pre-instantiate all singletons. It is therefore important (at least for singleton beans) that if you have a (parent) bean definition which you intend to use only as a template, and this definition specifies a class, you must make sure to set the abstract attribute to true, otherwise the application context will actually try to pre-instantiate it.

10.7 Creating AOP proxies programmatically with the ProxyFactory

It’s easy to create AOP proxies programmatically using Spring. This enables you to use Spring AOP without dependency on Spring IoC.

The following listing shows creation of a proxy for a target object, with one interceptor and one advisor. The interfaces implemented by the target object will automatically be proxied:

ProxyFactory factory = new ProxyFactory(myBusinessInterfaceImpl);
factory.addAdvice(myMethodInterceptor);
factory.addAdvisor(myAdvisor);
MyBusinessInterface tb = (MyBusinessInterface) factory.getProxy();

The first step is to construct an object of type org.springframework.aop.framework.ProxyFactory. You can create this with a target object, as in the above example, or specify the interfaces to be proxied in an alternate constructor.

You can add advices (with interceptors as a specialized kind of advice) and/or advisors, and manipulate them for the life of the ProxyFactory. If you add an IntroductionInterceptionAroundAdvisor, you can cause the proxy to implement additional interfaces.

There are also convenience methods on ProxyFactory (inherited from AdvisedSupport) which allow you to add other advice types such as before and throws advice. AdvisedSupport is the superclass of both ProxyFactory and ProxyFactoryBean.

[Tip]Tip

Integrating AOP proxy creation with the IoC framework is best practice in most applications. We recommend that you externalize configuration from Java code with AOP, as in general.

10.8 Manipulating advised objects

However you create AOP proxies, you can manipulate them using the org.springframework.aop.framework.Advised interface. Any AOP proxy can be cast to this interface, whichever other interfaces it implements. This interface includes the following methods:

Advisor[] getAdvisors();

void addAdvice(Advice advice) throws AopConfigException;

void addAdvice(int pos, Advice advice) throws AopConfigException;

void addAdvisor(Advisor advisor) throws AopConfigException;

void addAdvisor(int pos, Advisor advisor) throws AopConfigException;

int indexOf(Advisor advisor);

boolean removeAdvisor(Advisor advisor) throws AopConfigException;

void removeAdvisor(int index) throws AopConfigException;

boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;

boolean isFrozen();

The getAdvisors() method will return an Advisor for every advisor, interceptor or other advice type that has been added to the factory. If you added an Advisor, the returned advisor at this index will be the object that you added. If you added an interceptor or other advice type, Spring will have wrapped this in an advisor with a pointcut that always returns true. Thus if you added a MethodInterceptor, the advisor returned for this index will be an DefaultPointcutAdvisor returning your MethodInterceptor and a pointcut that matches all classes and methods.

The addAdvisor() methods can be used to add any Advisor. Usually the advisor holding pointcut and advice will be the generic DefaultPointcutAdvisor, which can be used with any advice or pointcut (but not for introductions).

By default, it’s possible to add or remove advisors or interceptors even once a proxy has been created. The only restriction is that it’s impossible to add or remove an introduction advisor, as existing proxies from the factory will not show the interface change. (You can obtain a new proxy from the factory to avoid this problem.)

A simple example of casting an AOP proxy to the Advised interface and examining and manipulating its advice:

Advised advised = (Advised) myObject;
Advisor[] advisors = advised.getAdvisors();
int oldAdvisorCount = advisors.length;
System.out.println(oldAdvisorCount + " advisors");

// Add an advice like an interceptor without a pointcut
// Will match all proxied methods
// Can use for interceptors, before, after returning or throws advice
advised.addAdvice(new DebugInterceptor());

// Add selective advice using a pointcut
advised.addAdvisor(new DefaultPointcutAdvisor(mySpecialPointcut, myAdvice));

assertEquals("Added two advisors", oldAdvisorCount + 2, advised.getAdvisors().length);
[Note]Note

It’s questionable whether it’s advisable (no pun intended) to modify advice on a business object in production, although there are no doubt legitimate usage cases. However, it can be very useful in development: for example, in tests. I have sometimes found it very useful to be able to add test code in the form of an interceptor or other advice, getting inside a method invocation I want to test. (For example, the advice can get inside a transaction created for that method: for example, to run SQL to check that a database was correctly updated, before marking the transaction for roll back.)

Depending on how you created the proxy, you can usually set a frozen flag, in which case the Advised isFrozen() method will return true, and any attempts to modify advice through addition or removal will result in an AopConfigException. The ability to freeze the state of an advised object is useful in some cases, for example, to prevent calling code removing a security interceptor. It may also be used in Spring 1.1 to allow aggressive optimization if runtime advice modification is known not to be required.

10.9 Using the "auto-proxy" facility

So far we’ve considered explicit creation of AOP proxies using a ProxyFactoryBean or similar factory bean.

Spring also allows us to use "auto-proxy" bean definitions, which can automatically proxy selected bean definitions. This is built on Spring "bean post processor" infrastructure, which enables modification of any bean definition as the container loads.

In this model, you set up some special bean definitions in your XML bean definition file to configure the auto proxy infrastructure. This allows you just to declare the targets eligible for auto-proxying: you don’t need to use ProxyFactoryBean.

There are two ways to do this:

  • Using an auto-proxy creator that refers to specific beans in the current context.
  • A special case of auto-proxy creation that deserves to be considered separately; auto-proxy creation driven by source-level metadata attributes.

10.9.1 Autoproxy bean definitions

The org.springframework.aop.framework.autoproxy package provides the following standard auto-proxy creators.

BeanNameAutoProxyCreator

The BeanNameAutoProxyCreator class is a BeanPostProcessor that automatically creates AOP proxies for beans with names matching literal values or wildcards.

<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames" value="jdk*,onlyJdk"/>
    <property name="interceptorNames">
        <list>
            <value>myInterceptor</value>
        </list>
    </property>
</bean>

As with ProxyFactoryBean, there is an interceptorNames property rather than a list of interceptors, to allow correct behavior for prototype advisors. Named "interceptors" can be advisors or any advice type.

As with auto proxying in general, the main point of using BeanNameAutoProxyCreator is to apply the same configuration consistently to multiple objects, with minimal volume of configuration. It is a popular choice for applying declarative transactions to multiple objects.

Bean definitions whose names match, such as "jdkMyBean" and "onlyJdk" in the above example, are plain old bean definitions with the target class. An AOP proxy will be created automatically by the BeanNameAutoProxyCreator. The same advice will be applied to all matching beans. Note that if advisors are used (rather than the interceptor in the above example), the pointcuts may apply differently to different beans.

DefaultAdvisorAutoProxyCreator

A more general and extremely powerful auto proxy creator is DefaultAdvisorAutoProxyCreator. This will automagically apply eligible advisors in the current context, without the need to include specific bean names in the auto-proxy advisor’s bean definition. It offers the same merit of consistent configuration and avoidance of duplication as BeanNameAutoProxyCreator.

Using this mechanism involves:

  • Specifying a DefaultAdvisorAutoProxyCreator bean definition.
  • Specifying any number of Advisors in the same or related contexts. Note that these must be Advisors, not just interceptors or other advices. This is necessary because there must be a pointcut to evaluate, to check the eligibility of each advice to candidate bean definitions.

The DefaultAdvisorAutoProxyCreator will automatically evaluate the pointcut contained in each advisor, to see what (if any) advice it should apply to each business object (such as "businessObject1" and "businessObject2" in the example).

This means that any number of advisors can be applied automatically to each business object. If no pointcut in any of the advisors matches any method in a business object, the object will not be proxied. As bean definitions are added for new business objects, they will automatically be proxied if necessary.

Autoproxying in general has the advantage of making it impossible for callers or dependencies to obtain an un-advised object. Calling getBean("businessObject1") on this ApplicationContext will return an AOP proxy, not the target business object. (The "inner bean" idiom shown earlier also offers this benefit.)

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
    <property name="transactionInterceptor" ref="transactionInterceptor"/>
</bean>

<bean id="customAdvisor" class="com.mycompany.MyAdvisor"/>

<bean id="businessObject1" class="com.mycompany.BusinessObject1">
    <!-- Properties omitted -->
</bean>

<bean id="businessObject2" class="com.mycompany.BusinessObject2"/>

The DefaultAdvisorAutoProxyCreator is very useful if you want to apply the same advice consistently to many business objects. Once the infrastructure definitions are in place, you can simply add new business objects without including specific proxy configuration. You can also drop in additional aspects very easily - for example, tracing or performance monitoring aspects - with minimal change to configuration.

The DefaultAdvisorAutoProxyCreator offers support for filtering (using a naming convention so that only certain advisors are evaluated, allowing use of multiple, differently configured, AdvisorAutoProxyCreators in the same factory) and ordering. Advisors can implement the org.springframework.core.Ordered interface to ensure correct ordering if this is an issue. The TransactionAttributeSourceAdvisor used in the above example has a configurable order value; the default setting is unordered.

AbstractAdvisorAutoProxyCreator

This is the superclass of DefaultAdvisorAutoProxyCreator. You can create your own auto-proxy creators by subclassing this class, in the unlikely event that advisor definitions offer insufficient customization to the behavior of the framework DefaultAdvisorAutoProxyCreator.

10.9.2 Using metadata-driven auto-proxying

A particularly important type of auto-proxying is driven by metadata. This produces a similar programming model to .NET ServicedComponents. Instead of defining metadata in XML descriptors, configuration for transaction management and other enterprise services is held in source-level attributes.

In this case, you use the DefaultAdvisorAutoProxyCreator, in combination with Advisors that understand metadata attributes. The metadata specifics are held in the pointcut part of the candidate advisors, rather than in the auto-proxy creation class itself.

This is really a special case of the DefaultAdvisorAutoProxyCreator, but deserves consideration on its own. (The metadata-aware code is in the pointcuts contained in the advisors, not the AOP framework itself.)

The /attributes directory of the JPetStore sample application shows the use of attribute-driven auto-proxying. In this case, there’s no need to use the TransactionProxyFactoryBean. Simply defining transactional attributes on business objects is sufficient, because of the use of metadata-aware pointcuts. The bean definitions include the following code, in /WEB-INF/declarativeServices.xml. Note that this is generic, and can be used outside the JPetStore:

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
    <property name="transactionInterceptor" ref="transactionInterceptor"/>
</bean>

<bean id="transactionInterceptor"
        class="org.springframework.transaction.interceptor.TransactionInterceptor">
    <property name="transactionManager" ref="transactionManager"/>
    <property name="transactionAttributeSource">
        <bean class="org.springframework.transaction.interceptor.AttributesTransactionAttributeSource">
            <property name="attributes" ref="attributes"/>
        </bean>
    </property>
</bean>

<bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes"/>

The DefaultAdvisorAutoProxyCreator bean definition (the name is not significant, hence it can even be omitted) will pick up all eligible pointcuts in the current application context. In this case, the "transactionAdvisor" bean definition, of type TransactionAttributeSourceAdvisor, will apply to classes or methods carrying a transaction attribute. The TransactionAttributeSourceAdvisor depends on a TransactionInterceptor, via constructor dependency. The example resolves this via autowiring. The AttributesTransactionAttributeSource depends on an implementation of the org.springframework.metadata.Attributes interface. In this fragment, the "attributes" bean satisfies this, using the Jakarta Commons Attributes API to obtain attribute information. (The application code must have been compiled using the Commons Attributes compilation task.)

The /annotation directory of the JPetStore sample application contains an analogous example for auto-proxying driven by JDK 1.5+ annotations. The following configuration enables automatic detection of Spring’s Transactional annotation, leading to implicit proxies for beans containing that annotation:

<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>

<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
    <property name="transactionInterceptor" ref="transactionInterceptor"/>
</bean>

<bean id="transactionInterceptor"
        class="org.springframework.transaction.interceptor.TransactionInterceptor">
    <property name="transactionManager" ref="transactionManager"/>
    <property name="transactionAttributeSource">
        <bean class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"/>
    </property>
</bean>

The TransactionInterceptor defined here depends on a PlatformTransactionManager definition, which is not included in this generic file (although it could be) because it will be specific to the application’s transaction requirements (typically JTA, as in this example, or Hibernate, JDO or JDBC):

<bean id="transactionManager"
        class="org.springframework.transaction.jta.JtaTransactionManager"/>
[Tip]Tip

If you require only declarative transaction management, using these generic XML definitions will result in Spring automatically proxying all classes or methods with transaction attributes. You won’t need to work directly with AOP, and the programming model is similar to that of .NET ServicedComponents.

This mechanism is extensible. It’s possible to do auto-proxying based on custom attributes. You need to:

  • Define your custom attribute.
  • Specify an Advisor with the necessary advice, including a pointcut that is triggered by the presence of the custom attribute on a class or method. You may be able to use an existing advice, merely implementing a static pointcut that picks up the custom attribute.

It’s possible for such advisors to be unique to each advised class (for example, mixins): they simply need to be defined as prototype, rather than singleton, bean definitions. For example, the LockMixin introduction interceptor from the Spring test suite, shown above, could be used in conjunction with a generic DefaultIntroductionAdvisor:

<bean id="lockMixin" class="test.mixin.LockMixin" scope="prototype"/>

<bean id="lockableAdvisor" class="org.springframework.aop.support.DefaultIntroductionAdvisor"
        scope="prototype">
    <constructor-arg ref="lockMixin"/>
</bean>

Note that both lockMixin and lockableAdvisor are defined as prototypes.

10.10 Using TargetSources

Spring offers the concept of a TargetSource, expressed in the org.springframework.aop.TargetSource interface. This interface is responsible for returning the "target object" implementing the join point. The TargetSource implementation is asked for a target instance each time the AOP proxy handles a method invocation.

Developers using Spring AOP don’t normally need to work directly with TargetSources, but this provides a powerful means of supporting pooling, hot swappable and other sophisticated targets. For example, a pooling TargetSource can return a different target instance for each invocation, using a pool to manage instances.

If you do not specify a TargetSource, a default implementation is used that wraps a local object. The same target is returned for each invocation (as you would expect).

Let’s look at the standard target sources provided with Spring, and how you can use them.

[Tip]Tip

When using a custom target source, your target will usually need to be a prototype rather than a singleton bean definition. This allows Spring to create a new target instance when required.

10.10.1 Hot swappable target sources

The org.springframework.aop.target.HotSwappableTargetSource exists to allow the target of an AOP proxy to be switched while allowing callers to keep their references to it.

Changing the target source’s target takes effect immediately. The HotSwappableTargetSource is threadsafe.

You can change the target via the swap() method on HotSwappableTargetSource as follows:

HotSwappableTargetSource swapper = (HotSwappableTargetSource) beanFactory.getBean("swapper");
Object oldTarget = swapper.swap(newTarget);

The XML definitions required look as follows:

<bean id="initialTarget" class="mycompany.OldTarget"/>

<bean id="swapper" class="org.springframework.aop.target.HotSwappableTargetSource">
    <constructor-arg ref="initialTarget"/>
</bean>

<bean id="swappable" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="targetSource" ref="swapper"/>
</bean>

The above swap() call changes the target of the swappable bean. Clients who hold a reference to that bean will be unaware of the change, but will immediately start hitting the new target.

Although this example doesn’t add any advice - and it’s not necessary to add advice to use a TargetSource - of course any TargetSource can be used in conjunction with arbitrary advice.

10.10.2 Pooling target sources

Using a pooling target source provides a similar programming model to stateless session EJBs, in which a pool of identical instances is maintained, with method invocations going to free objects in the pool.

A crucial difference between Spring pooling and SLSB pooling is that Spring pooling can be applied to any POJO. As with Spring in general, this service can be applied in a non-invasive way.

Spring provides out-of-the-box support for Jakarta Commons Pool 1.3, which provides a fairly efficient pooling implementation. You’ll need the commons-pool Jar on your application’s classpath to use this feature. It’s also possible to subclass org.springframework.aop.target.AbstractPoolingTargetSource to support any other pooling API.

Sample configuration is shown below:

<bean id="businessObjectTarget" class="com.mycompany.MyBusinessObject"
        scope="prototype">
    ... properties omitted
</bean>

<bean id="poolTargetSource" class="org.springframework.aop.target.CommonsPoolTargetSource">
    <property name="targetBeanName" value="businessObjectTarget"/>
    <property name="maxSize" value="25"/>
</bean>

<bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="targetSource" ref="poolTargetSource"/>
    <property name="interceptorNames" value="myInterceptor"/>
</bean>

Note that the target object - "businessObjectTarget" in the example - must be a prototype. This allows the PoolingTargetSource implementation to create new instances of the target to grow the pool as necessary. See the javadocs of AbstractPoolingTargetSource and the concrete subclass you wish to use for information about its properties: "maxSize" is the most basic, and always guaranteed to be present.

In this case, "myInterceptor" is the name of an interceptor that would need to be defined in the same IoC context. However, it isn’t necessary to specify interceptors to use pooling. If you want only pooling, and no other advice, don’t set the interceptorNames property at all.

It’s possible to configure Spring so as to be able to cast any pooled object to the org.springframework.aop.target.PoolingConfig interface, which exposes information about the configuration and current size of the pool through an introduction. You’ll need to define an advisor like this:

<bean id="poolConfigAdvisor" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="targetObject" ref="poolTargetSource"/>
    <property name="targetMethod" value="getPoolingConfigMixin"/>
</bean>

This advisor is obtained by calling a convenience method on the AbstractPoolingTargetSource class, hence the use of MethodInvokingFactoryBean. This advisor’s name ("poolConfigAdvisor" here) must be in the list of interceptors names in the ProxyFactoryBean exposing the pooled object.

The cast will look as follows:

PoolingConfig conf = (PoolingConfig) beanFactory.getBean("businessObject");
System.out.println("Max pool size is " + conf.getMaxSize());
[Note]Note

Pooling stateless service objects is not usually necessary. We don’t believe it should be the default choice, as most stateless objects are naturally thread safe, and instance pooling is problematic if resources are cached.

Simpler pooling is available using auto-proxying. It’s possible to set the TargetSources used by any auto-proxy creator.

10.10.3 Prototype target sources

Setting up a "prototype" target source is similar to a pooling TargetSource. In this case, a new instance of the target will be created on every method invocation. Although the cost of creating a new object isn’t high in a modern JVM, the cost of wiring up the new object (satisfying its IoC dependencies) may be more expensive. Thus you shouldn’t use this approach without very good reason.

To do this, you could modify the poolTargetSource definition shown above as follows. (I’ve also changed the name, for clarity.)

<bean id="prototypeTargetSource" class="org.springframework.aop.target.PrototypeTargetSource">
    <property name="targetBeanName" ref="businessObjectTarget"/>
</bean>

There’s only one property: the name of the target bean. Inheritance is used in the TargetSource implementations to ensure consistent naming. As with the pooling target source, the target bean must be a prototype bean definition.

10.10.4 ThreadLocal target sources

ThreadLocal target sources are useful if you need an object to be created for each incoming request (per thread that is). The concept of a ThreadLocal provide a JDK-wide facility to transparently store resource alongside a thread. Setting up a ThreadLocalTargetSource is pretty much the same as was explained for the other types of target source:

<bean id="threadlocalTargetSource" class="org.springframework.aop.target.ThreadLocalTargetSource">
    <property name="targetBeanName" value="businessObjectTarget"/>
</bean>
[Note]Note

ThreadLocals come with serious issues (potentially resulting in memory leaks) when incorrectly using them in a multi-threaded and multi-classloader environments. One should always consider wrapping a threadlocal in some other class and never directly use the ThreadLocal itself (except of course in the wrapper class). Also, one should always remember to correctly set and unset (where the latter simply involved a call to ThreadLocal.set(null)) the resource local to the thread. Unsetting should be done in any case since not unsetting it might result in problematic behavior. Spring’s ThreadLocal support does this for you and should always be considered in favor of using ThreadLocals without other proper handling code.

10.11 Defining new Advice types

Spring AOP is designed to be extensible. While the interception implementation strategy is presently used internally, it is possible to support arbitrary advice types in addition to the out-of-the-box interception around advice, before, throws advice and after returning advice.

The org.springframework.aop.framework.adapter package is an SPI package allowing support for new custom advice types to be added without changing the core framework. The only constraint on a custom Advice type is that it must implement the org.aopalliance.aop.Advice marker interface.

Please refer to the org.springframework.aop.framework.adapter javadocs for further information.

10.12 Further resources

Please refer to the Spring sample applications for further examples of Spring AOP:

  • The JPetStore’s default configuration illustrates the use of the TransactionProxyFactoryBean for declarative transaction management.
  • The /attributes directory of the JPetStore illustrates the use of attribute-driven declarative transaction management.

    == Testing

10.13 Introduction to Spring Testing

Testing is an integral part of enterprise software development. This chapter focuses on the value-add of the IoC principle to unit testing and on the benefits of the Spring Framework’s support for integration testing. (A thorough treatment of testing in the enterprise is beyond the scope of this reference manual.)

10.14 Unit Testing

Dependency Injection should make your code less dependent on the container than it would be with traditional Java EE development. The POJOs that make up your application should be testable in JUnit or TestNG tests, with objects simply instantiated using the new operator, without Spring or any other container. You can use mock objects (in conjunction with other valuable testing techniques) to test your code in isolation. If you follow the architecture recommendations for Spring, the resulting clean layering and componentization of your codebase will facilitate easier unit testing. For example, you can test service layer objects by stubbing or mocking DAO or Repository interfaces, without needing to access persistent data while running unit tests.

True unit tests typically run extremely quickly, as there is no runtime infrastructure to set up. Emphasizing true unit tests as part of your development methodology will boost your productivity. You may not need this section of the testing chapter to help you write effective unit tests for your IoC-based applications. For certain unit testing scenarios, however, the Spring Framework provides the following mock objects and testing support classes.

10.14.1 Mock Objects

Environment

The org.springframework.mock.env package contains mock implementations of the Environment and PropertySource abstractions (see Section 5.13.1, “Bean definition profiles” and Section 5.13.3, “PropertySource Abstraction”). MockEnvironment and MockPropertySource are useful for developing out-of-container tests for code that depends on environment-specific properties.

JNDI

The org.springframework.mock.jndi package contains an implementation of the JNDI SPI, which you can use to set up a simple JNDI environment for test suites or stand-alone applications. If, for example, JDBC DataSources get bound to the same JNDI names in test code as within a Java EE container, you can reuse both application code and configuration in testing scenarios without modification.

Servlet API

The org.springframework.mock.web package contains a comprehensive set of Servlet API mock objects, targeted at usage with Spring’s Web MVC framework, which are useful for testing web contexts and controllers. These mock objects are generally more convenient to use than dynamic mock objects such as EasyMock or existing Servlet API mock objects such as MockObjects.

Portlet API

The org.springframework.mock.web.portlet package contains a set of Portlet API mock objects, targeted at usage with Spring’s Portlet MVC framework.

10.14.2 Unit Testing support Classes

General utilities

The org.springframework.test.util package contains ReflectionTestUtils, which is a collection of reflection-based utility methods. Developers use these methods in unit and integration testing scenarios in which they need to set a non- public field or invoke a non- public setter method when testing application code involving, for example:

  • ORM frameworks such as JPA and Hibernate that condone private or protected field access as opposed to public setter methods for properties in a domain entity.
  • Spring’s support for annotations such as @Autowired, @Inject, and @Resource, which provides dependency injection for private or protected fields, setter methods, and configuration methods.

Spring MVC

The org.springframework.test.web package contains ModelAndViewAssert, which you can use in combination with JUnit, TestNG, or any other testing framework for unit tests dealing with Spring MVC ModelAndView objects.

[Tip]Unit testing Spring MVC Controllers

To test your Spring MVC Controllers, use ModelAndViewAssert combined with MockHttpServletRequest, MockHttpSession, and so on from the org.springframework.mock.web package.

Note: As of Spring 4.0, the set of mocks in the org.springframework.mock.web package is now based on the Servlet 3.0 API.

10.15 Integration Testing

10.15.1 Overview

It is important to be able to perform some integration testing without requiring deployment to your application server or connecting to other enterprise infrastructure. This will enable you to test things such as:

  • The correct wiring of your Spring IoC container contexts.
  • Data access using JDBC or an ORM tool. This would include such things as the correctness of SQL statements, Hibernate queries, JPA entity mappings, etc.

The Spring Framework provides first-class support for integration testing in the spring-test module. The name of the actual JAR file might include the release version and might also be in the long org.springframework.test form, depending on where you get it from (see the section on Dependency Management for an explanation). This library includes the org.springframework.test package, which contains valuable classes for integration testing with a Spring container. This testing does not rely on an application server or other deployment environment. Such tests are slower to run than unit tests but much faster than the equivalent Selenium tests or remote tests that rely on deployment to an application server.

In Spring 2.5 and later, unit and integration testing support is provided in the form of the annotation-driven Spring TestContext Framework. The TestContext framework is agnostic of the actual testing framework in use, thus allowing instrumentation of tests in various environments including JUnit, TestNG, and so on.

10.15.2 Goals of Integration Testing

Spring’s integration testing support has the following primary goals:

The next few sections describe each goal and provide links to implementation and configuration details.

Context management and caching

The Spring TestContext Framework provides consistent loading of Spring ApplicationContexts and WebApplicationContexts as well as caching of those contexts. Support for the caching of loaded contexts is important, because startup time can become an issue — not because of the overhead of Spring itself, but because the objects instantiated by the Spring container take time to instantiate. For example, a project with 50 to 100 Hibernate mapping files might take 10 to 20 seconds to load the mapping files, and incurring that cost before running every test in every test fixture leads to slower overall test runs that reduce developer productivity.

Test classes typically declare either an array of resource locations for XML configuration metadata — often in the classpath — or an array of annotated classes that is used to configure the application. These locations or classes are the same as or similar to those specified in web.xml or other deployment configuration files.

By default, once loaded, the configured ApplicationContext is reused for each test. Thus the setup cost is incurred only once per test suite, and subsequent test execution is much faster. In this context, the term test suite means all tests run in the same JVM — for example, all tests run from an Ant, Maven, or Gradle build for a given project or module. In the unlikely case that a test corrupts the application context and requires reloading — for example, by modifying a bean definition or the state of an application object — the TestContext framework can be configured to reload the configuration and rebuild the application context before executing the next test.

See the section called “Context management” and the section called “Context caching” with the TestContext framework.

Dependency Injection of test fixtures

When the TestContext framework loads your application context, it can optionally configure instances of your test classes via Dependency Injection. This provides a convenient mechanism for setting up test fixtures using preconfigured beans from your application context. A strong benefit here is that you can reuse application contexts across various testing scenarios (e.g., for configuring Spring-managed object graphs, transactional proxies, DataSources, etc.), thus avoiding the need to duplicate complex test fixture setup for individual test cases.

As an example, consider the scenario where we have a class, HibernateTitleRepository, that implements data access logic for a Title domain entity. We want to write integration tests that test the following areas:

  • The Spring configuration: basically, is everything related to the configuration of the HibernateTitleRepository bean correct and present?
  • The Hibernate mapping file configuration: is everything mapped correctly, and are the correct lazy-loading settings in place?
  • The logic of the HibernateTitleRepository: does the configured instance of this class perform as anticipated?

See dependency injection of test fixtures with the TestContext framework.

Transaction management

One common issue in tests that access a real database is their effect on the state of the persistence store. Even when you’re using a development database, changes to the state may affect future tests. Also, many operations — such as inserting or modifying persistent data — cannot be performed (or verified) outside a transaction.

The TestContext framework addresses this issue. By default, the framework will create and roll back a transaction for each test. You simply write code that can assume the existence of a transaction. If you call transactionally proxied objects in your tests, they will behave correctly, according to their configured transactional semantics. In addition, if a test method deletes the contents of selected tables while running within the transaction managed for the test, the transaction will roll back by default, and the database will return to its state prior to execution of the test. Transactional support is provided to a test via a PlatformTransactionManager bean defined in the test’s application context.

If you want a transaction to commit — unusual, but occasionally useful when you want a particular test to populate or modify the database — the TestContext framework can be instructed to cause the transaction to commit instead of roll back via the @TransactionConfiguration and @Rollback annotations.

See transaction management with the TestContext framework.

Support classes for integration testing

The Spring TestContext Framework provides several abstract support classes that simplify the writing of integration tests. These base test classes provide well-defined hooks into the testing framework as well as convenient instance variables and methods, which enable you to access:

  • The ApplicationContext, for performing explicit bean lookups or testing the state of the context as a whole.
  • A JdbcTemplate, for executing SQL statements to query the database. Such queries can be used to confirm database state both prior to and after execution of database-related application code, and Spring ensures that such queries run in the scope of the same transaction as the application code. When used in conjunction with an ORM tool, be sure to avoid false positives.

In addition, you may want to create your own custom, application-wide superclass with instance variables and methods specific to your project.

See support classes for the TestContext framework.

10.15.3 JDBC Testing Support

The org.springframework.test.jdbc package contains JdbcTestUtils, which is a collection of JDBC related utility functions intended to simplify standard database testing scenarios. Specifically, JdbcTestUtils provides the following static utility methods.

  • countRowsInTable(..): counts the number of rows in the given table
  • countRowsInTableWhere(..): counts the number of rows in the given table, using the provided WHERE clause
  • deleteFromTables(..): deletes all rows from the specified tables
  • deleteFromTableWhere(..): deletes rows from the given table, using the provided WHERE clause
  • dropTables(..): drops the specified tables

Note that AbstractTransactionalJUnit4SpringContextTests and AbstractTransactionalTestNGSpringContextTests provide convenience methods which delegate to the aforementioned methods in JdbcTestUtils.

The spring-jdbc module provides support for configuring and launching an embedded database which can be used in integration tests that interact with a database. For details, see Section 13.8, “Embedded database support” and Section 13.8.8, “Testing data access logic with an embedded database”.

10.15.4 Annotations

Spring Testing Annotations

The Spring Framework provides the following set of Spring-specific annotations that you can use in your unit and integration tests in conjunction with the TestContext framework. Refer to the corresponding javadocs for further information, including default attribute values, attribute aliases, and so on.

  • @ContextConfiguration

    Defines class-level metadata that is used to determine how to load and configure an ApplicationContext for integration tests. Specifically, @ContextConfiguration declares the application context resource locations or the annotated classes that will be used to load the context.

    Resource locations are typically XML configuration files located in the classpath; whereas, annotated classes are typically @Configuration classes. However, resource locations can also refer to files in the file system, and annotated classes can be component classes, etc.

    @ContextConfiguration("/test-config.xml")
    public class XmlApplicationContextTests {
        // class body...
    }
    @ContextConfiguration(classes = TestConfig.class)
    public class ConfigClassApplicationContextTests {
        // class body...
    }

    As an alternative or in addition to declaring resource locations or annotated classes, @ContextConfiguration may be used to declare ApplicationContextInitializer classes.

    @ContextConfiguration(initializers = CustomContextIntializer.class)
    public class ContextInitializerTests {
        // class body...
    }

    @ContextConfiguration may optionally be used to declare the ContextLoader strategy as well. Note, however, that you typically do not need to explicitly configure the loader since the default loader supports either resource locations or annotated classes as well as initializers.

    @ContextConfiguration(locations = "/test-context.xml", loader = CustomContextLoader.class)
    public class CustomLoaderXmlApplicationContextTests {
        // class body...
    }
    [Note]Note

    @ContextConfiguration provides support for inheriting resource locations or configuration classes as well as context initializers declared by superclasses by default.

    See the section called “Context management” and the @ContextConfiguration javadocs for further details.

  • @WebAppConfiguration

    A class-level annotation that is used to declare that the ApplicationContext loaded for an integration test should be a WebApplicationContext. The mere presence of @WebAppConfiguration on a test class ensures that a WebApplicationContext will be loaded for the test, using the default value of "file:src/main/webapp" for the path to the root of the web application (i.e., the resource base path). The resource base path is used behind the scenes to create a MockServletContext which serves as the ServletContext for the test’s WebApplicationContext.

    @ContextConfiguration
    @WebAppConfiguration
    public class WebAppTests {
        // class body...
    }

    To override the default, specify a different base resource path via the implicit value attribute. Both classpath: and file: resource prefixes are supported. If no resource prefix is supplied the path is assumed to be a file system resource.

    @ContextConfiguration
    @WebAppConfiguration("classpath:test-web-resources")
    public class WebAppTests {
        // class body...
    }

    Note that @WebAppConfiguration must be used in conjunction with @ContextConfiguration, either within a single test class or within a test class hierarchy. See the @WebAppConfiguration javadocs for further details.

  • @ContextHierarchy

    A class-level annotation that is used to define a hierarchy of ApplicationContexts for integration tests. @ContextHierarchy should be declared with a list of one or more @ContextConfiguration instances, each of which defines a level in the context hierarchy. The following examples demonstrate the use of @ContextHierarchy within a single test class; however, @ContextHierarchy can also be used within a test class hierarchy.

    @ContextHierarchy({
        @ContextConfiguration("/parent-config.xml"),
        @ContextConfiguration("/child-config.xml")
    })
    public class ContextHierarchyTests {
        // class body...
    }
    @WebAppConfiguration
    @ContextHierarchy({
        @ContextConfiguration(classes = AppConfig.class),
        @ContextConfiguration(classes = WebConfig.class)
    })
    public class WebIntegrationTests {
        // class body...
    }

    If you need to merge or override the configuration for a given level of the context hierarchy within a test class hierarchy, you must explicitly name that level by supplying the same value to the name attribute in @ContextConfiguration at each corresponding level in the class hierarchy. See the section called “Context hierarchies” and the @ContextHierarchy javadocs for further examples.

  • @ActiveProfiles

    A class-level annotation that is used to declare which bean definition profiles should be active when loading an ApplicationContext for test classes.

    @ContextConfiguration
    @ActiveProfiles("dev")
    public class DeveloperTests {
        // class body...
    }
    @ContextConfiguration
    @ActiveProfiles({"dev", "integration"})
    public class DeveloperIntegrationTests {
        // class body...
    }
    [Note]Note

    @ActiveProfiles provides support for inheriting active bean definition profiles declared by superclasses by default. It is also possible to resolve active bean definition profiles programmatically by implementing a custom ActiveProfilesResolver and registering it via the resolver attribute of @ActiveProfiles.

    See the section called “Context configuration with environment profiles” and the @ActiveProfiles javadocs for examples and further details.

  • @TestPropertySource

    A class-level annotation that is used to configure the locations of properties files and inlined properties to be added to the Environment's set of PropertySources for an ApplicationContext loaded for an integration test.

    Test property sources have higher precedence than those loaded from the operating system’s environment or Java system properties as well as property sources added by the application declaratively via @PropertySource or programmatically. Thus, test property sources can be used to selectively override properties defined in system and application property sources. Furthermore, inlined properties have higher precedence than properties loaded from resource locations.

    The following example demonstrates how to declare a properties file from the classpath.

    @ContextConfiguration
    @TestPropertySource("/test.properties")
    public class MyIntegrationTests {
        // class body...
    }

    The following example demonstrates how to declare inlined properties.

    @ContextConfiguration
    @TestPropertySource(properties = { "timezone = GMT", "port: 4242" })
    public class MyIntegrationTests {
        // class body...
    }
  • @DirtiesContext

    Indicates that the underlying Spring ApplicationContext has been dirtied during the execution of a test (i.e., modified or corrupted in some manner — for example, by changing the state of a singleton bean) and should be closed, regardless of whether the test passed. When an application context is marked dirty, it is removed from the testing framework’s cache and closed. As a consequence, the underlying Spring container will be rebuilt for any subsequent test that requires a context with the same configuration metadata.

    @DirtiesContext can be used as both a class-level and method-level annotation within the same test class. In such scenarios, the ApplicationContext is marked as dirty after any such annotated method as well as after the entire class. If the ClassMode is set to AFTER_EACH_TEST_METHOD, the context is marked dirty after each test method in the class.

    The following examples explain when the context would be dirtied for various configuration scenarios:

    • After the current test class, when declared on a class with class mode set to AFTER_CLASS (i.e., the default class mode).

      @DirtiesContext
      public class ContextDirtyingTests {
          // some tests that result in the Spring container being dirtied
      }
    • After each test method in the current test class, when declared on a class with class mode set to AFTER_EACH_TEST_METHOD.

      @DirtiesContext(classMode = ClassMode.AFTER_EACH_TEST_METHOD)
      public class ContextDirtyingTests {
          // some tests that result in the Spring container being dirtied
      }
    • After the current test, when declared on a method.

      @DirtiesContext
      @Test
      public void testProcessWhichDirtiesAppCtx() {
          // some logic that results in the Spring container being dirtied
      }

      If @DirtiesContext is used in a test whose context is configured as part of a context hierarchy via @ContextHierarchy, the hierarchyMode flag can be used to control how the context cache is cleared. By default an exhaustive algorithm will be used that clears the context cache including not only the current level but also all other context hierarchies that share an ancestor context common to the current test; all ApplicationContexts that reside in a sub-hierarchy of the common ancestor context will be removed from the context cache and closed. If the exhaustive algorithm is overkill for a particular use case, the simpler current level algorithm can be specified instead, as seen below.

      @ContextHierarchy({
          @ContextConfiguration("/parent-config.xml"),
          @ContextConfiguration("/child-config.xml")
      })
      public class BaseTests {
          // class body...
      }
      
      public class ExtendedTests extends BaseTests {
      
          @Test
          @DirtiesContext(hierarchyMode = HierarchyMode.CURRENT_LEVEL)
          public void test() {
              // some logic that results in the child context being dirtied
          }
      }

    For further details regarding the EXHAUSTIVE and CURRENT_LEVEL algorithms see the DirtiesContext.HierarchyMode javadocs.

  • @TestExecutionListeners

    Defines class-level metadata for configuring which TestExecutionListeners should be registered with the TestContextManager. Typically, @TestExecutionListeners is used in conjunction with @ContextConfiguration.

    @ContextConfiguration
    @TestExecutionListeners({CustomTestExecutionListener.class, AnotherTestExecutionListener.class})
    public class CustomTestExecutionListenerTests {
        // class body...
    }

    @TestExecutionListeners supports inherited listeners by default. See the javadocs for an example and further details.

  • @TransactionConfiguration

    Defines class-level metadata for configuring transactional tests. Specifically, the bean name of the PlatformTransactionManager that should be used to drive transactions can be explicitly specified if there are multiple beans of type PlatformTransactionManager in the test’s ApplicationContext and if the bean name of the desired PlatformTransactionManager is not "transactionManager". In addition, you can change the defaultRollback flag to false. Typically, @TransactionConfiguration is used in conjunction with @ContextConfiguration.

    @ContextConfiguration
    @TransactionConfiguration(transactionManager = "txMgr", defaultRollback = false)
    public class CustomConfiguredTransactionalTests {
        // class body...
    }
    [Note]Note

    If the default conventions are sufficient for your test configuration, you can avoid using @TransactionConfiguration altogether. In other words, if you have only one transaction manager — or if you have multiple transaction managers but the transaction manager for tests is named "transactionManager" or specified via a TransactionManagementConfigurer — and if you want transactions to roll back automatically, then there is no need to annotate your test class with @TransactionConfiguration.

  • @Rollback

    Indicates whether the transaction for the annotated test method should be rolled back after the test method has completed. If true, the transaction is rolled back; otherwise, the transaction is committed. Use @Rollback to override the default rollback flag configured at the class level.

    @Rollback(false)
    @Test
    public void testProcessWithoutRollback() {
        // ...
    }
  • @BeforeTransaction

    Indicates that the annotated public void method should be executed before a transaction is started for test methods configured to run within a transaction via the @Transactional annotation.

    @BeforeTransaction
    public void beforeTransaction() {
        // logic to be executed before a transaction is started
    }
  • @AfterTransaction

    Indicates that the annotated public void method should be executed after a transaction has ended for test methods configured to run within a transaction via the @Transactional annotation.

    @AfterTransaction
    public void afterTransaction() {
        // logic to be executed after a transaction has ended
    }
  • @Sql

    Used to annotate a test class or test method to configure SQL scripts to be executed against a given database during integration tests.

    @Test
    @Sql({"/test-schema.sql", "/test-user-data.sql"})
    public void userTest {
        // execute code that relies on the test schema and test data
    }

    See the section called “Executing SQL scripts declaratively with @Sql for further details.

  • @SqlConfig

    Defines metadata that is used to determine how to parse and execute SQL scripts configured via the @Sql annotation.

    @Test
    @Sql(
        scripts = "/test-user-data.sql",
        config = @SqlConfig(commentPrefix = "`", separator = "@@")
    )
    public void userTest {
        // execute code that relies on the test data
    }
  • @SqlGroup

    A container annotation that aggregates several @Sql annotations. Can be used natively, declaring several nested @Sql annotations. Can also be used in conjunction with Java 8’s support for repeatable annotations, where @Sql can simply be declared several times on the same class or method, implicitly generating this container annotation.

    @Test
    @SqlGroup({
        @Sql(scripts = "/test-schema.sql", config = @SqlConfig(commentPrefix = "`")),
        @Sql("/test-user-data.sql")
    )}
    public void userTest {
        // execute code that uses the test schema and test data
    }

Standard Annotation Support

The following annotations are supported with standard semantics for all configurations of the Spring TestContext Framework. Note that these annotations are not specific to tests and can be used anywhere in the Spring Framework.

  • @Autowired
  • @Qualifier
  • @Resource (javax.annotation) if JSR-250 is present
  • @Inject (javax.inject) if JSR-330 is present
  • @Named (javax.inject) if JSR-330 is present
  • @PersistenceContext (javax.persistence) if JPA is present
  • @PersistenceUnit (javax.persistence) if JPA is present
  • @Required
  • @Transactional
[Note]JSR-250 Lifecycle Annotations

In the Spring TestContext Framework @PostConstruct and @PreDestroy may be used with standard semantics on any application components configured in the ApplicationContext; however, these lifecycle annotations have limited usage within an actual test class.

If a method within a test class is annotated with @PostConstruct, that method will be executed before any before methods of the underlying test framework (e.g., methods annotated with JUnit’s @Before), and that will apply for every test method in the test class. On the other hand, if a method within a test class is annotated with @PreDestroy, that method will never be executed. Within a test class it is therefore recommended to use test lifecycle callbacks from the underlying test framework instead of @PostConstruct and @PreDestroy.

Spring JUnit Testing Annotations

The following annotations are only supported when used in conjunction with the SpringJUnit4ClassRunner or the JUnit support classes.

  • @IfProfileValue

    Indicates that the annotated test is enabled for a specific testing environment. If the configured ProfileValueSource returns a matching value for the provided name, the test is enabled. This annotation can be applied to an entire class or to individual methods. Class-level usage overrides method-level usage.

    @IfProfileValue(name="java.vendor", value="Oracle Corporation")
    @Test
    public void testProcessWhichRunsOnlyOnOracleJvm() {
        // some logic that should run only on Java VMs from Oracle Corporation
    }

    Alternatively, you can configure @IfProfileValue with a list of values (with OR semantics) to achieve TestNG-like support for test groups in a JUnit environment. Consider the following example:

    @IfProfileValue(name="test-groups", values={"unit-tests", "integration-tests"})
    @Test
    public void testProcessWhichRunsForUnitOrIntegrationTestGroups() {
        // some logic that should run only for unit and integration test groups
    }
  • @ProfileValueSourceConfiguration

    Class-level annotation that specifies what type of ProfileValueSource to use when retrieving profile values configured through the @IfProfileValue annotation. If @ProfileValueSourceConfiguration is not declared for a test, SystemProfileValueSource is used by default.

    @ProfileValueSourceConfiguration(CustomProfileValueSource.class)
    public class CustomProfileValueSourceTests {
        // class body...
    }
  • @Timed

    Indicates that the annotated test method must finish execution in a specified time period (in milliseconds). If the text execution time exceeds the specified time period, the test fails.

    The time period includes execution of the test method itself, any repetitions of the test (see @Repeat), as well as any set up or tear down of the test fixture.

    @Timed(millis=1000)
    public void testProcessWithOneSecondTimeout() {
        // some logic that should not take longer than 1 second to execute
    }

    Spring’s @Timed annotation has different semantics than JUnit’s @Test(timeout=...) support. Specifically, due to the manner in which JUnit handles test execution timeouts (that is, by executing the test method in a separate Thread), @Test(timeout=...) preemptively fails the test if the test takes too long. Spring’s @Timed, on the other hand, does not preemptively fail the test but rather waits for the test to complete before failing.

  • @Repeat

    Indicates that the annotated test method must be executed repeatedly. The number of times that the test method is to be executed is specified in the annotation.

    The scope of execution to be repeated includes execution of the test method itself as well as any set up or tear down of the test fixture.

    @Repeat(10)
    @Test
    public void testProcessRepeatedly() {
        // ...
    }

Meta-Annotation Support for Testing

As of Spring Framework 4.0, it is possible to use test-related annotations as meta-annotations in order to create custom composed annotations and reduce configuration duplication across a test suite.

Each of the following may be used as meta-annotations in conjunction with the TestContext framework.

  • @ContextConfiguration
  • @ContextHierarchy
  • @ActiveProfiles
  • @TestPropertySource
  • @DirtiesContext
  • @WebAppConfiguration
  • @TestExecutionListeners
  • @Transactional
  • @BeforeTransaction
  • @AfterTransaction
  • @TransactionConfiguration
  • @Rollback
  • @Sql
  • @SqlConfig
  • @SqlGroup
  • @Repeat
  • @Timed
  • @IfProfileValue
  • @ProfileValueSourceConfiguration

For example, if we discover that we are repeating the following configuration across our JUnit-based test suite…

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public class OrderRepositoryTests { }

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public class UserRepositoryTests { }

We can reduce the above duplication by introducing a custom composed annotation that centralizes the common test configuration like this:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ContextConfiguration({"/app-config.xml", "/test-data-access-config.xml"})
@ActiveProfiles("dev")
@Transactional
public @interface TransactionalDevTest { }

Then we can use our custom @TransactionalDevTest annotation to simplify the configuration of individual test classes as follows:

@RunWith(SpringJUnit4ClassRunner.class)
@TransactionalDevTest
public class OrderRepositoryTests { }

@RunWith(SpringJUnit4ClassRunner.class)
@TransactionalDevTest
public class UserRepositoryTests { }

10.15.5 Spring TestContext Framework

The Spring TestContext Framework (located in the org.springframework.test.context package) provides generic, annotation-driven unit and integration testing support that is agnostic of the testing framework in use. The TestContext framework also places a great deal of importance on convention over configuration with reasonable defaults that can be overridden through annotation-based configuration.

In addition to generic testing infrastructure, the TestContext framework provides explicit support for JUnit and TestNG in the form of abstract support classes. For JUnit, Spring also provides a custom JUnit Runner that allows one to write so-called POJO test classes. POJO test classes are not required to extend a particular class hierarchy.

The following section provides an overview of the internals of the TestContext framework. If you are only interested in using the framework and not necessarily interested in extending it with your own custom listeners or custom loaders, feel free to go directly to the configuration (context management, dependency injection, transaction management), support classes, and annotation support sections.

Key abstractions

The core of the framework consists of the TestContext and TestContextManager classes and the TestExecutionListener, ContextLoader, and SmartContextLoader interfaces. A TestContextManager is created on a per-test basis (e.g., for the execution of a single test method in JUnit). The TestContextManager in turn manages a TestContext that holds the context of the current test. The TestContextManager also updates the state of the TestContext as the test progresses and delegates to TestExecutionListeners, which instrument the actual test execution by providing dependency injection, managing transactions, and so on. A ContextLoader (or SmartContextLoader) is responsible for loading an ApplicationContext for a given test class. Consult the javadocs and the Spring test suite for further information and examples of various implementations.

  • TestContext: Encapsulates the context in which a test is executed, agnostic of the actual testing framework in use, and provides context management and caching support for the test instance for which it is responsible. The TestContext also delegates to a ContextLoader (or SmartContextLoader) to load an ApplicationContext if requested.
  • TestContextManager: The main entry point into the Spring TestContext Framework, which manages a single TestContext and signals events to all registered TestExecutionListeners at well-defined test execution points:

    • prior to any before class methods of a particular testing framework
    • test instance preparation
    • prior to any before methods of a particular testing framework
    • after any after methods of a particular testing framework
    • after any after class methods of a particular testing framework
  • TestExecutionListener: Defines a listener API for reacting to test execution events published by the TestContextManager with which the listener is registered. See the section called “TestExecutionListener configuration”.
  • ContextLoader: Strategy interface introduced in Spring 2.5 for loading an ApplicationContext for an integration test managed by the Spring TestContext Framework.

    Implement SmartContextLoader instead of this interface in order to provide support for annotated classes, active bean definition profiles, test property sources, context hierarchies, and WebApplicationContexts.

  • SmartContextLoader: Extension of the ContextLoader interface introduced in Spring 3.1.

    The SmartContextLoader SPI supersedes the ContextLoader SPI that was introduced in Spring 2.5. Specifically, a SmartContextLoader can choose to process resource locations, annotated classes, or context initializers. Furthermore, a SmartContextLoader can set active bean definition profiles and test property sources in the context that it loads.

    Spring provides the following implementations:

    • DelegatingSmartContextLoader: one of two default loaders which delegates internally to an AnnotationConfigContextLoader, a GenericXmlContextLoader, or a GenericGroovyXmlContextLoader depending either on the configuration declared for the test class or on the presence of default locations or default configuration classes. Groovy support is only enabled if Groovy is on the classpath.
    • WebDelegatingSmartContextLoader: one of two default loaders which delegates internally to an AnnotationConfigWebContextLoader, a GenericXmlWebContextLoader, or a GenericGroovyXmlWebContextLoader depending either on the configuration declared for the test class or on the presence of default locations or default configuration classes. A web ContextLoader will only be used if @WebAppConfiguration is present on the test class. Groovy support is only enabled if Groovy is on the classpath.
    • AnnotationConfigContextLoader: loads a standard ApplicationContext from annotated classes.
    • AnnotationConfigWebContextLoader: loads a WebApplicationContext from annotated classes.
    • GenericGroovyXmlContextLoader: loads a standard ApplicationContext from resource locations that are either Groovy scripts or XML configuration files.
    • GenericGroovyXmlWebContextLoader: loads a WebApplicationContext from resource locations that are either Groovy scripts or XML configuration files.
    • GenericXmlContextLoader: loads a standard ApplicationContext from XML resource locations.
    • GenericXmlWebContextLoader: loads a WebApplicationContext from XML resource locations.
    • GenericPropertiesContextLoader: loads a standard ApplicationContext from Java Properties files.

The following sections explain how to configure the TestContext framework through annotations and provide working examples of how to write unit and integration tests with the framework.

TestExecutionListener configuration

Spring provides the following TestExecutionListener implementations that are registered by default, exactly in this order.

  • ServletTestExecutionListener: configures Servlet API mocks for a WebApplicationContext
  • DependencyInjectionTestExecutionListener: provides dependency injection for the test instance
  • DirtiesContextTestExecutionListener: handles the @DirtiesContext annotation
  • TransactionalTestExecutionListener: provides transactional test execution with default rollback semantics
  • SqlScriptsTestExecutionListener: executes SQL scripts configured via the @Sql annotation
Registering custom TestExecutionListeners

Custom TestExecutionListeners can be registered for a test class and its subclasses via the @TestExecutionListeners annotation. See annotation support and the javadocs for @TestExecutionListeners for details and examples.

Automatic discovery of default TestExecutionListeners

Registering custom TestExecutionListeners via @TestExecutionListeners is suitable for custom listeners that are used in limited testing scenarios; however, it can become cumbersome if a custom listener needs to be used across a test suite. To address this issue, Spring Framework 4.1 supports automatic discovery of default TestExecutionListener implementations via the SpringFactoriesLoader mechanism.

Specifically, the spring-test module declares all core default TestExecutionListeners under the org.springframework.test.context.TestExecutionListener key in its META-INF/spring.factories properties file. Third-party frameworks and developers can contribute their own TestExecutionListeners to the list of default listeners in the same manner via their own META-INF/spring.factories properties file.

Ordering TestExecutionListeners

When the TestContext framework discovers default TestExecutionListeners via the aforementioned SpringFactoriesLoader mechanism, the instantiated listeners are sorted using Spring’s AnnotationAwareOrderComparator which honors Spring’s Ordered interface and @Order annotation for ordering. AbstractTestExecutionListener and all default TestExecutionListeners provided by Spring implement Ordered with appropriate values. Third-party frameworks and developers should therefore make sure that their default TestExecutionListeners are registered in the proper order by implementing Ordered or declaring @Order. Consult the javadocs for the getOrder() methods of the core default TestExecutionListeners for details on what values are assigned to each core listener.

Merging TestExecutionListeners

If a custom TestExecutionListener is registered via @TestExecutionListeners, the default listeners will not be registered. In most common testing scenarios, this effectively forces the developer to manually declare all default listeners in addition to any custom listeners. The following listing demonstrates this style of configuration.

@ContextConfiguration
@TestExecutionListeners({
    MyCustomTestExecutionListener.class,
    ServletTestExecutionListener.class,
    DependencyInjectionTestExecutionListener.class,
    DirtiesContextTestExecutionListener.class,
    TransactionalTestExecutionListener.class,
    SqlScriptsTestExecutionListener.class
})
public class MyTest {
    // class body...
}

The challenge with this approach is that it requires that the developer know exactly which listeners are registered by default. Moreover, the set of default listeners can change from release to release — for example, SqlScriptsTestExecutionListener was introduced in Spring Framework 4.1. Furthermore, third-party frameworks like Spring Security register their own default TestExecutionListeners via the aforementioned automatic discovery mechanism.

To avoid having to be aware of and re-declare all default listeners, the mergeMode attribute of @TestExecutionListeners can be set to MergeMode.MERGE_WITH_DEFAULTS. MERGE_WITH_DEFAULTS indicates that locally declared listeners should be merged with the default listeners. The merging algorithm ensures that duplicates are removed from the list and that the resulting set of merged listeners is sorted according to the semantics of AnnotationAwareOrderComparator as described in the section called “Ordering TestExecutionListeners”. If a listener implements Ordered or is annotated with @Order it can influence the position in which it is merged with the defaults; otherwise, locally declared listeners will simply be appended to the list of default listeners when merged.

For example, if the MyCustomTestExecutionListener class in the previous example configures its order value (for example, 500) to be less than the order of the ServletTestExecutionListener (which happens to be 1000), the MyCustomTestExecutionListener can then be automatically merged with the list of defaults in front of the ServletTestExecutionListener, and the previous example could be replaced with the following.

@ContextConfiguration
@TestExecutionListeners(
    listeners = MyCustomTestExecutionListener.class,
    mergeMode = MERGE_WITH_DEFAULTS,
)
public class MyTest {
    // class body...
}

Context management

Each TestContext provides context management and caching support for the test instance it is responsible for. Test instances do not automatically receive access to the configured ApplicationContext. However, if a test class implements the ApplicationContextAware interface, a reference to the ApplicationContext is supplied to the test instance. Note that AbstractJUnit4SpringContextTests and AbstractTestNGSpringContextTests implement ApplicationContextAware and therefore provide access to the ApplicationContext automatically.

[Tip]@Autowired ApplicationContext

As an alternative to implementing the ApplicationContextAware interface, you can inject the application context for your test class through the @Autowired annotation on either a field or setter method. For example:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class MyTest {

    @Autowired
    private ApplicationContext applicationContext;

    // class body...
}

Similarly, if your test is configured to load a WebApplicationContext, you can inject the web application context into your test as follows:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration
public class MyWebAppTest {
    @Autowired
    private WebApplicationContext wac;

    // class body...
}

Dependency injection via @Autowired is provided by the DependencyInjectionTestExecutionListener which is configured by default (see the section called “Dependency injection of test fixtures”).

Test classes that use the TestContext framework do not need to extend any particular class or implement a specific interface to configure their application context. Instead, configuration is achieved simply by declaring the @ContextConfiguration annotation at the class level. If your test class does not explicitly declare application context resource locations or annotated classes, the configured ContextLoader determines how to load a context from a default location or default configuration classes. In addition to context resource locations and annotated classes, an application context can also be configured via application context initializers.

The following sections explain how to configure an ApplicationContext via XML configuration files, annotated classes (typically @Configuration classes), or context initializers using Spring’s @ContextConfiguration annotation. Alternatively, you can implement and configure your own custom SmartContextLoader for advanced use cases.

Context configuration with XML resources

To load an ApplicationContext for your tests using XML configuration files, annotate your test class with @ContextConfiguration and configure the locations attribute with an array that contains the resource locations of XML configuration metadata. A plain or relative path — for example "context.xml" — will be treated as a classpath resource that is relative to the package in which the test class is defined. A path starting with a slash is treated as an absolute classpath location, for example "/org/example/config.xml". A path which represents a resource URL (i.e., a path prefixed with classpath:, file:, http:, etc.) will be used as is.

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/app-config.xml" and
// "/test-config.xml" in the root of the classpath
@ContextConfiguration(locations={"/app-config.xml", "/test-config.xml"})
public class MyTest {
    // class body...
}

@ContextConfiguration supports an alias for the locations attribute through the standard Java value attribute. Thus, if you do not need to declare additional attributes in @ContextConfiguration, you can omit the declaration of the locations attribute name and declare the resource locations by using the shorthand format demonstrated in the following example.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"/app-config.xml", "/test-config.xml"})
public class MyTest {
    // class body...
}

If you omit both the locations and value attributes from the @ContextConfiguration annotation, the TestContext framework will attempt to detect a default XML resource location. Specifically, GenericXmlContextLoader and GenericXmlWebContextLoader detect a default location based on the name of the test class. If your class is named com.example.MyTest, GenericXmlContextLoader loads your application context from "classpath:com/example/MyTest-context.xml".

package com.example;

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from
// "classpath:com/example/MyTest-context.xml"
@ContextConfiguration
public class MyTest {
    // class body...
}
Context configuration with Groovy scripts

To load an ApplicationContext for your tests using Groovy scripts that utilize the Groovy Bean Definition DSL, annotate your test class with @ContextConfiguration and configure the locations or value attribute with an array that contains the resource locations of Groovy scripts. Resource lookup semantics for Groovy scripts are the same as those described for XML configuration files.

[Tip]Enabling Groovy script support

Support for using Groovy scripts to load an ApplicationContext in the Spring TestContext Framework is enabled automatically if Groovy is on the classpath.

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/AppConfig.groovy" and
// "/TestConfig.groovy" in the root of the classpath
@ContextConfiguration({"/AppConfig.groovy", "/TestConfig.Groovy"})
public class MyTest {
    // class body...
}

If you omit both the locations and value attributes from the @ContextConfiguration annotation, the TestContext framework will attempt to detect a default Groovy script. Specifically, GenericGroovyXmlContextLoader and GenericGroovyXmlWebContextLoader detect a default location based on the name of the test class. If your class is named com.example.MyTest, the Groovy context loader will load your application context from "classpath:com/example/MyTestContext.groovy".

package com.example;

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from
// "classpath:com/example/MyTestContext.groovy"
@ContextConfiguration
public class MyTest {
    // class body...
}
[Tip]Declaring XML config and Groovy scripts simultaneously

Both XML configuration files and Groovy scripts can be declared simultaneously via the locations or value attribute of @ContextConfiguration. If the path to a configured resource location ends with .xml it will be loaded using an XmlBeanDefinitionReader; otherwise it will be loaded using a GroovyBeanDefinitionReader.

The following listing demonstrates how to combine both in an integration test.

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from
// "/app-config.xml" and "/TestConfig.groovy"
@ContextConfiguration({ "/app-config.xml", "/TestConfig.groovy" })
public class MyTest {
    // class body...
}
Context configuration with annotated classes

To load an ApplicationContext for your tests using annotated classes (see Section 5.12, “Java-based container configuration”), annotate your test class with @ContextConfiguration and configure the classes attribute with an array that contains references to annotated classes.

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from AppConfig and TestConfig
@ContextConfiguration(classes = {AppConfig.class, TestConfig.class})
public class MyTest {
    // class body...
}
[Tip]Annotated Classes

The term annotated class can refer to any of the following.

  • A class annotated with @Configuration
  • A component (i.e., a class annotated with @Component, @Service, @Repository, etc.)
  • A JSR-330 compliant class that is annotated with javax.inject annotations
  • Any other class that contains @Bean-methods

Consult the javadocs of @Configuration and @Bean for further information regarding the configuration and semantics of annotated classes, paying special attention to the discussion of `@Bean` Lite Mode.

If you omit the classes attribute from the @ContextConfiguration annotation, the TestContext framework will attempt to detect the presence of default configuration classes. Specifically, AnnotationConfigContextLoader and AnnotationConfigWebContextLoader will detect all static inner classes of the test class that meet the requirements for configuration class implementations as specified in the @Configuration javadocs. In the following example, the OrderServiceTest class declares a static inner configuration class named Config that will be automatically used to load the ApplicationContext for the test class. Note that the name of the configuration class is arbitrary. In addition, a test class can contain more than one static inner configuration class if desired.

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from the
// static inner Config class
@ContextConfiguration
public class OrderServiceTest {

    @Configuration
    static class Config {

        // this bean will be injected into the OrderServiceTest class
        @Bean
        public OrderService orderService() {
            OrderService orderService = new OrderServiceImpl();
            // set properties, etc.
            return orderService;
        }
    }

    @Autowired
    private OrderService orderService;

    @Test
    public void testOrderService() {
        // test the orderService
    }

}
Mixing XML, Groovy scripts, and annotated classes

It may sometimes be desirable to mix XML configuration files, Groovy scripts, and annotated classes (i.e., typically @Configuration classes) to configure an ApplicationContext for your tests. For example, if you use XML configuration in production, you may decide that you want to use @Configuration classes to configure specific Spring-managed components for your tests, or vice versa.

Furthermore, some third-party frameworks (like Spring Boot) provide first-class support for loading an ApplicationContext from different types of resources simultaneously (e.g., XML configuration files, Groovy scripts, and @Configuration classes). The Spring Framework historically has not supported this for standard deployments. Consequently, most of the SmartContextLoader implementations that the Spring Framework delivers in the spring-test module support only one resource type per test context; however, this does not mean that you cannot use both. One exception to the general rule is that the GenericGroovyXmlContextLoader and GenericGroovyXmlWebContextLoader support both XML configuration files and Groovy scripts simultaneously. Furthermore, third-party frameworks may choose to support the declaration of both locations and classes via @ContextConfiguration, and with the standard testing support in the TestContext framework, you have the following options.

If you want to use resource locations (e.g., XML or Groovy) and @Configuration classes to configure your tests, you will have to pick one as the entry point, and that one will have to include or import the other. For example, in XML or Groovy scripts you can include @Configuration classes via component scanning or define them as normal Spring beans; whereas, in a @Configuration class you can use @ImportResource to import XML configuration files. Note that this behavior is semantically equivalent to how you configure your application in production: in production configuration you will define either a set of XML or Groovy resource locations or a set of @Configuration classes that your production ApplicationContext will be loaded from, but you still have the freedom to include or import the other type of configuration.

Context configuration with context initializers

To configure an ApplicationContext for your tests using context initializers, annotate your test class with @ContextConfiguration and configure the initializers attribute with an array that contains references to classes that implement ApplicationContextInitializer. The declared context initializers will then be used to initialize the ConfigurableApplicationContext that is loaded for your tests. Note that the concrete ConfigurableApplicationContext type supported by each declared initializer must be compatible with the type of ApplicationContext created by the SmartContextLoader in use (i.e., typically a GenericApplicationContext). Furthermore, the order in which the initializers are invoked depends on whether they implement Spring’s Ordered interface, are annotated with Spring’s @Order or the standard @Priority annotation.

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from TestConfig
// and initialized by TestAppCtxInitializer
@ContextConfiguration(
    classes = TestConfig.class,
    initializers = TestAppCtxInitializer.class)
public class MyTest {
    // class body...
}

It is also possible to omit the declaration of XML configuration files or annotated classes in @ContextConfiguration entirely and instead declare only ApplicationContextInitializer classes which are then responsible for registering beans in the context — for example, by programmatically loading bean definitions from XML files or configuration classes.

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be initialized by EntireAppInitializer
// which presumably registers beans in the context
@ContextConfiguration(initializers = EntireAppInitializer.class)
public class MyTest {
    // class body...
}
Context configuration inheritance

@ContextConfiguration supports boolean inheritLocations and inheritInitializers attributes that denote whether resource locations or annotated classes and context initializers declared by superclasses should be inherited. The default value for both flags is true. This means that a test class inherits the resource locations or annotated classes as well as the context initializers declared by any superclasses. Specifically, the resource locations or annotated classes for a test class are appended to the list of resource locations or annotated classes declared by superclasses. Similarly, the initializers for a given test class will be added to the set of initializers defined by test superclasses. Thus, subclasses have the option of extending the resource locations, annotated classes, or context initializers.

If @ContextConfiguration's inheritLocations or inheritInitializers attribute is set to false, the resource locations or annotated classes and the context initializers, respectively, for the test class shadow and effectively replace the configuration defined by superclasses.

In the following example that uses XML resource locations, the ApplicationContext for ExtendedTest will be loaded from "base-config.xml" and "extended-config.xml", in that order. Beans defined in "extended-config.xml" may therefore override (i.e., replace) those defined in "base-config.xml".

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/base-config.xml"
// in the root of the classpath
@ContextConfiguration("/base-config.xml")
public class BaseTest {
    // class body...
}

// ApplicationContext will be loaded from "/base-config.xml" and
// "/extended-config.xml" in the root of the classpath
@ContextConfiguration("/extended-config.xml")
public class ExtendedTest extends BaseTest {
    // class body...
}

Similarly, in the following example that uses annotated classes, the ApplicationContext for ExtendedTest will be loaded from the BaseConfig and ExtendedConfig classes, in that order. Beans defined in ExtendedConfig may therefore override (i.e., replace) those defined in BaseConfig.

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from BaseConfig
@ContextConfiguration(classes = BaseConfig.class)
public class BaseTest {
    // class body...
}

// ApplicationContext will be loaded from BaseConfig and ExtendedConfig
@ContextConfiguration(classes = ExtendedConfig.class)
public class ExtendedTest extends BaseTest {
    // class body...
}

In the following example that uses context initializers, the ApplicationContext for ExtendedTest will be initialized using BaseInitializer and ExtendedInitializer. Note, however, that the order in which the initializers are invoked depends on whether they implement Spring’s Ordered interface, are annotated with Spring’s @Order or the standard @Priority annotation.

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be initialized by BaseInitializer
@ContextConfiguration(initializers = BaseInitializer.class)
public class BaseTest {
    // class body...
}

// ApplicationContext will be initialized by BaseInitializer
// and ExtendedInitializer
@ContextConfiguration(initializers = ExtendedInitializer.class)
public class ExtendedTest extends BaseTest {
    // class body...
}
Context configuration with environment profiles

Spring 3.1 introduced first-class support in the framework for the notion of environments and profiles (a.k.a., bean definition profiles), and integration tests can be configured to activate particular bean definition profiles for various testing scenarios. This is achieved by annotating a test class with the @ActiveProfiles annotation and supplying a list of profiles that should be activated when loading the ApplicationContext for the test.

[Note]Note

@ActiveProfiles may be used with any implementation of the new SmartContextLoader SPI, but @ActiveProfiles is not supported with implementations of the older ContextLoader SPI.

Let’s take a look at some examples with XML configuration and @Configuration classes.

<!-- app-config.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc"
    xmlns:jee="http://www.springframework.org/schema/jee"
    xsi:schemaLocation="...">

    <bean id="transferService"
            class="com.bank.service.internal.DefaultTransferService">
        <constructor-arg ref="accountRepository"/>
        <constructor-arg ref="feePolicy"/>
    </bean>

    <bean id="accountRepository"
            class="com.bank.repository.internal.JdbcAccountRepository">
        <constructor-arg ref="dataSource"/>
    </bean>

    <bean id="feePolicy"
        class="com.bank.service.internal.ZeroFeePolicy"/>

    <beans profile="dev">
        <jdbc:embedded-database id="dataSource">
            <jdbc:script
                location="classpath:com/bank/config/sql/schema.sql"/>
            <jdbc:script
                location="classpath:com/bank/config/sql/test-data.sql"/>
        </jdbc:embedded-database>
    </beans>

    <beans profile="production">
        <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/>
    </beans>

    <beans profile="default">
        <jdbc:embedded-database id="dataSource">
            <jdbc:script
                location="classpath:com/bank/config/sql/schema.sql"/>
        </jdbc:embedded-database>
    </beans>

</beans>
package com.bank.service;

@RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "classpath:/app-config.xml"
@ContextConfiguration("/app-config.xml")
@ActiveProfiles("dev")
public class TransferServiceTest {

    @Autowired
    private TransferService transferService;

    @Test
    public void testTransferService() {
        // test the transferService
    }
}

When TransferServiceTest is run, its ApplicationContext will be loaded from the app-config.xml configuration file in the root of the classpath. If you inspect app-config.xml you’ll notice that the accountRepository bean has a dependency on a dataSource bean; however, dataSource is not defined as a top-level bean. Instead, dataSource is defined three times: in the production profile, the dev profile, and the default profile.

By annotating TransferServiceTest with @ActiveProfiles("dev") we instruct the Spring TestContext Framework to load the ApplicationContext with the active profiles set to {"dev"}. As a result, an embedded database will be created and populated with test data, and the accountRepository bean will be wired with a reference to the development DataSource. And that’s likely what we want in an integration test.

It is sometimes useful to assign beans to a default profile. Beans within the default profile are only included when no other profile is specifically activated. This can be used to define fallback beans to be used in the application’s default state. For example, you may explicitly provide a data source for dev and production profiles, but define an in-memory data source as a default when neither of these is active.

The following code listings demonstrate how to implement the same configuration and integration test but using @Configuration classes instead of XML.

@Configuration
@Profile("dev")
public class StandaloneDataConfig {

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript("classpath:com/bank/config/sql/schema.sql")
            .addScript("classpath:com/bank/config/sql/test-data.sql")
            .build();
    }
}
@Configuration
@Profile("production")
public class JndiDataConfig {

    @Bean
    public DataSource dataSource() throws Exception {
        Context ctx = new InitialContext();
        return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource");
    }
}
@Configuration
@Profile("default")
public class DefaultDataConfig {

    @Bean
    public DataSource dataSource() {
        return new EmbeddedDatabaseBuilder()
            .setType(EmbeddedDatabaseType.HSQL)
            .addScript("classpath:com/bank/config/sql/schema.sql")
            .build();
    }
}
@Configuration
public class TransferServiceConfig {

    @Autowired DataSource dataSource;

    @Bean
    public TransferService transferService() {
        return new DefaultTransferService(accountRepository(), feePolicy());
    }

    @Bean
    public AccountRepository accountRepository() {
        return new JdbcAccountRepository(dataSource);
    }

    @Bean
    public FeePolicy feePolicy() {
        return new ZeroFeePolicy();
    }

}
package com.bank.service;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {
        TransferServiceConfig.class,
        StandaloneDataConfig.class,
        JndiDataConfig.class,
        DefaultDataConfig.class})
@ActiveProfiles("dev")
public class TransferServiceTest {

    @Autowired
    private TransferService transferService;

    @Test
    public void testTransferService() {
        // test the transferService
    }
}

In this variation, we have split the XML configuration into four independent @Configuration classes:

  • TransferServiceConfig: acquires a dataSource via dependency injection using @Autowired
  • StandaloneDataConfig: defines a dataSource for an embedded database suitable for developer tests
  • JndiDataConfig: defines a dataSource that is retrieved from JNDI in a production environment
  • DefaultDataConfig: defines a dataSource for a default embedded database in case no profile is active

As with the XML-based configuration example, we still annotate TransferServiceTest with @ActiveProfiles("dev"), but this time we specify all four configuration classes via the @ContextConfiguration annotation. The body of the test class itself remains completely unchanged.

It is often the case that a single set of profiles is used across multiple test classes within a given project. Thus, to avoid duplicate declarations of the @ActiveProfiles annotation it is possible to declare @ActiveProfiles once on a base class, and subclasses will automatically inherit the @ActiveProfiles configuration from the base class. In the following example, the declaration of @ActiveProfiles (as well as other annotations) has been moved to an abstract superclass, AbstractIntegrationTest.

package com.bank.service;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {
        TransferServiceConfig.class,
        StandaloneDataConfig.class,
        JndiDataConfig.class,
        DefaultDataConfig.class})
@ActiveProfiles("dev")
public abstract class AbstractIntegrationTest {
}
package com.bank.service;

// "dev" profile inherited from superclass
public class TransferServiceTest extends AbstractIntegrationTest {

    @Autowired
    private TransferService transferService;

    @Test
    public void testTransferService() {
        // test the transferService
    }
}

@ActiveProfiles also supports an inheritProfiles attribute that can be used to disable the inheritance of active profiles.

package com.bank.service;

// "dev" profile overridden with "production"
@ActiveProfiles(profiles = "production", inheritProfiles = false)
public class ProductionTransferServiceTest extends AbstractIntegrationTest {
    // test body
}

Furthermore, it is sometimes necessary to resolve active profiles for tests programmatically instead of declaratively — for example, based on:

  • the current operating system
  • whether tests are being executed on a continuous integration build server
  • the presence of certain environment variables
  • the presence of custom class-level annotations
  • etc.

To resolve active bean definition profiles programmatically, simply implement a custom ActiveProfilesResolver and register it via the resolver attribute of @ActiveProfiles. The following example demonstrates how to implement and register a custom OperatingSystemActiveProfilesResolver. For further information, refer to the corresponding javadocs.

package com.bank.service;

// "dev" profile overridden programmatically via a custom resolver
@ActiveProfiles(
    resolver = OperatingSystemActiveProfilesResolver.class,
    inheritProfiles = false)
public class TransferServiceTest extends AbstractIntegrationTest {
    // test body
}
package com.bank.service.test;

public class OperatingSystemActiveProfilesResolver implements ActiveProfilesResolver {

    @Override
    String[] resolve(Class<?> testClass) {
        String profile = ...;
        // determine the value of profile based on the operating system
        return new String[] {profile};
    }
}
Context configuration with test property sources

Spring 3.1 introduced first-class support in the framework for the notion of an environment with a hierarchy of property sources, and since Spring 4.1 integration tests can be configured with test-specific property sources. In contrast to the @PropertySource annotation used on @Configuration classes, the @TestPropertySource annotation can be declared on a test class to declare resource locations for test properties files or inlined properties. These test property sources will be added to the Environment's set of PropertySources for the ApplicationContext loaded for the annotated integration test.

[Note]Note

@TestPropertySource may be used with any implementation of the SmartContextLoader SPI, but @TestPropertySource is not supported with implementations of the older ContextLoader SPI.

Implementations of SmartContextLoader gain access to merged test property source values via the getPropertySourceLocations() and getPropertySourceProperties() methods in MergedContextConfiguration.

Declaring test property sources

Test properties files can be configured via the locations or value attribute of @TestPropertySource as shown in the following example.

Both traditional and XML-based properties file formats are supported — for example, "classpath:/com/example/test.properties" or "file:///path/to/file.xml".

Each path will be interpreted as a Spring Resource. A plain path — for example, "test.properties" — will be treated as a classpath resource that is relative to the package in which the test class is defined. A path starting with a slash will be treated as an absolute classpath resource, for example: "/org/example/test.xml". A path which references a URL (e.g., a path prefixed with classpath:, file:, http:, etc.) will be loaded using the specified resource protocol. Resource location wildcards (e.g. **/*.properties) are not permitted: each location must evaluate to exactly one .properties or .xml resource.

@ContextConfiguration
@TestPropertySource("/test.properties")
public class MyIntegrationTests {
    // class body...
}

Inlined properties in the form of key-value pairs can be configured via the properties attribute of @TestPropertySource as shown in the following example. All key-value pairs will be added to the enclosing Environment as a single test PropertySource with the highest precedence.

The supported syntax for key-value pairs is the same as the syntax defined for entries in a Java properties file:

  • "key=value"
  • "key:value"
  • "key value"
@ContextConfiguration
@TestPropertySource(properties = {"timezone = GMT", "port: 4242"})
public class MyIntegrationTests {
    // class body...
}

Default properties file detection

If @TestPropertySource is declared as an empty annotation (i.e., without explicit values for the locations or properties attributes), an attempt will be made to detect a default properties file relative to the class that declared the annotation. For example, if the annotated test class is com.example.MyTest, the corresponding default properties file is "classpath:com/example/MyTest.properties". If the default cannot be detected, an IllegalStateException will be thrown.

Precedence

Test property sources have higher precedence than those loaded from the operating system’s environment or Java system properties as well as property sources added by the application declaratively via @PropertySource or programmatically. Thus, test property sources can be used to selectively override properties defined in system and application property sources. Furthermore, inlined properties have higher precedence than properties loaded from resource locations.

In the following example, the timezone and port properties as well as any properties defined in "/test.properties" will override any properties of the same name that are defined in system and application property sources. Furthermore, if the "/test.properties" file defines entries for the timezone and port properties those will be overridden by the inlined properties declared via the properties attribute.

@ContextConfiguration
@TestPropertySource(
    locations = "/test.properties",
    properties = {"timezone = GMT", "port: 4242"}
)
public class MyIntegrationTests {
    // class body...
}

Inheriting and overriding test property sources

@TestPropertySource supports boolean inheritLocations and inheritProperties attributes that denote whether resource locations for properties files and inlined properties declared by superclasses should be inherited. The default value for both flags is true. This means that a test class inherits the locations and inlined properties declared by any superclasses. Specifically, the locations and inlined properties for a test class are appended to the locations and inlined properties declared by superclasses. Thus, subclasses have the option of extending the locations and inlined properties. Note that properties that appear later will shadow (i.e.., override) properties of the same name that appear earlier. In addition, the aforementioned precedence rules apply for inherited test property sources as well.

If @TestPropertySource's inheritLocations or inheritProperties attribute is set to false, the locations or inlined properties, respectively, for the test class shadow and effectively replace the configuration defined by superclasses.

In the following example, the ApplicationContext for BaseTest will be loaded using only the "base.properties" file as a test property source. In contrast, the ApplicationContext for ExtendedTest will be loaded using the "base.properties" and "extended.properties" files as test property source locations.

@TestPropertySource("base.properties")
@ContextConfiguration
public class BaseTest {
    // ...
}

@TestPropertySource("extended.properties")
@ContextConfiguration
public class ExtendedTest extends BaseTest {
    // ...
}

In the following example, the ApplicationContext for BaseTest will be loaded using only the inlined key1 property. In contrast, the ApplicationContext for ExtendedTest will be loaded using the inlined key1 and key2 properties.

@TestPropertySource(properties = "key1 = value1")
@ContextConfiguration
public class BaseTest {
    // ...
}

@TestPropertySource(properties = "key2 = value2")
@ContextConfiguration
public class ExtendedTest extends BaseTest {
    // ...
}
Loading a WebApplicationContext

Spring 3.2 introduced support for loading a WebApplicationContext in integration tests. To instruct the TestContext framework to load a WebApplicationContext instead of a standard ApplicationContext, simply annotate the respective test class with @WebAppConfiguration.

The presence of @WebAppConfiguration on your test class instructs the TestContext framework (TCF) that a WebApplicationContext (WAC) should be loaded for your integration tests. In the background the TCF makes sure that a MockServletContext is created and supplied to your test’s WAC. By default the base resource path for your MockServletContext will be set to "src/main/webapp". This is interpreted as a path relative to the root of your JVM (i.e., normally the path to your project). If you’re familiar with the directory structure of a web application in a Maven project, you’ll know that "src/main/webapp" is the default location for the root of your WAR. If you need to override this default, simply provide an alternate path to the @WebAppConfiguration annotation (e.g., @WebAppConfiguration("src/test/webapp")). If you wish to reference a base resource path from the classpath instead of the file system, just use Spring’s classpath: prefix.

Please note that Spring’s testing support for WebApplicationContexts is on par with its support for standard ApplicationContexts. When testing with a WebApplicationContext you are free to declare either XML configuration files or @Configuration classes via @ContextConfiguration. You are of course also free to use any other test annotations such as @TestExecutionListeners, @TransactionConfiguration, @ActiveProfiles, etc.

The following examples demonstrate some of the various configuration options for loading a WebApplicationContext.

Conventions. 

@RunWith(SpringJUnit4ClassRunner.class)

// defaults to "file:src/main/webapp"
@WebAppConfiguration

// detects "WacTests-context.xml" in same package
// or static nested @Configuration class
@ContextConfiguration

public class WacTests {
    //...
}

The above example demonstrates the TestContext framework’s support for convention over configuration. If you annotate a test class with @WebAppConfiguration without specifying a resource base path, the resource path will effectively default to "file:src/main/webapp". Similarly, if you declare @ContextConfiguration without specifying resource locations, annotated classes, or context initializers, Spring will attempt to detect the presence of your configuration using conventions (i.e., "WacTests-context.xml" in the same package as the WacTests class or static nested @Configuration classes).

Default resource semantics. 

@RunWith(SpringJUnit4ClassRunner.class)

// file system resource
@WebAppConfiguration("webapp")

// classpath resource
@ContextConfiguration("/spring/test-servlet-config.xml")

public class WacTests {
    //...
}

This example demonstrates how to explicitly declare a resource base path with @WebAppConfiguration and an XML resource location with @ContextConfiguration. The important thing to note here is the different semantics for paths with these two annotations. By default, @WebAppConfiguration resource paths are file system based; whereas, @ContextConfiguration resource locations are classpath based.

Explicit resource semantics. 

@RunWith(SpringJUnit4ClassRunner.class)

// classpath resource
@WebAppConfiguration("classpath:test-web-resources")

// file system resource
@ContextConfiguration("file:src/main/webapp/WEB-INF/servlet-config.xml")

public class WacTests {
    //...
}

In this third example, we see that we can override the default resource semantics for both annotations by specifying a Spring resource prefix. Contrast the comments in this example with the previous example.

To provide comprehensive web testing support, Spring 3.2 introduced a ServletTestExecutionListener that is enabled by default. When testing against a WebApplicationContext this TestExecutionListener sets up default thread-local state via Spring Web’s RequestContextHolder before each test method and creates a MockHttpServletRequest, MockHttpServletResponse, and ServletWebRequest based on the base resource path configured via @WebAppConfiguration. ServletTestExecutionListener also ensures that the MockHttpServletResponse and ServletWebRequest can be injected into the test instance, and once the test is complete it cleans up thread-local state.

Once you have a WebApplicationContext loaded for your test you might find that you need to interact with the web mocks — for example, to set up your test fixture or to perform assertions after invoking your web component. The following example demonstrates which mocks can be autowired into your test instance. Note that the WebApplicationContext and MockServletContext are both cached across the test suite; whereas, the other mocks are managed per test method by the ServletTestExecutionListener.

Injecting mocks. 

@WebAppConfiguration
@ContextConfiguration
public class WacTests {

    @Autowired
    WebApplicationContext wac; // cached

    @Autowired
    MockServletContext servletContext; // cached

    @Autowired
    MockHttpSession session;

    @Autowired
    MockHttpServletRequest request;

    @Autowired
    MockHttpServletResponse response;

    @Autowired
    ServletWebRequest webRequest;

    //...
}

Context caching

Once the TestContext framework loads an ApplicationContext (or WebApplicationContext) for a test, that context will be cached and reused for all subsequent tests that declare the same unique context configuration within the same test suite. To understand how caching works, it is important to understand what is meant by unique and test suite.

An ApplicationContext can be uniquely identified by the combination of configuration parameters that are used to load it. Consequently, the unique combination of configuration parameters are used to generate a key under which the context is cached. The TestContext framework uses the following configuration parameters to build the context cache key:

  • locations (from @ContextConfiguration)
  • classes (from @ContextConfiguration)
  • contextInitializerClasses (from @ContextConfiguration)
  • contextLoader (from @ContextConfiguration)
  • parent (from @ContextHierarchy)
  • activeProfiles (from @ActiveProfiles)
  • propertySourceLocations (from @TestPropertySource)
  • propertySourceProperties (from @TestPropertySource)
  • resourceBasePath (from @WebAppConfiguration)

For example, if TestClassA specifies {"app-config.xml", "test-config.xml"} for the