Sei sulla pagina 1di 10

One of the strengths of the Spring Framework is its robust and flexible aspect oriented

programming infrastructure. In Spring, AOP is a little different than other AOP frameworks in
that it brings with it a consistent AOP infrastructure that can be applied for other AOP technical
solutions. Out of the gate, Spring supports dynamic-proxy-based AOP, and CGLib-based AOP.
Both of these have their limitations, but can honestly be used in a very large majority of cases.
Spring does have integration support with AspectJ as well, however, so don't worry. Thankfully,
the AspectJ integration is not drastically different from the regular AOP, which I think shows
some of the strengths of Spring's AOP infrastructure; even an AOP library as different as AspectJ
can still be integrated.

General Education

Spring's 'built-in' AOP infrastructure is defined by the org.springframework.aop.* packages.


To understand the packages, you have to have at least some idea of the concepts of AOP as
Spring models these concepts *very* closely in implementation, so I'll explain them. Now...
every article I read on AOP seems to just try to confuse me - and the vocabulary around AOP
even makes it worse. I'm going to do my best to describe things as simply as possible, so bear
with me:

• Aspect - Think of this as the general feature you want to apply globally to your
application (logging, performance monitoring, exception handling, transaction
management, etc).
• Advice - A chunk of code that is invoked during program execution, and is a piece of the
logic for implementing your aspect. This is the first important piece of a Spring AOP
aspect implementation! I like to compare advice implementations to the decorator
pattern. While an advice doesn't necessarily wrap an entire object in concept, it has the
same general effect. We'll learn in a bit that how that advice is applied is more
granular/formal than typically defined in the decorator pattern however.
• Joinpoint - A *single* location in the code where an advice should be executed (such as
field access, method invocation , constructor invocation, etc.). Spring's built-in AOP only
supports method invocation currently, so joinpoints aren't particularly important to focus
on at this point.
• Pointcut - A pointcut is a set of many joinpoints where an advice should be executed. So
if, in Spring, a joinpoint is always a method invocation, then a pointcut is just a set of
methods that, when called, should have advices invoked around them. This is the second
important pieces of a Spring AOP aspect implementation!
• Targets/Target Objects - The objects you want to apply an aspect or set of aspects to!
• Introduction - This is the ability to add methods to an object. This is closely tied to, and
is almost analogous to the term 'mixins'. It's really just a way to make an object of type A
also an object of type B. Introduction in Spring is limited to interfaces.

Spring and Advice Objects

I like to start with the concept of advice objects, because they are the easiest to bridge to from a
non-AOP way of thinking, because an advice is really very similar to a decorator (as I mentioned
above). Advice implementations in Spring are simply implementations of the
org.aopalliance.intercept.MethodInterceptor interface. Woah! Wait a minute - that's not
a Spring class! Nope - it turns out that Spring's AOP implementation uses a *standard* AOP API
from the AOP Alliance, which you can read more about here . The MethodInterceptor
interface is actually a child of the org.aopalliance.intercept.Interceptor interface,
which is a child of another interface, org.aopalliance.aop.Advice - Whew!. Remember that
I said Spring AOP only supports method invocation, but that conceptually, an advice could
include field access, constructor invocation and a bunch of other things. That is why Spring's
advice starts at the MethodInterceptor interface, even though there are other interfaces higher
up - because MethodInterceptor is the sub-interface that is designed for method-invocation style
advice and for which Spring has support. The MethodInterceptor interface is really quite
simple:

public interface MethodInterceptor extends Interceptor {


Object invoke(MethodInvocation invocation) throws Throwable;
}

Basically, when you write an advice for intercepting a method, you have to implement one
method - the invoke method, and you are given a MethodInvocation object to work with. The
MethodInvocation object tells us a bunch of stuff about the method that we're intercepting, and
also gives a hook to tell the method to go ahead and run.

Let's jump right in and look at a (very) basic method performance profiling advice:

import org.aopalliance.intercept.*;

