Professional Java Development with the Spring Framework

Spring's AOP Framework

Let's begin by looking at Spring's own AOP framework — a proxy-based framework that works in pure Java. You can use it in any application server and all the required classes are included in the Spring distribution. Although many users think of Spring AOP largely as a powerful middleware alternative to much EJB functionality, Spring AOP can be used in any environment. You can use it in a web container, inside an EJB container behind an EJB facade, in a rich client application — even in an applet.

The Interceptor Chain

Like most proxy-based AOP implementations, Spring AOP is based around the concept of an interceptor chain. Invocations are notionally directed toward a target object. In AOP terminology, this object contains the join point. Each interceptor in the chain provides around advice — that is, has the ability to interpose additional behavior before or after the invocation, or short circuit the invocation altogether, returning its own chosen value. Each interceptor controls whether the invocation proceeds down the interceptor chain toward the target object, and what the return value should be. So it's possible for an interceptor to chain the arguments or return value, and interpose custom behavior before or after the method on the target object executes.

The target object is said to be advised by the AOP framework by the addition of crosscutting behavior.

We'll look at the org.aopalliance.intercept.MethodInterceptor interface in detail later in this chapter.

Pros and Cons

The notion of a distinct target object is central to understanding Spring AOP.

This concept is different to that seen in some other AOP solutions, such as AspectJ. In those solutions, the byte codes of either the caller or the callee are modified and the advice becomes part of the compiled code at runtime.

The idea of a separate target object has many consequences, both positive and negative. It's a good tradeoff for the intended usage of Spring AOP to address common problems in enterprise applications, some of which were traditionally addressed in a far less flexible way using EJB.

This separation has the following advantages:

The negative consequences are that:

Advice

Let's now move on to some definitions.

The first essential to AOP is advice.

Important 

Advice specifies what to do at a join point. In the case of Spring, this is the additional behavior that Spring will inject around a method invocation. It is most often defined in a method interceptor, which will be invoked as part of an interceptor chain wrapping the method invocation.

The AOP Alliance

Spring's AOP framework is based on the AOP Alliance API. This is a small set of interfaces specifying the signatures required to implement method interception code that can run in multiple AOP frameworks — most important, the org.aopalliance.intercept.MethodInterceptor interface. The AOP Alliance was founded in early 2003 by Rod Johnson, Jon Tirsen (creator of Nanning Aspects and a pioneer of proxy-based AOP), and Bob Lee (author and creator of the jAdvise and DynAOP AOP frameworks).

The AOP Alliance interfaces do not presently specify pointcuts. However, they do provide the ability to use interceptors such as Spring's org.springframework.transaction.interceptor.TransactionInterceptor in multiple AOP frameworks. This is valuable, as it allows the building of libraries of reusable aspects. Instead of the old EJB model where all services were provided by the container vendor, it's possible to select best-of-breed services for use in any compliant aspect framework — a different way of thinking about assembling exactly the infrastructure required by each application.

Important 

AOP provides a powerful way of modularizing and, hence, componentizing services such as transaction management. As this becomes reality, monolithic containers aiming to provide all services, such as EJB containers, seem quite literally like dinosaurs, unable to compete with smaller, more agile competitors.

Besides Spring, DynAOP and JAC implement the AOP Alliance interfaces. AspectJ also provides support for invoking AOP Alliance method interceptors. While if using AspectJ, you'd probably choose the more powerful AspectJ AOP model in general, it's still valuable to be able to use existing method interceptors in AspectJ code.

Method Interceptors

AOP Alliance method interceptors implement the following interface:

public interface org.aopalliance.intercept.MethodInterceptor extends Interceptor { Object invoke(MethodInvocation invocation) throws Throwable; }

The MethodInvocation argument to the invoke() method exposes the method being invoked, the target joinpoint, 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 might look 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; } }

The proceed() method on the MethodInvocation interface is used to invoke the next interceptor in the chain. If the interceptor invoking proceed() is the last in the chain, the target method on the target object will be invoked by calling proceed(), and control will flow back down the chain as shown in Figure 4-1.

Figure 4-1

If you're familiar with Servlet filters, or any of the many other special-purpose APIs using a similar interception concept, you already understand the key concept here. The only difference is that this is a general-purpose approach that can be used with any POJO, whatever the method signatures involved.

Spring Advice Types

Besides the AOP Alliance MethodInterceptor, Spring provides several advice types of its own. These are implemented under the covers using AOP Alliance MethodInterceptors, but they offer a slightly different programming model.

Around advice such as a MethodInterceptor can be used to achieve anything that other advice types can. However, it's not always best to use the most powerful construct available. Often we want to expose the minimum amount of power to get the job done. Also, thinking of AOP purely in terms of interception is not always the best approach.

Spring's additional advice types are inspired by those offered by AspectJ, which also provides the choice of around advice and more restricted advice types, and which has demonstrated its value.

The UML class diagram shown in Figure 4-2 illustrates the different advice types supported out of the box by Spring. Note that all are descended from the tag interface org.aopalliance.aop.Advice, which is taken as an argument by many Spring AOP framework methods, enabling consistent manipulation of all advice types.

Figure 4-2

Important 

Using a Spring-specific advice type, such as MethodBeforeAdvice or ThrowsAdvice, may be the simplest and most natural way of expressing a particular construct. It also minimizes the potential for errors, as there's no need to call MethodInvocation.proceed().

If you choose to use Spring-specific advice types, you can still easily use the code in another AOP framework supporting the AOP Alliance interfaces by wrapping the Spring- specific advice in the relevant Spring wrapper, such as org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor. To facilitate use outside Spring, these wrapper classes do not depend on any other Spring framework classes.

Let's look at the other advice types offered by Spring.

