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.
我们先看看Spring AOP框架是什么-一个使用纯java实现的,基于代理的框架。可以在任何应用的服务端使用,并且所需要用到的所有类都包含在Spring的发布版本中。
虽然许多用户认为SpringAop很大程度上只是一个具备大量EJB功能的强大的中间件的替代品,但是Spring Aop可以被使用在任何环境中。你可以在一个web容器中,一个使用EJB外观包装的EJB容器,或者在一个丰富的客户端应用中-甚至在applet中使用Spring Aop。
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.
类似大多数的基于代理的AOP实现,Spring Aop也是围绕拦截器链的概念来构建的。函数调用理论上还是被直接发送到目标对象。在Aop的理论中,目标对象包含连接点。拦截链中的每一个拦截器都提供Around Advice能力,也就是可以在方法调用前后执行额外的行为,或者直接导致整个调用短路返回自己选择的值。每一个拦截器都控制着针对目标对象的拦截行为是否继续沿着拦截链进行下去以及应该返回什么值。因此,一个拦截器是有可能“chain”参数或返回值并且在针对目标对象的方法执行前或者后插入自定义的行为。
The target object is said to be advised by the AOP framework by the addition of crosscutting behavior.
目标对象被AOP框架通过额外的切面行为所影响的过程称为 " be advised".
We'll look at the org.aopalliance.intercept.MethodInterceptor interface in detail later in this chapter.
本节我们将详细探讨org.aopalliance.intercept.MethodInterceptor interface 。
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:
-
There is no need to perform a special compilation step or instrument the class loader at runtime. Thus the build and deployment process is that of a plain Java application.
-
It's possible to proxy any object, regardless of what language it is implemented in. Thus you can use Spring's support for scripting languages to implement any managed object in any language, yet still apply the full power of Spring AOP to your scripted objects.
-
It enables the use of different advice for multiple instances of the same class, even in the same class loader. This is difficult or impossible with byte code modification approaches, but is sometimes very useful. For example, imagine that an application uses two DataSources of the same class, and we want to apply different exception handling policies to each.
-
It is easy to understand in terms of the Proxy and Decorator design patterns.
-
It does not affect the target object. The target object itself will behave the same way; it has not been altered.
-
It's possible to create a proxy programmatically, in class library style.
The negative consequences are that:
-
Spring AOP is limited to method interception. While Spring's API design, like the AOP Alliance APIs it uses, would allow for other types of join point to be advised, Spring AOP is likely to remain focused around delivering its core value proposition well. For example, it is not possible to advise field access or object creation.
-
It's possible only to proxy explicitly. Objects will not automatically be proxied when created by the new operator; proxies must be created programmatically or obtained from a Spring context through Dependency Injection or explicit lookup. This is the most significant of the limitations in practice. However, as Dependency Injection provides such compelling advantages in general, your enthusiasm for the new operator is likely to wane significantly when working with an IoC container such as Spring, PicoContainer, or HiveMind.
-
Targets are not aware of being proxied. This is usually a good thing, but it does mean that if a target object calls a method on itself, the call will not be advised. Similarly, if the target passes a collaborator a reference to itself using this, calls on that reference will not be advised. We'll discuss how to address this issue when required later in this chapter.
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.
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.
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:
-
All setter methods.
-
All methods in a particular package.
-
All methods returning void.
-
All method calls with one argument, where that argument is passed a null value. This last is an example of a pointcut that identifies methods in a certain context. Whether or not this pointcut is satisfied can't be known until runtime.
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.
-
GETTERS is a constant Pointcut object matching any getter method in any class.
-
SETTERS is a constant Pointcut object matching any setter method in any class. 127
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:
-
patterns: Array of regular expressions for methods that the pointcut will match
-
pattern: Convenient String property when you have just a single pattern and don't need an array
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 id="settersAndAbsquatulatePointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut"> <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" class="org.springframework.aop.support.DefaultPointcutAdvisor"> <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 id="settersAndAbsquatulateAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor"> <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:
-
Any object created by the IoC container can easily be advised.
-
All AOP framework objects, such as pointcuts and advices, can be configured using Spring IoC.
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.
It's important to understand the function of each class in this diagram:
-
ProxyConfig is the base class for all objects than can create AOP proxies.
-
AdvisedSupport holds configuration for objects with a single TargetSource and set of interfaces.
-
ProxyFactoryBean is used to define proxies in XML or other metadata configuration. As its name indicates, it is a FactoryBean, as discussed in Chapter 3 on Spring's IoC container.
-
ProxyFactory is used to create proxies programmatically, without an IoC container.
-
AbstractAutoProxyCreator and subclasses handle "autoproxying," discussed later. They inherit basic configuration from ProxyConfig, but do not extend from AdvisedSupport, as TargetSource, interfaces, and other AdvisedSupport configuration parameters are relevant to a single proxy type, rather than generic proxy creation.
Important
A quick summary: ProxyConfig defines configuration relating to the creation of proxies in general, such as whether to proxy the target class.
AdvisedSupport extends ProxyConfig to define configuration relating to the creation of one or more instances of the same type of proxy. For example, AdvisedSupport defines interfaces to be proxied.
Thus "autoproxy creators" or other objects that can create many proxies of different types extend ProxyConfig, not AdvisedSupport.
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:
-
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.
-
Define a ProxyFactoryBean bean definition with the public name you want your proxy to have. The most important properties to set here are:
-
proxyInterfaces
-
interceptorNames
-
target
-
The following example shows the use of ProxyFactoryBean with an Advisor and an Advice (an interceptor):
<bean id="myAdvisor" class="com.mycompany.MyAdvisor"> <property name="someProperty"><value>Custom string property value</value></property> </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</value></property> <!-- Use inner bean, not local reference to target --> <property name="target"> <bean class="com.mycompany.PersonImpl"> <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 id="personTarget" class="com.mycompany.PersonImpl"> ... </bean> ... <bean id="person" class="org.springframework.aop.framework.ProxyFactoryBean"> <!--Other configuration omitted --> ...
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 id="proxyTemplate" class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true"> <property name="interceptorNames"> <list> <value>myAdvisor</value> <value>debugInterceptor</value> </list> </property> </bean> <bean id="person" parent="proxyTemplate"> <property name="proxyInterfaces"><value>com.mycompany.Person</value></property> <!-- Use inner bean, not local reference to target --> <property name="target"> <bean class="com.mycompany.PersonImpl"> <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: This wraps a number of raw bean definitions in an AOP proxy with the same config, applying AOP advice.
-
DefaultAdvisorAutoProxyCreator: This causes bean definitions to be proxied regardless of their bean name. Proxying will add any advisors whose pointcuts can match any method on the target bean instance.
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 properties inherited from ProxyConfig, discussed previously.
-
The beanNames property. This can contain multiple values. It supports both literal bean names for exact matching, and a simple wildcard mechanism, where an * character matches any number of characters.
The following simple example will apply a consistent interceptor chain to beans with the name accountManager, inventoryManager, and inventoryDao:
<bean id="myBeanNameProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <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:
class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/ >
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:
-
ProxyFactoryBean is a dependable way of creating proxies, allowing control over every aspect of the proxy, but using it often results in more verbose configuration. However, this can be offset by using the inheritance mechanism of Spring's IoC container.
-
BeanNameAutoProxyCreator is a good half-way house that can reduce verbosity somewhat without excessive magic. It's ideal for replacing a number of ProxyFactoryBean configurations that are identical with the exception of the target, with a single definition.
-
DefaultAdvisorAutoProxyCreator is the most powerful AOP configuration option. It more closely approaches "true" AOP solutions such as AspectJ, where advice is applied to objects automatically based on pointcuts. But there's also more magic involved, which can be confusing at times. One of the main strengths of advisor-based autoproxy creation is that it can be put in place by developers specializing in the AOP framework, with the rest of the team able subsequently to write POJO bean definitions, yet have their objects benefit from crosscutting code.
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:
-
You might want to add auditing behavior around a particular object on the fly, removing it when the operation needing auditing is complete.
-
You might want to add a set of interceptors to a particular object based on the user identity, rather than configuration known in advance.
-
You might want to make an introduction (to be discussed shortly) in Java code at runtime, rather than in configuration written before the application is running.
-
You might be writing some infrastructure elements that benefit from interception.
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.