public class PerformanceInterceptor implements MethodInterceptor {

public Object invoke(MethodInvocation method) throws Throwable {


long start = System.currentTimeMillis();
try {
Object result = method.proceed();
return result;
}
finally {
long end = System.currentTimeMillis();
long timeMs = end - start;
System.out.println("Method: " + method.toString() + "
took: " + timeMs +"ms.");
}
}
}

Not too complicated really - just capture the time before the method invocation, tell the method
to go ahead and run, then afterward capture the time again, calculate the difference, and print it
out. Incidentally, Spring already has a better implementation of this type of interceptor - the
org.springframework.aop.interceptor.PerformanceMonitorInterceptor - there are
actually quite a few useful concrete interceptor implementations in there - check it out.

Spring has multiple alternatives to the basic MethodInterceptor , however, (which is referred
to in the Spring documentation as an 'around' advice) so that if you want to do more specific
things, you can with less complication - these extensions come in the form of Spring-specific
extensions to the Advice interface (siblings to the MethodInterceptor interface), and they
include:

• org.springframework.aop.MethodBeforeAdvice - Implementations of this interface


have to implement this contract:
• void before(Method method, Object[] args, Object target) throws
Throwable;

You'll notice in this case you aren't given the MethodInvocation object, just the
underlying Method
object - this is because the call to proceed() will be handled by Spring for you; all you
need to do is
do what you need *before* the method is called (as the interface name implies).

• org.springframework.aop.AfterReturningAdvice - This is the pong to the ping of


MethodBeforeAdvice .
This interface's method will be called on the return from the invocation of a method. The
contract looks like this:
• void afterReturning(Object returnValue, Method method, Object[] args,
Object target) throws Throwable;

You'll notice it looks a whole like the before advice, but simply adds the Object's return
value to the
method arguments.

• org.springframework.aop.ThrowsAdvice - This is a strange implementation. Instead of


requiring you
to implement a particular contract, this is simply a 'marker' interface, and expects you to
implement any number
of methods that look like this:
• void afterThrowing([Method], [args], [target], [some type of throwable]
subclass)

Oddly enough, the only mandatory argument is the Throwable sub-type.

Here is a snapshot that generally covers the 'advice' hierarchy:

That's a primer on advice objects. Not too bad so far, right? If you've ever worked with in
reflection in Java, most of this is fairly similar in style.

Spring and Pointcuts


What seperates AOP from object-oriented design patterns such as the decorator pattern, at least
when talking about Spring AOP, is the fact that the *what* is defined seperately from the
*where* (or would it be *whom*?). In other words, the 'advice', which is the code to be invoked,
is disconnected entirely from the particular item it is 'advising' - which, again, in the Spring case
is always a method. In other words, an advice in Spring doesn't have any association, type
binding, dependency, or any other form of direct awareness of the method it is working with.

Remember that the thing that an advice works with is called a JoinPoint . Our join points in
Spring are always methods, and at runtime resolve to org.aopalliance.aop.Method objects
which have made appearances as method arguments to our advices above. To solidify the point,
org.aopalliance.aop.Method extends org.aopalliance.aop.JoinPoint .

The reason I am bringing joinpoints back up is because a Pointcut object is all about defining
all of the joinpoints that an advice should be 'applied to'. In Spring terms, a pointcut defines all of
the methods that our interceptor should intercept. Pointcuts in Spring implement the
org.springframework.aop.Pointcut interface and look something like this:

package org.springframework.aop;

public interface Pointcut {


ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}

The class filter is a special type of object that describes which classes have potential joinpoints
(read methods) on them. The method matcher simply describes which methods for a given class
are considered valid joinpoints for this pointcut. I don't want to spend too much time on the
pointcut interface, however, because chances are - you won't be implementing it.

Static vs. Dynamic Method Matching

Spring makes a distinction between static and dynamic method matching. A static method
matching pointcut (a subclass of the
org.springframework.aop.support.StaticMethodMatcherPointcut class) knows at the
time it proxies a target object what methods it considers joinpoints on that object. A dymamic
method matching pointcut (see below for implementation details), on the other hand must be
consulted at *every* method invocation. This is a useful implementation detail because a static
method matcher, while having less flexibility (you can't check the method invocation
arguments), is, by design, much faster, as the check is only performed once, rather than at every
method invocation. Static Matching pointcuts implementations look something like this:

public class MyBeanPointcut extends StaticMethodMatcherPointcut {


public boolean matches(java.lang.reflect.Method theMethod,
java.lang.Class theClass) {
return (MyBean.class.isAssignableFrom(theClass) &&
theMethod.equals(...));
}
}

In most cases, however, this is irrelevant, because there is a very convenient pair of static method
matchers that cover almost all concerns - the
org.springframework.aop.support.JdkRegexpMethodPointcut and
org.springframework.aop.support.PerlRegexpMethodPointcut classes. You typically
configure these outside of your code (we'll get to configuration in a bit), and don't have to do any
nasty reflection checks as seen above. In addition, there is a simpler variety of text-based
matching called the NameMatchedMethodPointcut - which is similar to the regex
implementations, but only matches exact names.

Dynamic matching pointcut implementations typically look something like this:

public class MyBeanPointcut extends StaticMethodMatcherPointcut {


public boolean matches(java.lang.reflect.Method theMethod,
java.lang.Class theClass, Object[] arguments) {
boolean matches = false;
if(MyBean.class.isAssignableFrom(theClass) &&
theMethod.equals(...)) {
if(arguments[0].equals("Joe Smith")) {
matches = true;
}
}
return matches;
}
}

Due to the nature of dynamic pointcuts, there are no real convenience implementations of this
class. Here is what the pointcut hierarchy generally looks like:

You may have noticed, neither of my pointcut examples made any reference to any advice (e.g.
MethodInterceptor implementation) - remember that I said an advice knows the *what*, not
the *where*? Well, a pointcut is the inverse - it knows the *where*, not the *what*. Therefore,
theoretically, these two components can be intermingled in different configurations and reused.

Tying Pointcuts with Advisors - PointcutAdvisors

I've gone to great lengths above to clarify that pointcuts don't know about advice objects, and
advice objects don't know about pointcuts. Some object somewhere, however, must know about
both if we are going to have any hope of wrapping our beans in aspects. That is where
implementations of PointcutAdvisor come in. Conceptually speaking, a PointcutAdvisor is
nothing more than a pointcut and an advice object combined - hence the name. The most basic
variety of pointcut advisor is the
org.springframework.aop.support.DefaultPointcutAdvisor class. This is for the most
part just a bean that has two references - something akin to this:

public class DefaultPointcutAdvisor {


private Pointcut pointcut;
private Advice advice;

public Pointcut getPointcut() { return pointcut; }


public Advice getAdvice() { return advice; }
public void setPointcut(Pointcut pc) { pointcut = pc; }
public void setAdvice(Advice a) { advice = a; }

Yes, yes, in reality it is more complicated than this - but really that is the bulk of it right there.
Now we are getting to a point where we can define the *what* (the Advice) and the *where* (the
Pointcut) in one discrete location. A basic configuration of this advisor in a spring bean
definition may look something like this:

<!--
A simple name matching pointcut that will consider all methods named
'handleRequestInternal'
as joinpoints
-->
<bean name="controller.handle.pointcut"
class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedName" value="handleRequestInternal"/>
</bean>

<!-- A simple MethodInterceptor style advice object (InterceptorA implements


MethodInterceptor) -->
<bean name="interceptorA" class="com.javalobby.tnt.spring.aop.InterceptorA"
/>
<!-- A simple MethodBeforeAdvice style advice object (BeforeAdviceA
implements MethodBeforeAdvice) -->
<bean name="beforeAdviceA"
class="com.javalobby.tnt.spring.aop.BeforeAdviceA"/>

<!-- A pointcut advisor that combines the controller pointcut with


interceptor A -->
<bean name="pointcut.advisor1"
class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="interceptorA"/>
<property name="pointcut" ref="controller.handle.pointcut"/>
</bean>

<!--
An alternative pointcut advisor that combines the before advice with the
controller pointcut
Showing how reuse of pointcuts and advices is possible
-->
<bean name="pointcut.advisor2"
class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="beforeAdviceA"/>
<property name="pointcut" ref="controller.handle.pointcut"/>
</bean>

Hopefully this gives you some idea of the relationship of these three classes. As you can see,
advice objects and pointcuts can be intermixed freely into varying pointcut advisors.

Let's Simplify Things

Ok, now, throw all of that example out of the window. Why? Well, because in reality while the
above example is much more flexible, it is quite verbose as well. Most times that level of
granularity is unnecessary, as we will soon see. Earlier I glossed over the
org.springframework.aop.support.PointcutAdvisor class hierarchy, and just mentioned
the most basic DefaultPointcutAdvisor . Let's take a closer look at the available class
hierarchy now:
Did you notice how similar the names are to the pointcuts we just learned about? Most of these
classes take the seperation of pointcut and advisor out of the equation, which, while theoretically
reducing some degree of flexibility, typically makes configuration much easier. Here is the same
example above, using the NameMatchMethodPointcut Advisor object (which combines the
PointcutAdvisor API with the NameMatchMethodPointcut class):

<!-- A simple MethodInterceptor style advice object (InterceptorA implements


MethodInterceptor) -->

<bean name="interceptorA" class="com.javalobby.tnt.spring.aop.InterceptorA"


/>
<!-- A simple MethodBeforeAdvice style advice object (BeforeAdviceA
implements MethodBeforeAdvice) -->
<bean name="beforeAdviceA"
class="com.javalobby.tnt.spring.aop.BeforeAdviceA"/>

<!--
Use the NameMatchMethod pointcut advisor to make things a little simpler.
-->
<bean name="pointcut.advisor1"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="interceptorA"/>
<property name="mappedName" value="handleRequestInternal"/>
</bean>

<!--
Use the NameMatchMethod pointcut advisor to make things a little simpler.
-->
<bean name="pointcut.advisor2"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="beforeAdviceA"/>
<property name="mappedName" value="handleRequestInternal"/>
</bean>

As you can see, we got rid of the configuration of one bean entirely. Technically speaking we are
no longer reusing the pointcut, but since pointcut definitions are typically a configuration
concern (as seen above), it doesn't usually matter one way or another to us.

Gluing it All Together

So, we've covered advice objects and pointcut objects - which when you get down to it, are the
core; the center of Spring AOP support. Then we covered pointcut advisors which take advice
objects and pointcut objects and glue them together into one cohesive chunk - the peanut butter
and jelly; the meat and potatoes; the spaghetti and meatballs; the lamb and tunafish. There is a
very important piece of the puzzle missing however: how do we wrap these pointcut-advisor
combos around our objects? After all, that is the whole point of all of this. Enter the
ProxyFactoryBean .

Without getting into too much detail, Spring supports the concept of a FactoryBean , which is a
special type of bean, in that the bean returned is a factory result, rather than just a plain
'newInstance()' call on the class you provided. So, you could have a factory bean implementation
that, based on certain configuration details, factoried different implementations of a certain class.
So, just to solidify my point, in this example:

<bean name="myBean"
class="com.javalobby.tnt.spring.factorybeans.MyFactoryBean"/>

If you ask for myBean from the bean factory, you're *not* going to get an instance of
MyFactoryBean - instead, Spring is going to consult with the MyFactoryBean object, and ask it
to provide the object you want.

Why is all of this important? Well, because this FactoryBean concept is how Spring wraps your
beans - via the some configuration details, and then using some internal tool (dynamic proxies,
CGLib, etc.) to create a proxy for your bean that executes some advice on method calls when the
pointcut says the method is a joinpoint (assuming a pointcut is defined).

Expanding our example above, here is how Spring's proxy factory bean works:

<!-- A simple MethodInterceptor style advice object (InterceptorA implements


MethodInterceptor) -->
<bean name="interceptorA" class="com.javalobby.tnt.spring.aop.InterceptorA"
/>
<!-- A simple MethodBeforeAdvice style advice object (BeforeAdviceA
implements MethodBeforeAdvice) -->
<bean name="beforeAdviceA"
class="com.javalobby.tnt.spring.aop.BeforeAdviceA"/>

<!--
Use the NameMatchMethod pointcut advisor to make things a little simpler.
-->
<bean name="pointcut.advisor1"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="interceptorA"/>
<property name="mappedName" value="handleRequestInternal"/>
</bean>

<!--
Use the NameMatchMethod pointcut advisor to make things a little simpler.
-->
<bean name="pointcut.advisor2"
class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<property name="advice" ref="beforeAdviceA"/>
<property name="mappedName" value="handleRequestInternal"/>
</bean>

<!-- Create our controller bean -->


<bean name="myRawController"
class="com.javalobby.tnt.spring.aop.ExampleController" />

<!-- Create the proxy bean that returns AOP'd varieties of our controller -->
<bean name="myController"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<list>
<value>pointcut.advisor2</value>
<value>pointcut.advisor1</value>
<value>myRawController</value>
</list>
</property>
</bean>

Notice the interceptorNames property? This is how we tell the proxy factory bean what
advisors or advice objects we want to apply to the proxied bean. Order is important in this list -
the order the advisors or advice objects are entered in the list defines the order they will be
invoked when entering and exiting the bean. Note that in this case the *last* entry in the list is
our bean that we want to be proxied. This is just one possible way to define the bean to be
proxied as we'll see in a moment. Also, did you notice that I said advisors or advice objects ?
That is because the proxy factory bean allows for another shortcut; not specifying a pointcut at
all, just an advice. In those cases, an 'every method is a joinpoint' style pointcut will
automatically be applied. So, if we didn't care which methods were advised, we could shorten the
example above like this:

<!-- A simple MethodInterceptor style advice object (InterceptorA implements


MethodInterceptor) -->
<bean name="interceptorA" class="com.javalobby.tnt.spring.aop.InterceptorA"
/>
<!-- A simple MethodBeforeAdvice style advice object (BeforeAdviceA
implements MethodBeforeAdvice) -->
<bean name="beforeAdviceA"
class="com.javalobby.tnt.spring.aop.BeforeAdviceA"/>

<!-- Create our controller bean -->


<bean name="myRawController"
class="com.javalobby.tnt.spring.aop.ExampleController" />

<!-- Create the proxy bean that returns AOP'd varieties of our controller -->
<bean name="myController"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<list>
<value>beforeAdviceA</value>
<value>interceptorA</value>
<value>myRawController</value>
</list>
</property>
</bean>

Now, I mentioned earlier that there is another way to specify the target bean. This can be done
through the targetName and/or target properties on the factory bean:

<!-- Create the proxy bean that returns AOP'd varieties of our controller -->
<bean name="myController"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="myRawController"/>
<property name="interceptorNames">
<list>
<value>beforeAdviceA</value>
<value>interceptorA</value>
</list>
</property>
</bean>
If you don't need direct (non-AOP'd) access to your bean, then it may be better for the simplicity
of the file to just use an anonymous inner bean, rather than declaring the bean seperately to the
proxy:

<!-- Create the proxy bean that returns AOP'd varieties of our controller -->
<bean name="myController"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target"><bean
class="com.javalobby.tnt.aop.ExampleController"/></property>
<property name="interceptorNames">
<list>
<value>beforeAdviceA</value>
<value>interceptorA</value>
</list>
</property>
</bean>

Conclusion for Now

Ok, well, I could keep going on and on and on, but I'd never finish this article, and you'd never
get to read it; and if you *did*, it'd be so long and boring that I might as well put it on the shelf
next to the encyclopedia.

Now, some people who already know about Spring AOP are probably ready to clamor because I
haven't covered these topics (among others I'm sure):

• Introductions/Mixins
• Specialized Proxy Support (such as the TransactionProxyFactoryBean)
• Other corner cases

I didn't cover introductions specifically because they are so uniquely different from other types
of Spring AOP, I thought it would be good to cover the basic, common forms first. As far as the
specialized cases and 'unique tweaks', let's gauge the popularity of the subject, and see where we
get.

I'm looking forward to your feedback, questions, and comments on whether or not you want
more tips on this subject!

Potrebbero piacerti anche