Around, Before and After Advices
This topic has not yet been written. The content below is from the topic description.
Around, Before and After Advices As seen on previous sections, around advices wrap the joinpoint execution. An around advice replaces the joinpoint execution in the base system, and is responsible for forwarding execution to the joinpoint itself, as well as for returning a value to the base system. Around advices can be composed by four parts at most: a before joinpoint execution block, a proceed to joinpoint step, an after joinpoint execution block, and, finally, a return value step. To see an example, consider this PER_VM scoped aspect: public class SynchronizationAspect { public Object aroundAdvice(Invocation invocation) throws Throwable { Object result; // part 1: retrieve lock before joinpoint execution synchronized(this) { System.out.println(">>> Retrieved concurrency lock"); // part 2: proceed to joinpoint execution result = invocation.invokeNext(); // part 3: release lock after joinpoint execution System.out.println(" < < < Releasing concurrency lock"); } // part 4: return result return result; } } SynchronizationAspect synchronizes all intercepted joinpoints (in a concurrent programming application), avoiding that two or more intercepted joinpoints run at the same time. As we can see, SynchronizationAspect.aroundAdvice() is composed of four steps: retrieving a lock before the joinpoint execution, achieved by entering the synchronized block; proceeding to joinpoint execution; releasing the lock after the joinpoint execution, achieved by exiting the synchronized block; and returning the joinpoint result. Notice that this advice does not alter joinpoint execution (the advice does not skip it) nor its return result (the advice could overwrite this value, but returns the joinpoint return value itself instead). Hence, we can say that the relevant part of it is only what is performed before and after the joinpoint (parts 1 and 3). To illustrate the before/after concept, we wish to replace this single around advice by a couple of before/after advices. However, we cannot do that by using the previous example. A synchronized block cannot be splitten into two parts and still achieve the same effect. So, lets first replace this around advice by one that uses a mutex intead of a synchronized block: public class MutexAspect { private Object lock = new Object(); private boolean locked = false; public Object aroundAdvice(Invocation invocation) throws Throwable { Object result; // part 1: retrieve lock before joinpoint execution synchronized(lock) { while (locked) { try { lock.wait(); } catch(InterruptedException e) { Thread.currentThread().interrupt(); return; } } locked = true; System.out.println(">>> Retrieved concurrency lock"); } // part 2: proceed to joinpoint execution result = invocation.invokeNext(); // part 3: release lock after joinpoint execution synchronized(lock) { locked = false; lock.notify(); System.out.println(" < < < Releasing concurrency lock"); } // part 4: return result return result; } } As much as SynchronizedAspect, MutexAspect avoids simultaneous access to the intercepted joinpoint, and is also composed of the four steps (getting a lock, proceeding to joinpoint execution, releasing the lock, and returning a result). Now we can easily split this around advice into two advices: one that retrieves the lock, and another one that releases it. We wish to run the first one before a joinpoint, and the other one, after it. The example that follows is a copy of the previous one, except for that, now, MutexAspect.aroundAdvice() has been splitten into MutexAspect.beforeAdvice() and MutexAspect.afterAdvice(): public class MutexAspect { private Object lock = new Object(); private boolean locked = false; public void beforeAdvice(@JoinPoint Joinpoint joinPoint) { synchronized(lock) { while (locked) { try { lock.wait(); } catch(InterruptedException e) { Thread.currentThread().interrupt(); return; } } locked = true; System.out.println(">>> Retrieved concurrency lock"); } } public void afterAdvice(@JoinPoint Joinpoint joinPoint) { synchronized(lock) { locked = false; lock.notify(); System.out.println(" < < < Releasing concurrency lock"); } } } Notice that, in this version, parts 2 and 4 are gone (proceeding to joinpoint execution and returning its result). This is due to the fact that before and after advices don't wrap a joinpoint, they are just executed before or after it.