Jonas Bonér bio photo

Jonas Bonér

Present.
Entrepreneur.
Hacker.
Public Speaker.
Powder Skier.
Perpetual Learner.
Jazz Fanatic.
Wannabee Musician.

Twitter LinkedIn Github

The AspectWerkz 2 architecture has been designed to be an Extensible Aspect Container, which can deploy and run arbitrary aspects. You can read more about the details in this article.

In this article I will show you how you can make use of this container to run Spring AOP aspects more performant plus utilize the annotation-driven AOP in AspectWerkz along with its more expressive pointcut pattern language.

In this article I am using Spring as an example but everything covered here applies to all frameworks that implements the AOP Alliance interfaces (e.g. dynaop, JoyAop, JAC etc.).

Write a regular Spring advice

First we write a regular spring advice that implements authentication:

    public class AuthenticationAdvice implements MethodBeforeAdvice {

        public void before(Method m, Object[] args, Object target) throws Throwable {
            // try to authenticate the user

            // if not authenticated throw a SecurityException

        }
    }

Define the advice using Java 5 annotations

In this example we will not define this advice using the slightly verbose Spring config file. But make use of Java 5 annotations. In AspectWerkz you have a set of predefined annotations that we can use, f.e. one for each advice type. The advice we have implemented here is a before advice so we will use the @Before annotation when defining the advice:

    public class AuthenticationAdvice implements MethodBeforeAdvice {

        @Before("authenticationPoints")
        public void before(Method m, Object[] args, Object target) {
            // try to authenticate the user

            // if not authenticated throw a SecurityException

        }
    }
Here we bind the advice to the pointcut named "authenticationPoints", this pointcut will pick out all the points where we want authentication to take place. However we do not define this pointcut yet. Since we want to make this aspect reusable, then it is better to just compile it, put it in a jar and then at deployment time resolve this definition by defining the pointcut in the external META-INF/aop.xml file.

We can of course choose to not define the pointcut in an external XML file but directly in the Before annotation like this:

    @Before("call(@RestrictedOperation * *.*(..))")
    public void before(Method m, Object[] args, Object target) {
        ...
    }
if we think that that is beneficial. (Then the META-INF/aop.xml only have to define the aspect class name, see below for details).

Define the pointcut in the external aop.xml file

Now all we need to do put this advice to work is to write the little META-INF/aop.xml file. In this case there are two things that we need to define there:

  • we need to tell the AspectWerkz container that it should deploy this Spring advice as a regular AspectWerkz aspect
  • we need to resolve the definition by defining the "authenticationPoints" pointcut
Example:
    <aspectwerkz>
        <system id="spring-extension-sample">
            <aspect class="my.application.aspects.AuthenticationAdvice">
                <pointcut name="authenticationPoints" expression="call(@RestrictedOperation * *.*(..))" />
            </aspect>
        </system>
    </aspectwerkz>
Here we defined the pointcut to pick out all method calls to a method that is marked with the annotation @RestrictedOperation.

Note that we are using a call pointcut here, which means that this advice will execute on the client side and not the server (something that is not possible with regular spring aop which only supports execution pointcuts). This can be beneficial in many situations, it can f.e. can save us a remove call from the client to the server, or take some load off the server if the client is executing in a separate VM, etc.

Start up the application

The last thing we need to do is to add two VM options:

  • we need to register the Aspect Model implementation for the Spring extension in the AspectWerkz container. This is done like this: -Daspectwerkz.extension.aspectmodels=org.codehaus.aspectwerkz.transform.spring.SpringAspectModel
  • we need to register the AspectWerkz weaver agent: -javaagent:lib/aspectwerkz-jdk5-RC2.jar
You also need to put the aspectwerkz-core-RC2.jar, aspectwerkz-RC2.jar, aw-ext-spring-0.1.jar and aw-ext-aopalliance-0.1.jar plus the regular AspectWerkz dependency jars on the classpath. (You find the aspectwerkz jars in the aspectwerkz distribution and the aw-ext-*.jar jars you need to build yourself (see Resources for details).

The you can start up the application as usual using java ....

We have been thinking of providing a way of defining the spring aspect model on the application level (per META-INF/aop.xml file) and not only on the VM level (using a VM option). If there is interest in this, please get back to us and we will add support for this.

This means that we can start up the application like this:
# set AspectWerkz version and libs dependancies
set VERSION=2.0.RC1
set DEPS=... // AspectWerkz dependancies - see bin/setEnv for the complete list


# all AspectWerkz jar, and dependancies
set AW_PATH=aspectwerkz-core-$VERSION.jar:aspectwerkz-$VERSION.jar:$DEPS

# -javaagent option
# adapth the path to aspectwerkz-core-$VERSION.jar as required
java -javaagent:lib/aspectwerkz-jdk5-$VERSION.jar -cp $AW_PATH:... \
     -Daspectwerkz.extension.aspectmodels=org.codehaus.aspectwerkz.transform.spring.SpringAspectModel \
     ... my.application.Main

What about my Spring bean config file, dependency injection etc?

Good news is that you can still use your regular Spring bean config file and let Spring do its job, with dependency injection, bean configurations etc.

AspectWerkz has a pluggable factory mechanism for the aspect instantiation and life-cycle management. We have written a factory for the Spring framework that allows you to use Spring to configure your aspects/advice just as usual. Read more about that here.

Much better performance

Apart from allowing defining your aspects using Java5 annotations and using the semantics of the AspectWerkz pointcut language and weaver, you will also get much better performance (ranging between 1300 to 50 percent). I won't go into detail on that here but you can read more about it in this article.

Drawbacks

Everything has tradoffs and there are of course some drawbacks in using the AspectWerkz Extensible Aspect Container as the runtime environment for your Spring aspects/advice:
  • You will weave the actual target classes - this is a more intrusive way of doing the weaving, which in some cases perhaps is not beneficial
  • You need a couple of extra VM options when you start up your application.
  • You need one extra XML (very tiny) config file - the META-INF/aop.xml file

Resources

I have not written any specific sample application for this article but if you want you can look at and run the tests in the AspectWerkz distribution. You can download the distribution here. The tests are in ./src/compiler-extensions/spring/src/test directory and you can run them by invoking ant test when standing in the ./src/compiler-extensions/spring directory. However these tests does not use the Java5 annotation syntax but only the XML definition to define the aspects. But you should be able to modify the tests as you like.

The aspectwerkz*.jar jars and the dependency jars are in the ./lib folder in the AspectWerkz distribution, but the aw-ext-*.jar jars you need to build yourself. This is done by stepping into the ./src/compiler-extensions/spring directory and type ant dist then the jar will be put into the ./src/compiler-extensions/spring/lib directory, use same procedure to build the AOP Alliance extension jar.

Enjoy.