Before Advice

Before advice, as its name implies, executes before the join point. While Spring offers a generic org.springframework.aop.BeforeAdvice interface that could be used with any kind of join point, the org.springframework.aop.MethodBeforeAdvice subinterface is always used for method interception. You will always implement MethodBeforeAdvice.

The signature of a before advice exposes the target method and arguments. The before() method returns void, meaning that before advice cannot change the return value. However, it can throw any throwable, to break the interceptor chain:

public interface MethodBeforeAdvice extends BeforeAdvice { void before(Method m, Object[] args, Object target) throws Throwable; }

Let's look at a simple implementation that counts method invocations:

public class CountingBeforeAdvice implements MethodBeforeAdvice { private int count; public void before(Method m, Object[] args, Object target) { ++count; } public int getCount() { return count; } }

Before advice is particularly useful for auditing style operations, and security checks.

Important 

Sharp-eyed readers will note that this advice, like the advice in the next few examples, is not entirely threadsafe. Although ints are atomic, and the advice's state cannot become corrupted, the count may not be entirely accurate under heavy load (which may or may not matter). In this case, synchronization would easily solve the problem without excessive impact on throughput. However, it does bring up an important point: Advice instances are most often shared among threads, so we need to consider thread safety issues, exactly as with service objects. Typically — as with service objects — advices are naturally threadsafe, so this is not a problem. (Consider the Spring transaction interceptor, which does not need to hold read-write instance variables, as its behavior depends on per-invocation state such as the method being invoked.)

After Returning Advice

After returning advice is invoked when a method returns successfully, without throwing an exception. As with before advice, the return type is void; after returning advices are not intended to change the return value.

The interface again contains a single method. Again, it's not possible to change the return value — this is reserved to MethodInterceptor around advice:

public interface org.springframework.aop.AfterReturningAdvice extends Advice { void afterReturning(Object returnValue, Method m, Object[] args, Object target) throws Throwable; }

We could implement our count as an after returning advice as follows:

public class CountingAfterReturningAdvice implements AfterReturningAdvice { private int count; public void afterReturning(Object returnValue, Method m, Object[] args, Object target) { ++count; } public int getCount() { return count; } }

Although there might not seem to be much difference in effect on such a simple count from the before advice shown earlier (merely counting invocations after, rather than before, the method invocation), in fact there is: This advice will count only successful method invocations, not those that throw an exception.

Throws Advice

Spring's throws advice differs from other advice types in that it is more strongly typed (in terms of method arguments), yet has a less well-defined interface.

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 methods should be of the following form:

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

Only the last argument is required. Thus each afterThrowing() method must take either one or four arguments, depending on whether the implementation is interested in the method and arguments. Unlike the case of other advice types, where there is a single strongly typed method to implement, a throws advice may implement any number of overloaded afterThrowing() methods to handle different exceptions.

A counting throws advice, reacting to any exception, might look as follows:

public class CountingThrowsAdvice implements ThrowsAdvice { private int count; public void afterThrowing(Exception ex) throws Throwable { ++count; } public int getCount() { return count; } }

The following advice will be invoked if a RemoteException is thrown. It will also react to any subclass of RemoteException being thrown:

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 or a RemoteException is thrown. Unlike the previous examples, this class implements an afterThrowing() method taking all four arguments, so it has access to the invoked method, method arguments, and target object:

