Aspect-Oriented Programming – Part 2

Aspect-Oriented Programming (AOP) diagram

Last week I covered the concepts and terminology of aspect-oriented programming. As promised, this week I’ll illustrate the main AOP concepts with some code examples.

How we actually implement AOP programmatically will depend on the framework/container we’re using. There are many implementations, including AspectJ, JBoss AOP and Spring AOP.

For the sake of simplicity, I’ll use AspectJ annotated classes as used by the Spring AOP as the examples. If you use a different implementation, your code may be a little different.

Aspect-Oriented Programming Implementation in Spring

With Spring AOP, we can create aspects either using XML configuration or AspectJ annotations. With XML configuration, Spring’s aop schema is used to configure beans as aspects. With the AspectJ annotation approach, annotations such as @Aspect@Pointcut@Before@After, etc., are used to program aspects.

The easiest way is to implement AOP with normal POJO classes. These will be annotated with the AspectJ @Aspect annotation. The Spring container will create proxied classes behind the scenes at runtime.

Spring AOP isn’t the most complete AOP implementation, but it can easily solve common enterprise problems. Spring AOP currently only intercepts *method* execution join points. If we want to apply advice to fields or constructors, we must use a language like AspectJ. AspectJ is a AOP language which extends Java with new keywords for defining joinpoints, pointcuts, advice and aspects.

Advice Types

Spring AOP includes the following types of advice:

  • Before advice: Advice that runs before a join point. If the before advice doesn’t throw an exception, the target method (join point) will always be called.
  • After returning advice: Advice that runs after a join point completes normally, i.e., without throwing an exception. The after returning advice will not be executed if the target method throws an exception. An after returning advice can access the value returned by the target method, and modify it before it is returned to the calling object.
  • After throwing advice: Advice that runs after the target method (join point) throws an exception. The after throwing advice can access the exception thrown by the method.
  • After advice: Advice that always runs after the target method has been executed no matter whether the join point returns normally or fails by throwing an exception.
  • Around advice: This is the most powerful kind of advice. It is advice that wraps around a join point. It can run code both before and after the join point. It can decide whether to actually call the join point or not. It can read the join point parameters, change them if desired, and even change the return value, or catch, change or throw any exception.

Example POJO Code

Let’s say that we are modelling an office domain with programmers who have specific tasks to tackle and complete. Most programmers feel they work quite well by themselves, but management usually allocates a team leader to a project to encourage and manage the team. We can think of a team leader as an *aspect*, having things to do before, during and after the programmers work on their allocated tasks.

First, let’s create a TeamLeader as a normal POJO class:

package com.office;
import java.io.PrintStream;

public class TeamLeader {

    private PrintStream stream;

    public TeamLeader(PrintStream stream) {
        this.stream = stream;
    }

    public void encourageBeforeStart() {
        stream.println("Ra ra! Work hard!");
    }

    public void praiseAfterCompletion() {
        stream.println("Hip hip hurray, a successful task!");
    }

    public void berateAfterFail() {
        stream.println("That's bad! You must work harder!");
    }
} // end of class 

As can be seen, this is a straight-forward plain Java class, and is does not contain any aspect related code.

Example Aspect Code

To change it into an aspect we mark the class as an @Aspect. Each method containing the advice to be applied will be annotated with the appropriate @Before@After@Around, etc. annotation.

We need to have a *pointcut* that determines which target methods to apply the advice on. A pointcut is a filter expression (predicate) that selects matching join points from all the possible join points. This is done with a *pointcut designator expression*. Pointcut expressions use pointcut designators to apply advice to matching methods. Spring uses the AspectJ pointcut expression language.

The pointcut designator expression can be passed as an attribute value to each advice annotation, but this will lead to repeated code. We can reuse the same pointcut expression across multiple advices by using the @Pointcut annotation.

To do this, we create an empty method in the class and annotate it with the @Pointcut annotation. The empty method must return void. The value attribute of the @Pointcut annotation specifies the pointcut expression. An advice can then refer to the @Pointcut annotated method, which is useful if we want to reuse pointcut expressions between multiple advice methods.

Here’s the TeamLeader re-coded using AspectJ annotations:

package com.office;

import java.io.PrintStream;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;

@Aspect
public class TeamLeader {

    private PrintStream stream;

    public TeamLeader(PrintStream stream) {
        this.stream = stream;
    }

    @Pointcut("execution(* *.tackle(..))")
    public void tackleTask() {}

    @Before("tackleTask()")
    public void encourageBeforeStart() {
        stream.println("Ra ra! Work hard!");
    }

    @AfterReturning("tackleTask()")
    public void praiseAfterCompletion() {
        stream.println("Hip hip hurray, a successful task!");
    }

    @AfterThrowing("tackleTask()") 
    public void berateAfterFail() {
        stream.println("That's bad! You must work harder!");
    }
}  // end of class

At runtime, the Spring container will create a proxied class that will intercept the execution of the tackle() method of the Programmer class, and run the appropriate code of the TeamLeader at the appropriate time:

  • Before the tackle() method is run, the encourageBeforeStart() method will be run.
  • After the tackle() method returns normally without throwing any exceptions, the praiseAfterCompletion() method will be run.
  • If the tackle() method throws any exceptions, the berateAfterFail() method will be run.

Aspect-Oriented Programming in EJB Containers

We don’t have the same AspectJ approach to AOP in EJB. However, EJB implements AOP using the Interceptors 1.2 API (JSR-318). This is another annotation-based approach, with three annotations in the javax.interceptor package:

  • @AroundInvoke (version 1.0) – annotates an interceptor method that will intercept a business method of the target class.
  • @AroundTimeout (version 1.1) – annotates an interceptor method that will intercept a timeout method of the target class.
  • @AroundConstruct (version 1.2) – annotates an interceptor method that will be called when the target class constructor is invoked.

In the next post, we’ll look at the differences between how the Around advice is implemented in Spring AOP and in EJB.

I’m always interested in your opinion, so please leave a comment. Your feedback helps me write tips that help you.

Leave a Comment

Your email address will not be published. Required fields are marked *

Code like a Java Guru!

Thank You

We're Excited!

Thank you for completing the form. We're excited that you have chosen to contact us about training. We will process the information as soon as we can, and we will do our best to contact you within 1 working day. (Please note that our offices are closed over weekends and public holidays.)

Don't Worry

Our privacy policy ensures your data is safe: Incus Data does not sell or otherwise distribute email addresses. We will not divulge your personal information to anyone unless specifically authorised by you.

If you need any further information, please contact us on tel: (27) 12-666-2020 or email info@incusdata.com

How can we help you?

Let us contact you about your training requirements. Just fill in a few details, and we’ll get right back to you.

Your Java tip is on its way!

Check that incusdata.com is an approved sender, so that your Java tips don’t land up in the spam folder.

Our privacy policy means your data is safe. You can unsubscribe from these tips at any time.