Table of Contents
Introduction
Here are some simple examples to get you going. All examples
together with ready to execute tests are to be found in the
source distribution under
If you are using
CachingThis advice implements a simple caching service. It caches the results from the method invocations that are picked out by the pointcuts mapped to this advice. Note: The caching example has been rewritten and is now a bit more complex than necessary. The background to the change is that the current implementation is a solution to Cedric Beusts AOP challange . The simplified version is shown here for improved readability and understanding.
To run the example type:
public class CachingAdvice extends AroundAdvice { private Map m_cache = new StaticBucketMap(1000); public CachingAdvice() { super(); } public Object execute(final JoinPoint joinPoint) throws Throwable { final Long hash = new Long(calculateHash((MethodJoinPoint)joinPoint)); final Object cachedResult = m_cache.get(hash); // if we have a cached result; return the cache if (cachedResult != null) return cachedResult; // else, proceed with the method invocation and store the result in the cache final Object result = joinPoint.proceed(); m_cache.put(hash, result); return result; } private long calculateHash(final MethodJoinPoint joinPoint) { int result = 17; result = 37 * result + joinPoint.getMethodName().hashCode(); Object[] parameters = joinPoint.getParameters(); for (int i = 0, j = parameters.length; i < j; i++) { result = 37 * result + parameters[i].hashCode(); } return result; } } Asynchronous callsThis advice makes it possible to achive asynchronous method invocations. All the methods that are picked out by the pointcuts mapped to this advice are being executed in it's own thread. Uses a thread pool.
To run the example type:
public class AsynchronousAdvice extends AroundAdvice { private PooledExecutor m_threadPool = ... // initalize the thread pool public AsynchronousAdvice() { super(); } public Object execute(final JoinPoint joinPoint) throws Throwable { m_threadPool.execute( new Runnable() { public void run() { try { // invoke the intercepted method joinPoint.proceedInNewThread(); // using proceedInNewThread } catch (Throwable e) { throw new WrappedRuntimeException(e); } } } ); return null; } } SynchronizationThis advice implements method synchronization. It synchronizes access to the methods that are picked out by the pointcuts mapped to this advice.
To run the example type:
public class SynchronizationAdvice extends AroundAdvice { private Mutex m_mutex = new Mutex(); // if a counting semaphore is needed use: // private Semaphore m_mutex = new Semaphore(nrThreadsAllowed); public SynchronizationAdvice() { super(); } public Object execute(final JoinPoint joinPoint) throws Throwable { m_mutex.acquire(); Object result = joinPoint.proceed(); m_mutex.release(); return result; } } Logging + runtime attributes + parameterized advices + join point controllerThis advice implements a simple logging service. It logs the entry and exit of the methods that are picked out by the pointcuts mapped to this advice. In this simple example I am only using a small subset of all the metadata available from the join point. This example is defined using runtime attributes .
To run the example type:
Here is the
/** * @aspectwerkz.advice-def name=log * deployment-model=perJVM * attribute=log * @aspectwerkz.advice-param advice-ref=log * name=param * value=value */ public class LoggingAdvice extends AroundAdvice { private int m_level = 0; public LoggingAdvice() { super(); } public Object execute(final JoinPoint joinPoint) throws Throwable { String parameter = getParameter("param")); // get the parameter defined in the definition MethodJoinPoint jp = (MethodJoinPoint)joinPoint; indent(); System.out.println("--> " + jp.getTargetClass().getName() + "::" + jp.getMethodName()); m_level++; final Object result = joinPoint.proceed(); m_level--; indent(); System.out.println("<-- " + jp.getTargetClass().getName() + "::" + jp.getMethodName()); return result; } private void indent() { for (int i = 0; i < m_level; i++) { System.out.print(" "); } } }
This is the code for the target class that wants to be logged. As we can see
here we have defined
runtime attributes
at each method that we want to be logged. This is done by using the
For one of the methods we have also added a
public class Target { /** * @aspectwerkz.joinpoint.controller examples.logging.DummyJoinPointController * @aspectwerkz.advice.method log * @aspectwerkz.advice.method log */ public static void toLog1() { new Target().toLog2("parameter"); } /** * @aspectwerkz.advice.method log */ private void toLog2(java.lang.String arg) { new Target().toLog3(); } /** * @aspectwerkz.advice.method log */ private String toLog3() { return "result"; } /** * @aspectwerkz.advice.method log */ public static void main(String[] args) { Target.toLog1(); } } Introductions and MixinsThis example shows both how an Mixin/Introduction is implemented.
To run the example type:
Note: if you add more than one
public interface Mixin { String sayHello(); } public class MixinImpl implements Mixin { public String sayHello() { return "Hello World!"; } }
Second you have to define your
Now you will be able to invoke your
public class Target { ... System.out.println("The mixin says: " + ((Mixin)this).sayHello()); ... } Caller side pointcutsAs a part of the caching example I am also demonstrating how to implement caller pointcuts. Which means that the method is advised on the caller side and not on the callee side. I.e. method invocation and not method execution.
To advise on the caller side your
public class InvocationCounterAdvice extends PreAdvice { public InvocationCounterAdvice() { super(); } public void execute(final JoinPoint joinPoint) throws Throwable { CallerSideJoinPoint jp = (CallerSideJoinPoint)joinPoint; CacheStatistics.addMethodInvocation( jp.getMethodName(), jp.getParameterTypes()); } }
This
<aspect ...> <pointcut-def name="caller" type="callerSide" pattern="examples.caching.*->int examples.caching.Pi.getPiDecimal(int)"/> </aspect>
The
What happens now is that the
Control flow (cflow) pointcuts + runtime attributesThis example shows how control flow (cflow) pointcuts are implemented. This example is defined using runtime attributes .
To run the example type:
In this example we have two methods
First we define a
Second we define a normal method advice for the
public class Target { /** * @aspectwerkz.cflow cflowtest */ public void step1() { step2(); // step2 is called in the control flow of step1 } /** * @aspectwerkz.advice.method my_advice cflow=cflowtest */ public void step2() { } ... } An equivalent XML definition of the above would look like this:
<aspect name="CFlowExample"> <pointcut-def name="step1" type="cflow" pattern="* Target.step1()"/> <pointcut-def name="step2" type="method" pattern="* Target.step2()"/> <advice cflow="step1" pointcut="step2"> <advice-ref name="my_advice"/> </advice> </aspect> XML definition file for the examplesHere is the XML definition file for the advice examples above: <!DOCTYPE aspectwerkz PUBLIC "-//AspectWerkz//DTD 0.8.1//EN" "http://aspectwerkz.codehaus.org/dtd/aspectwerkz_0_8_1.dtd"> <aspectwerkz> <!-- ============================================= --> <!-- Introductions --> <!-- ============================================= --> <introduction-def name="mixin" interface="examples.introduction.Mixin" implementation="examples.introduction.MixinImpl" deployment-model="perJVM"/> <!-- ============================================= --> <!-- Advices --> <!-- ============================================= --> <advice-def name="cache" advice="examples.caching.CachingAdvice" deployment-model="perJVM"/> <advice-def name="invocationCounter" advice="examples.caching.InvocationCounterAdvice" deployment-model="perJVM"/> <advice-def name="asynchronous" advice="examples.asynchronous.AsynchronousAdvice" deployment-model="perJVM"/> <advice-def name="synchronize" advice="examples.synchronization.SynchronizationAdvice" deployment-model="perJVM"/> <!-- ============================================= --> <!-- Abstract aspects --> <!-- ============================================= --> <abstract-aspect name="AbstractSynchronization"> <advice pointcut="synchronizedCalls"> <advice-ref name="synchronize"/> </advice> </abstract-aspect> <!-- ============================================= --> <!-- Concrete aspects --> <!-- ============================================= --> <aspect name="Caching"> <pointcut-def name="callee" type="method" pattern="int examples.caching.Pi.getPiDecimal(int)"/> <pointcut-def name="caller" type="callerSide" pattern="examples.caching.*->int examples.caching.Pi.getPiDecimal(int)"/> <advice pointcut="callee"> <advice-ref name="cache"/> </advice> <advice pointcut="caller"> <advice-ref name="invocationCounter"/> </advice> </aspect> <aspect name="Asynchronous"> <pointcut-def name="asynchronousCalls" type="method" pattern="* examples.asynchronous.Target.toRunAsynchronously()"/> <advice pointcut="asynchronousCalls"> <advice-ref name="asynchronous"/> </advice> </aspect> <aspect name="Synchronization" extends="AbstractSynchronization"> <pointcut-def name="synchronizedCalls" type="method" pattern="* examples.synchronization.Target.toSynchronize()"/> </aspect> <aspect name="Introduction"> <introduction class="examples.introduction.Target"> <introduction-ref name="mixin"/> </introduction> </aspect> </aspectwerkz> Field interception - Transparent persistence of POJOs
In the
Read more about it on my weblog .
Run the example with:
|