public static class ServletThrowsAdviceWithArguments implements ThrowsAdvice { public void afterThrowing(Method m, Object[] args, Object target, ServletException ex) { // Do something with all arguments } public void afterThrowing(RemoteException ex) throws Throwable { // Do something with remote exception } }

Throws advice is perhaps the most useful of the specialized Spring advices. While it is, of course, possible to react to exceptions using interception around advice, throws advice is clearer. And, as our initial example in this chapter showed, it's often important to apply consistent, crosscutting policies in the event of failures.

Other Advice Types

The Spring AOP framework is also extensible to allow the implementation of custom advice types. This is a rarely used advanced feature and beyond the scope of this chapter. If you would like to see an example, look at the org.springframework.aop.SimpleBeforeAdvice class in the Spring test suite, and the org.springframework.aop.SimpleBeforeAdviceAdapter class that extends the AOP framework to support it, without any modification to existing Spring code.

This extensibility allows support for other flavors of AOP such as the concept of typed advice, introduced by Rickard Oberg and originally called abstract schema advice. This kind of advice involves an abstract class that implements those methods whose behavior should be advised, while retaining the ability to proceed through a special method invocation. Typed advice represents a significantly different approach to AOP than other advice types. However, the fact that it can be accommodated within Spring's advice support — without changing the core of Spring AOP — indicates the flexibility of the Spring AOP framework. Typed advice is likely to be supported by Spring out of the box post–Spring 1.2.

Pointcuts

As noted at the beginning of this chapter, the key to AOP is providing a different way of thinking about application structure.

This structural thinking is captured in the form of pointcuts. Pointcuts are predicates determining which joinpoints a piece of advice should apply to. It's more intuitive — although not entirely accurate — to think of a pointcut as a set of joinpoints: for example, a set of methods that might be targeted by an advice.

Important 

Pointcuts identify where advice should apply. The magic of AOP lies more in the specification of where action should be taken (pointcuts) than what action to apply (advice).

Spring Pointcut Concepts

Spring pointcuts are essentially ways of identifying method invocations that fit a certain criteria. Often this means identifying methods; sometimes it means identifying methods in a certain context. A pointcut might select a set of method invocations such as:

As the possibilities are limitless, Spring provides a programmable pointcut model.

The Pointcut Interface and Friends

Spring expresses pointcuts through the org.springframework.aop.Pointcut interface, shown as follows:

public interface Pointcut { ClassFilter getClassFilter(); MethodMatcher getMethodMatcher(); }

You can implement the Pointcut interface yourself, but it's nearly always best to use one of the convenient pointcut implementations Spring provides, which include base classes for implementing custom pointcuts.

The Pointcut interface is broken into two dependent interfaces because class filtering and method matching are occasionally used independently — for example, introduction (discussed later in this chapter) requires only class filtering.

The MethodMatcher is the most important of the two interfaces returned by a Pointcut. As its name suggests, it tests methods (and, optionally, arguments) for matching. We'll discuss this important interface shortly.

The ClassFilter interface is used to limit which target classes the pointcut applies to:

public interface ClassFilter { boolean matches(Class clazz); ClassFilter TRUE = TrueClassFilter.INSTANCE; }

For example, we might want to limit matches to all classes in a particular package, all classes derived from a particular class, or all classes implementing a particular interface. By "target class" we mean the class of the target object, not the interface or class the invoked method is declared on. For example, it will be a class like DefaultAccountManager or AccountManagerImpl, rather than the interface AccountManager.

The canonical instance ClassFilter.TRUE will match all classes. This is commonly used, as custom class matching is rarer than custom method matching.

Note 

The Pointcut interface could be extended to address matching fields and other joinpoints. However, there are no plans to add such support in Spring.

Static and Dynamic Pointcuts

The terms static and dynamic are given varying meanings in AOP usage.

Spring uses static to refer to a pointcut that can be evaluated when a proxy is created. Such a pointcut will be evaluated based on criteria that can't change afterwards, such as the method invoked, any annotations on the method, or the interface the method is invoked on.

In Spring terminology, a dynamic pointcut is one that not only may have static criteria, but also relies on information known only when an invocation is made, such as the argument values or the call stack.

Dynamic pointcuts are slower to evaluate than static pointcuts and allow less potential for optimization. It's always necessary to evaluate them on each invocation to which they might apply, although some dynamic pointcuts can be excluded in advance, if they cannot possibly match particular methods.

In Spring, both static and dynamic pointcuts are captured in a single interface, org.springframework.aop.MethodMatcher:

public interface MethodMatcher { boolean matches(Method m, Class targetClass); boolean isRuntime(); boolean matches(Method m, Class targetClass, Object[] args); }

A dynamic pointcut will return true in the isRuntime() method; a static pointcut false. If the isRuntime() method returns false, the 3-argument dynamic matches() method will never be invoked.

The method argument to the matches() methods will be the declaring method on the class or interface the proxy invokes. Thus if there is an AccountManager interface and the advised instance is of class AccountManagerImpl, the 2-argument matches() method will be invoked with the first argument being the invoked method on AccountManager and the second argument being class AccountManagerImpl.

Pointcuts Shipped with Spring

While it's easy enough to implement any of these interfaces yourself, there's usually no need. Spring provides concrete pointcuts and abstract base classes for your convenience.

Pointcut Constants

If you want to do certain common matching operations, you can use the constants defined in the org.springframework.aop.support.Pointcuts class.

NameMatchMethodPointcut

The simple concrete org.springframework.aop.support.NameMatchMethodPointcut class is useful for programmatic proxy creation, as well as configuration in a Spring factory via Setter Injection. It includes the following methods:

NameMatchMethodPointcut addMethodName(String methodName)   void setMappedName(String methodName) void setMappedNames(String methodName)

For convenience, the addMethodName() method returns this, so you can add multiple method names in one line as follows:

Pointcut pc = new NameMatchMethodPointcut().addMethodName("setAge").addMethodName("setName");

The two JavaBean properties are for use with Setter Injection.

NameMatchMethodPointcut is intended for simple uses. All methods with the given name will be advised in the event of method overloading. This may or may not be what you want, but provides a simple API.

Regular Expression Pointcuts

For more sophisticated out-of-the-box pointcuts, regular expressions provide a good way of selecting methods.

Regular expression pointcuts are ideally suited to configuration via XML or other metadata, and thus fit well into typical usage of Spring.

Both Jakarta ORO and the Java 1.4 regular expression API are supported, so this functionality is available even on Java 1.3. org.springframework.aop.support.Perl5RegexpMethodPointcut uses Jakarta ORO; and org.springframework.aop.support.JdkRegexpMethodPointcut uses Java 1.4 regular expression support. As both these classes share a common base class, usage is identical.

Configuration is done through the following properties:

Matching takes place against the fully qualified method name, such as com.mycompany.mypackage.MyClass.absquatulate. This means that you must remember to consider the package: This method could be matched by the regular expression .*absquatulate, but not by absquatulate, which doesn't match the package prefix.

Note 

If you are not familiar with regular expression syntax, please refer to documentation on regular expression syntax for information about wildcards and other capabilities of Java 1.4 or ORO "Perl" regular expressions.

The following example shows XML configuration of a regular expression pointcut:

<bean > <property name="patterns"> <list> <value>.*get.*</value> <value>.*absquatulate</value> </list> </property> </bean>

ControlFlowPointcut

Another out-of-the-box pointcut is dynamic, rather than static, and concerns the call stack that led to the current invocation.

This is similar to the AspectJ cflow construct, although much less powerful. However, it is powerful enough to address some important requirements: for example, applying a special security check if a business method was invoked from a web GUI, rather than a web services client.

Control flow pointcuts perform significantly better on J2SE 1.4 and above because of the availability of the new StackTraceElement API that avoids the need to parse an exception stack trace String.

You can configure control flow pointcuts programmatically or declaratively (using setter injection). However, programmatic definition, in a custom pointcut or advisor, is most common. The following control flow pointcut will match any method invocation under the scope of a method from MyWebTierObject:

Pointcut pc = new org.springframework.aop.support.ControlFlowPointcut(MyWebTierObject.class)

Note 

Pointcut composition works best programmatically. It's easy to create pointcut instances or pointcut factory methods that can then be used in Spring metadata.

StaticMethodMatcherPointcut Base Class

Most likely when you implement a custom pointcut it will be static. Most likely you won't bother with a custom ClassFilter element. In this case, you are best to extend Spring's convenient StaticMethodMatcherPointcut class, as follows:

public static Pointcut myStaticPointcut = new StaticMethodMatcherPointcut() { public boolean matches(Method m, Class targetClass) { // implement custom check } };

As the example shows, you can then create a pointcut by implementing a single method. This is especially useful if you want to create a pointcut in an anonymous inner class, as shown.

DynamicMethodMatcherPointcut Base Class

This is an analogous base class for use when you want to implement a custom dynamic pointcut, where you need to implement the 3-argument matches() method as well. Again, it's useful when an anonymous inner class is appropriate. Use it as follows:

public static Pointcut myDynamicPointcut = new DynamicMethodMatcherPointcut() { public boolean matches(Method m, Class targetClass) { // implement custom check } public boolean matches(Method m, Class targetClass, Object[] args) { // implement custom check } }

The 2-argument matches() method will be invoked exactly as in the static pointcut example we've just seen. It will be evaluated when the proxy is created, identifying the set of methods (for which it returns true) which might match the dynamic criteria.

The 3-argument matches() method is invoked only on methods that match the 2-argument method, and allows custom argument-based checks.

Operating on Pointcuts

The org.springframework.aop.support.Pointcuts class provides static methods for manipulating pointcuts:

public static Pointcut union(Pointcut a, Pointcut b)     public static Pointcut intersection(Pointcut a, Pointcut b)

The union of two pointcuts is the pointcut matching any method matched by either pointcut. The intersection matches only methods matched by both pointcuts.

This enables convenient pointcut composition. This is normally more convenient in Java than in XML. However, it's easy to create Java classes that will then be configured in XML bean definition files.

Advisors

In order to pull pointcuts and advice together, we need an object that contains both: that is, containing the behavior that should be added (advice) and where that behavior should apply (pointcut).

Spring introduces the concept of an Advisor: an object that includes both advice and a pointcut specifying where that advice should apply. Unlike advice and pointcut, an advisor is not an established AOP concept, but a Spring-specific term.

Important 

The purpose of an Advisor is to allow both advice and pointcuts to be reusable independently.

If an advice is used without a pointcut, a pointcut will be created that will match all method invocations. Spring uses the canonical instance Pointcut.TRUE in this case. Thus it is normally possible to use an advice instead of an advisor if you want the advice to apply to all proxied methods.

Advisor Implementations

Besides the case of introductions (discussed later in this chapter), which don't require a MethodMatcher, Advisors are instances of PointcutAdvisor.

DefaultPointcutAdvisor

org.springframework.aop.support.DefaultPointcutAdvisor is the most commonly used Advisor class. It is a generic Advisor that can contain any pointcut and advice. It can be used in the majority of cases where an Advisor is required; there is seldom any need to implement a custom Advisor. (On the other hand, you will quite often implement custom pointcuts if you make sophisticated use of Spring AOP.)

A DefaultPointcutAdvisor instance can be created programmatically as follows:

Advisor myAdvice = new DefaultPointcutAdvisor(myPointcut, myAdvice);

It can also be configured using Dependency Injection, via either setter or constructor injection. The following illustrates the use of Setter Injection to achieve the same result declaratively:

<bean name ="myAdvisor" > <property name="pointcut"><ref local="myPointcut" /></property> <property name="advice"><ref local="myAdvice" /></property> </bean>

Of course you may choose to user inner bean definitions for pointcut and advice properties. If these objects are not referenced elsewhere in configuration, this can be regarded as best practice.

Regular Expressions, Take 2

Often we want to create an advisor using a regular expression pointcut. Spring provides a concrete advisor for this common case.

<bean >        <property name="advice"><ref local="myAdvice"/></property> <property name="patterns"> <list> <value>.*set.*</value> <value>.*absquatulate</value> </list> </property> </bean>

Configuration properties are the same as defined in AbstractRegexpMethodPointcut, with the addition of a perl5 property, which determines whether to use Jakarta ORO Perl5 regular expressions.

Wrapping

The publicly visible Spring invocation chain consists of advisors. This representation is optimized internally to minimize the need for pointcut evaluation at runtime, but that's not visible to the application developer. Thus any advice you add without specifying an advisor (as an Advisor subclass) will be wrapped in an advisor. This is important to remember. Thus if you want to programmatically query an advice you added, the getAdvisors[] method of the Advised interface (discussed shortly) will return a DefaultPointcutAdvisor that wraps your advice, but matches any method.

Integration with the Spring IoC Container

Spring's AOP framework does not aim to be the most powerful AOP framework. It aims to provide a good solution to common problems faced in J2EE development, and a close integration with Spring's IoC container.

To this end:

This means that all AOP objects are first-class parts of the application. For example, a dynamic pointcut could match methods at runtime depending on the state of other application objects — for example, a security check could be applied based on comparing certain method arguments to a Limit object.

Basic Proxy Configuration

To create a Spring proxy, it's necessary to use a proxy factory, or configure a context to "autoproxy" objects it manages.

All proxy factories are derived from org.springframework.aop.ProxyConfig. This provides common configuration properties that can be set programmatically or by Setter Injection.

When an AOP proxy is created, it holds a reference to the configuration object that created it. A configuration object may create many proxies.

Subclasses of ProxyConfig normally double as proxy factories. While it is possible for a proxy configuration to become divorced from a factory — for example, as a result of serialization and deserialization — normally subclasses of ProxyConfig know how to create proxies.

Note that all configuration parameters discussed in this section will affect all AOP proxies created by a configuration object.

The UML class diagram shown in Figure 4-3 illustrates the hierarchy below ProxyConfig.

Figure 4-3

It's important to understand the function of each class in this diagram:

All configuration objects inherit the behavior shown in the following table from ProxyConfig.

Property

Purpose

Default

Notes

proxyTargetClass

Cause the proxy to extend the target class—making public methods on the class available, as well as methods on all interfaces implemented by the class—rather than implement only the interfaces implemented by the target class, or the subset identified. Setting this property to true forces the use of CGLIB proxies, rather than J2SE dynamic proxies, which can implement interfaces only.

False

Setting this value to true requires CGLIB on the classpath.

We recommend the use of J2SE dynamic proxies rather than CGLIB. It’s simpler, only marginally slower, and avoids problems with final variables and some other quirks of CGLIB.

It’s good practice to program to interfaces, rather than classes, anyway, so using CGLIB this way should seldom be necessary. However, it is sometimes unavoidable when you need to proxy legacy classes.

exposeProxy

Expose the AOPproxy as a thread local on each AOPinvocation.

False

This property defaults to false because the thread local binding has a small performance impact.

optimize

Tells the framework to apply optimizations if possible.

False

Effect depends on the AOPproxy created. As of Spring 1.1, the opti- mize flag doesn’t have a significant effect and shouldn’t normally be used.

frozen

To allow advice to be fixed, preventing changes at runtime.

False

Setting frozen to true may allow for optimization, with a gain in runtime performance in some cases. It may also be appropriate for security: for example, to pre- vent a user from removing a secu- rity interceptor or transaction interceptor. Note that the frozen field does not prevent a user querying for advice and possibly changing the state of any advice in the advice chain; it’s just not possi- ble to change the advice chain, for example by replacing an advice or adding or removing an advice.

opaque

To prevent proxies being cast to Advised, preventing querying or modifying advice.

False

Provides a higher-level of security than the frozen flag. When this property is true, it’s impossible to cast a proxy cre- ated by the configuration to the Advised interface, meaning that advice cannot be queried or changed.

aopProxyFactory

Provides an extension point, allowing for customization of how proxies are created.

Instance of DefaultAop ProxyFactory, which knows how to create J2SE dynamic proxies and CGLIB proxies

Not serialized. There should be no need for user code to modify this property; it allows for extensions to the framework.

AdvisedSupport is the superclass of ProxyFactory and ProxyFactoryBean. It adds the properties shown in the following table, defining a single type of proxy, with a particular set of interfaces and TargetSource.

Name

Type

Purpose

Default

Notes

targetSource

Bean property

Allows the framework to obtain the target object on each invocation

EmptyTarget Source, containing a null target

The TargetSource interface is discussed in detail later. The application developer usually sets a target, rather than a TargetSource.

You might set this property to use a pool- ing or other “dynamic” TargetSource.

target

Writable bean property of type java.lang.Object

Sets the target

No target.

Setting the target Source property is an alternative to setting this property.

This property is not readable, as the target object will be wrapped in a Singleton TargetSource.

interfaces

Bean property with additional config methods

Sets the proxied interface

The default is for the AOP framework to automatically proxy all interfaces implemented by the target, or to use CGLIB to proxy the target class if the target implements no interfaces, and thus J2SE dynamic proxies are not usable.

Configure using setInterfaces (Class[]) property setter or using addInterface (Class).

listeners

Configured via methods

Adds listeners that receive notifications of changes to advice (such as adding or removing advice)

 

Not serialized. Primarily intended for framework use.

advisorChain Factory

Bean property

  

Not for end-user use.

addAdvice/ removeAdvice

Allows advice to be added or removed

  

Most of these configuration methods are inherited from the Advised interface.

addAdvisor/ removeAdvisor

Allows Advisors to be added or removed

  

The addXXXX methods are typically used when constructing a proxy pro- grammatically with ProxyFactoryBean, not when configuring a proxy using XMLor other bean definitions.

ProxyFactoryBean adds the properties shown in the following table.

Property

Purpose

Default

Notes

singleton

Indicate whether there should be a single shared instance of the proxy, or whether a new instance should be created for each getBean() call or distinct object dependency

true

Is the ProxyFactoryBean intended to create a shared instance, or should it create a new instance for each call to its getObject() method? This is a common concept to factory beans. If the singleton prop- erty is true, a single proxy instance will be cached in ProxyFactoryBean.

interceptor Names

Establish interceptor chain

Empty interceptor chain (not valid unless a custom TargetSource is set)

This method can be used to specify the name of Advice or Advisor beans in the current factory.

advisor Adapter Registry

Allow extension of Spring AOPto recognize new advice type

Adefault implementation that understands the Spring advice types beyond the AOPAlliance Method Interceptor: before, after returning, and throws Advice.

Not intended for use by application developers. Allows control over custom advice type conversion.

Using ProxyFactoryBean

ProxyFactoryBean is the lowest-level and most flexible way of creating proxies in a Spring IoC environment. However, it is also the most verbose. Nevertheless, it is important to understand it, as it directly exposes the core concepts of Spring AOP.

Basic Concepts

Let's look at the XML-based configuration most commonly used to configure AOP proxies.

Note 

Note that ProxyFactoryBeans can be defined using any supported Spring configuration format, not just XML.

This requires the following configuration steps:

  1. Define beans for any Advisors you wish to use (possibly including separate Advice and Pointcut bean references), and any Interceptors or other Advices you wish to use that aren't contained in Advisors.

  2. Define a ProxyFactoryBean bean definition with the public name you want your proxy to have. The most important properties to set here are:

    1. proxyInterfaces

    2. interceptorNames

    3. target

The following example shows the use of ProxyFactoryBean with an Advisor and an Advice (an interceptor):

<bean > <property name="someProperty"><value>Custom string property value</value></property> </bean> <bean > </bean> <bean > <property name="proxyInterfaces"><value>com.mycompany.Person</value></property> <!-- Use inner bean, not local reference to target --> <property name="target"> <bean > <property name="name"><value>Tony</value></property> <property name="age"><value>51</value></property> </bean> </property> <property name="interceptorNames"> <list> <value>myAdvisor</value> <value>debugInterceptor</value> </list> </property> </bean>

You should be familiar with most of these properties.

The most important property on ProxyFactoryBean is interceptorNames. This is a list of names of advice or advisors that together build up the interceptor chain. Ordering is important. We need to use a list of bean names here, rather than advice or advisor bean references, as there may be singleton or non- singleton advices.

Note 

The bean names in the interceptorNames properties need not only be interceptors; they can be any advice or advisor. The "interceptor" part of the name is retained largely for backward compatibility.

Note the use of an "inner bean" for the target. We could equally use a <ref> element instead of an inline inner bean definition in the preceding target element. In fact, this usage is common:

<bean > ... </bean> ... <bean > <!--Other configuration omitted -->     <property name="target"><ref local="personTarget"/></property> ...

This usage — with a top-level "target" object — has the disadvantage that there are now two beans of type Person: personTarget and person. We're most likely interested only in person (the AOP proxy): other beans will express a dependency on that using Dependency Injection. If autowiring by type is used to resolve dependencies, having an extra bean of this type will be a problem, as it will be impossible to resolve a dependency of type Person unambiguously. With an inner bean as in the first example, there is a single bean. It's impossible to get access to the unadvised object.

Important 

We recommend using an inner bean to define the target for a ProxyFactoryBean in most cases.

Simplifying Configuration When Using ProxyFactoryBean

Clearly if you have multiple proxies that are set up identically, using multiple, very similar ProxyFactory Bean definitions might become verbose. Worse still, you'd have duplication in your XML configuration files and would need to change multiple elements to make a consistent change such as adding a new advisor.

There are several solutions to this problem. One is to use "autoproxy creators," discussed later, rather than ProxyFactoryBean. But you can also use the bean definition inheritance features of the Spring IoC container to help. This can enable you to capture shared definitions such as interceptor names, proxy TargetClass, or any other proxy configuration flags you may set, once in an abstract base definition, extended by each child definition. The child definition will typically add only a unique name, and the"target" property: the object that is to be proxied, along with any properties that that inner bean definition requires.

The following example, refactoring the "Person" example shown earlier, illustrates this approach and shows best practice for using ProxyFactoryBean consistently across multiple application objects:

<bean abstract="true"> <property name="interceptorNames"> <list> <value>myAdvisor</value> <value>debugInterceptor</value> </list> </property> </bean> <bean parent="proxyTemplate"> <property name="proxyInterfaces"><value>com.mycompany.Person</value></property> <!-- Use inner bean, not local reference to target --> <property name="target"> <bean > <property name="name"><value>Tony</value></property> <property name="age"><value>51</value></property> </bean> </property> </bean>

The proxyTemplate bean definition specifies the interceptor chain. This bean definition is abstract and cannot be instantiated. (It is incomplete and does not identify a target.) Any number of child bean definitions can "extend" the proxyTemplate definition, specifying a target. They can optionally add further properties, such as proxy interfaces.

Duplication is error-prone and nearly always worth eliminating. When you have several proxies defined, there can also be a significant saving in the total volume of configuration data.

Important 

Remember the option of dedicated proxies such as TransactionProxyFactoryBean and LocalStatelessSessionProxyFactoryBean. These provide less control over AOP configuration but are simpler to use when you're primarily interested in the aspect they specialize in. You will typically use these, too, with the common parent approach to avoiding code duplication. Look at the transactional bean definitionsin the Spring PetStore example for an illustration of best practice for TransactionProxyFactoryBean usage.

Understanding the Lifecycle of Objects

As with everything you do with Spring IoC, you should consider the lifecycle of AOP proxies and the objects they reference.

Any AOP framework object can be configured via Spring IoC. This means that we can choose whether we want to define the necessary beans with singleton or prototype (non-singleton) scope.

Let's see why this is important and useful.

In simple cases, all objects will be singletons. For example, a transactional proxy might wrap a threadsafe singleton service object by using a singleton instance of a threadsafe TransactionInterceptor.

However, what if an advice needs to hold state on behalf of the target? For example, what if it needs to guard the target based on whether a lock is activated? In this case the advice and/or containing advice can be said to be stateful. Of course in this case, there is a greater overhead to creating a proxy, as a new advice instance needs to be created when the interceptor chain is created. Of course, it will be cached for the life of that proxy.

You can mix and match singleton and non-singleton advices in the same proxy definition. Normally, for efficiency reasons, you will want to minimize the number of stateful advices you have.

If you need stateful advice, you must remember to set the singleton property of ProxyFactoryBean to false. Otherwise the ProxyFactoryBean will assume singleton usage and cache a single proxy instance as an optimization.

There is no point using a prototype ProxyFactoryBean unless your target is also a prototype.

Important 

"Enterprise-level" generic advice, such as transaction interceptors, will typically be singleton scoped.

Pointcuts will typically be singleton-scoped, as they're unlikely to hold per-proxy state.

However, if it's necessary for some aspects to hold state on behalf of an advised target, Spring AOP fully supports this.

Autoproxying

ProxyFactoryBean provides a powerful way of specifying exactly how each proxy is created. The downside is that with one ProxyFactoryBean for each proxy instance, there’s quite a bit of configuration for each bean.

Autoproxying means that depending on some configuration, proxying is applied consistently to a number of objects.

Autoproxying is built on the IoC container's bean post processor mechanism, discussed in Chapter 3. This enables objects implementing the org.springframework.beans.factory.config.BeanPostProcessor interface to wrap or otherwise replace the raw objects resulting from bean definitions. In the case of AOP autoproxying, various "autoproxy creator" implementations use different approaches and configuration data to wrap the raw POJO resulting from a bean definition in an AOP proxy.

Thus an infrastructure team may be responsible for setting up the autoproxy definitions while application developers simply implement POJOs and write regular bean definitions — without any AOP information — as they focus on the application domain.

There are two main types of autoproxy creator:

BeanNameAutoProxyCreator

The simplest form of autoproxy creator, this basically amounts to a more concise take on ProxyFactoryBean. It's always obvious what advice will apply to a given bean.

Configuration is via:

The following simple example will apply a consistent interceptor chain to beans with the name accountManager, inventoryManager, and inventoryDao:

<bean > <property name="beanNames"><value>accountManager,inventory*</value></property> <property name="interceptorNames"> <list> <value>auditAdvisor</value> <value>securityInterceptor</value> </list> </property> </bean>

Both advisors and advices can be used in the interceptorNames list.

DefaultAdvisorAutoProxyCreator

DefaultAdvisorAutoProxyCreator provides a more sophisticated model, driven by Advisors defined in the current context.

Like BeanNameAutoProxyCreator, this is transparent to bean definitions, which don't need to declare any AOP configuration but may end up being proxied.

Important 

A DefaultAdvisorAutoProxyCreator examines all Advisors defined in the current context or ancestor contexts. Any Advisors whose pointcut can match one or more methods on a target object will result in that object being autoproxied.

Thus, different target objects can be given quite different advice chains by an advisor autoproxy creator. This is more magical than bean name autoproxying, but still more powerful, as you don't need to keep a list of bean names up to date.

Note that pointcuts are required for such matching; thus advisors are required, not just advices.

Defining a DefaultAdvisorAutoProxyCreator can be as easy as including a bean definition, without setting any configuration properties:

 <bean / >

The behavior of a DefaultAdvisorAutoProxyCreator will be determined by the advisors it finds in the current context. As with any autoproxy creator, the bean name of the autoproxy creator itself is usually unimportant; an autoproxy creator bean definition is intended to change the effect of other bean definitions, not for access by application code or other framework objects.

Configuration Options

AbstractAutoProxyCreator is the base class for all Spring autoproxy creators and defines a number of common configuration options, shown in the following table. Note that as it extends ProxyConfig, all ProxyConfig parameters are inherited.

Property

Purpose

Default

Notes

Order

Allow control over ordering of this autoproxy creator relative to other Bean PostProcessors in the same context. It is possible, although unusual, to have a chain of BeanPostProcessorsthat each modify the bean instance, and thus make ordering important.

Integer.MAX_ VALUE: means after all post processors with a lower order value, and in no guaranteed order among unordered post processors

Spring uses the org.springframework.core.Ordered interface as an optional interface that can be implemented by many classes to control behavior when Spring manages a group of the same objects.

Interceptor Names

Set the advisors or advices for “common interceptors.”

 

Analogous to the same named property on ProxyFactoryBean. Provides the ability to have a common intercep- tor chain in addition to bean-specific advisors.

applyCommon Interceptors First

Should common interceptors be applied before bean-specific interceptors (advisors matching the given bean)?

true

 

customTarget SourceCreators

List of TargetSource Creators that should be used to try to create a custom TargetSource for this bean instance. The first TargetSource Creator returning non-null from its get TargetSource() method will "win." If the list is empty, or all Target SourceCreators return null, a SingletonTarget Source will be used.

Empty list

Used to customize TargetSource creation, in cases where it isn’t sufficient to wrap the target in a Single tonTargetSource (the default). The TargetSourceCreatorinterface is discussed later in this chapter.

This is an advanced configuration setting that is used to provide instance pooling and other specialized services.

Like ProxyFactoryBean, autoproxy creators work only in a BeanFactory (including its subclass ApplicationContext). They cannot be used without a Spring context. Like all post processors, they run automatically only in an ApplicationContext.

The ordering of advisors matching a particular autoproxied bean is controlled by whether those advisors implemented the Ordered interface.

If no advisors match a bean and no custom target source is created by a TargetSourceCreator, the bean instance is not proxied by the AOP framework. A normal bean reference will result from getBean() calls for that bean, or dependencies expressed on that bean.

Attribute-Driven Autoproxying

An important special case of autoproxying concerns pointcuts that are driven by source-level attributes. This simply involves static pointcuts that are aware of metadata attributes or annotations associated with source elements. Typically we are most interested in method and class level attributes when using Spring AOP.

Important 

Source-level metadata will become increasingly important in Java as J2SE 1.5 reaches the mainstream. Spring already supports attributes.

Attributes are usable out of the box for transaction management, as you see in Chapter 6, "Transaction and Resource Management."

Advanced Autoproxy Creation

The org.springframework.aop.framework.autoproxy.TargetSourceCreator interface is required to help autoproxy creators work with target sources. As you'll see in more detail later, a TargetSource implementation is used to obtain the instance of the "target" object to invoke at the end of the interceptor chain. Usually, there is only one target object, so the TargetSource interface performs a simple function of returning that instance.

An object such as a ProxyFactoryBean works with a single TargetSource. However, autoproxy creators may affect multiple bean definitions with different target objects, and hence must be able to work with multiple TargetSources.

In general, you don't need to concern yourself with this. A SingletonTargetSource will be created by the autoproxy creator as needed. However, if you need more sophisticated TargetSource features such as pooling, you need to be able to control TargetSource creation.

The TargetSourceCreator interface defines the following method:

TargetSource getTargetSource(Object bean, String beanName, BeanFactory factory);

This method should return null if this TargetSourceCreator is not interested in the bean, or a custom TargetSource (such as pooling TargetSource) if it is.

An AbstractAutoProxyCreator maintains a list of TargetSourceCreators. By default, this list is empty. When each bean is analyzed, this method is called on each TargetSourceCreator in turn. The first TargetSourceCreator to return non-null will win. If all TargetSourceCreators return null, or the list of TargetSourceCreators is empty, a SingletonTargetSource will be used to wrap the bean.

The TargetSourceCreator interface is useful for infrastructure requirements. Inside Spring, for example, the TargetSourceCreator mechanism is used to handle pooling and hot swapping. In this case, there must be a distinct TargetSource instance for each autoproxied bean definition, although the autoproxy mechanism provides a single means of configuration. The TargetSourceCreator implementation will use some strategy to determine whether or not a pooling or other special target source should be used for a given bean definition. (The BeanDefinition can be found from the factory if necessary.)

You should understand the mechanism, but are unlikely to need to implement your own TargetSourceCreator in normal application development.

Making a Choice

You may be feeling a little confused right now. Why does Spring provide so many different ways of creating AOP proxies? Why not just standardize on one?

Spring's flexibility is arguably a strength rather than a weakness. It's partly a consequence of the fact that Spring uses a consistent configuration mechanism across the entire framework; anything can be defined using XML bean definitions because the IoC container can manage an arbitrarily fine-grained object. However, Spring also provides higher-level constructs to achieve simplification in some cases, and it's important to understand them.

The following guidelines on proxy creation may be helpful:

Examining and Manipulating Proxy State at Runtime

Spring allows us to examine and even change the advice applying to any AOP proxy at runtime.

It's easy to find whether an object is an AOP proxy. Use the static isAopProxy(Object o) method in the org.springframework.aop.support.AopUtils class.

You can also use the isJdkDynamicProxy() method to find whether an object is a JDK proxy and the isCglibProxy() method in the same class to find whether an object is a CGLIB proxy.

Any AOP proxy can be cast to the org.springframework.aop.framework.Advised interface, which enables advice to be examined and changed. The methods are as follows:

public interface Advised { TargetSource getTargetSource(); void setTargetSource(TargetSource targetSource); boolean getExposeProxy(); boolean getProxyTargetClass(); Advisor[] getAdvisors(); Class[] getProxiedInterfaces(); boolean isInterfaceProxied(Class intf); 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; boolean removeAdvisor(Advisor advisor) throws AopConfigException; void removeAdvisor(int index) throws AopConfigException; boolean removeAdvice(Advice advice) throws AopConfigException; boolean isFrozen(); // Other methods omitted: finding and replacing advices and advisors }

It can be useful to be able to examine proxy state at runtime — particularly when testing. The getAdvisors[] method can be used to find the current Advisors.

The getTargetSource() method is particularly useful, as you can use it to obtain a reference to the target object in the commonest case, where SingletonTargetSource is in use. This means that given a reference to an advised object, it is possible to find the target object it is proxying as well.

It is sometimes useful to manipulate proxy state at runtime, but there's potential danger in doing so, as well as a conceptual question mark. Do we really want to change the structure of an application at runtime?

Note 

Spring's AOP framework is threadsafe in normal operation, but, for performance reasons, does not synchronize to protect against race conditions in adding or removing advice. Thus, if you add an advice while one or more method invocations are underway, the effect might be a concurrent modification exception. As with the core Java Collections, you are responsible for ensuring thread safety in your application code.

Programmatic Proxy Creation

While the integration with Spring's IoC container is usually the main focus of use of Spring AOP, it's easy to create proxies programmatically. This can be very useful, and is used in several places in the Spring framework itself. For example:

It is possible to create AOP proxies programmatically using the org.springframework.aop.framework.ProxyFactory class. The following simple example demonstrates the approach. We need to set the target or TargetSource, add any advisors or advice we choose, and then call the getProxy() method to obtain an AOP proxy, as follows:

PersonImpl personTarget = new PersonImpl(); ProxyFactory pf = new ProxyFactory(); pf.setTarget(personTarget); pf.addInterface(Person.class); pf.addAdvisor(myAdvisor); pf.addAdvice(myAdvice); Person person = (Person) pf.getProxy();

ProxyFactory, like ProxyFactoryBean, is a subclass of org.springframework.aop.framework.AdvisedSupport, so its properties should be familiar. ProxyFactory adds no new properties, merely convenient constructors: one taking a target object (from which interfaces will be deduced if none are specified) and one taking an array of Class specifying the interfaces to proxy. The no-arg constructor, as used in the preceding code, leaves the caller to specify target or TargetSource and interfaces to proxy.

The preceding example could be rewritten as follows using the constructor that takes a target object:

PersonImpl personTarget = new PersonImpl(); ProxyFactory pf = new ProxyFactory(personTarget); pf.addAdvisor(myAdvisor); pf.addAdvice(myAdvice); Person person = (Person) pf.getProxy();

This would have the same effect as the preceding code, assuming that the PersonImpl class implemented only the Person interface. The interfaces to proxy would automatically be found using reflection. If the target object implemented no interface, Spring would try to create a CGLIB proxy.

Note 

It's not possible to automatically proxy an object created using the new operator using Spring AOP. If you need to do this — for example, to advise large numbers of fine-grained objects — consider using AspectJ or AspectWerkz as alternatives to Spring's own AOP framework.

Категории