Technically Feasible

Aspect Oriented Programming with AspectJ and Spring AOP

Likeness of Michael Oldroyd
Michael Oldroyd
⚠️ This content was imported from a previous incarnation of this blog, and may contain formatting errors

Recently I have been experimenting with aspect oriented programming, and the ease with which you can handle cross-cutting concerns. It's an extremely powerful tool, allowing you to insert pointcuts throughout your code, and inject bytecode around code without polluting your source code. AspectJ provides a great deal of flexibility in the methods through which you can instrument your code.

For a live demo, take a look at the example repository over at github. The examples are using the dynamic proxy generation provided by spring. This library provides support for processing the AspectJ annotations as well as an xml-based DSL. Using this method, it is possible to easily collect arbitrary metrics, or inject logging. It can be achieved simply by adding an annotation, or a point-cut around a method.

Spring Aspect Examples #

We will define an aspect which defines two sets of advice. One instruments an execution, which in this case is bound to a specific method. You are able to use interfaces here, or concrete classes. The other applies instrumentation to an annotation. This allows you to attach an annotation to any spring-managed bean, and all calls to the advised methods will be instrumented. The following code demonstrates a spring @Aspect.


@Aspect
@Component
public class ExampleAspect {
    private Logger log;

    public ExampleAspect(Logger log) {
        this.log = log;
    }

    @Around("execution(* uk.co.michaeloldroyd.example.ExampleController.exampleRequest(..))")
    public Object aspectAroundMethod(ProceedingJoinPoint pjp) throws Throwable {
        log.info("Entering {}", pjp.getClass());
        Object result = pjp.proceed();
        log.info("After {}", pjp.getClass());
        return result;
    }

    @Around("@annotation(exampleAnnotation)")
    public Object aspectAroundAnnotation(ProceedingJoinPoint pjp, ExampleAnnotation exampleAnnotation) throws Throwable {
        log.info("Entering {}", pjp.getClass());
        Object result = pjp.proceed();
        log.info("After {}", pjp.getClass());
        return result;
    }
}

Annotation-based Aspect #

Component scanning the controller below, the call to SomeClassWithAspectedMethodCall.aspectedMethodCall() will be instrumented during object construction;


@Controller
class ExampleController {
  SomeClassWithAspectedMethodCall thing;
  public ExampleController(SomeClassWithAspectedMethodCall thing) {
    thing.aspectedMethodCall(); // This would work
  }
}

@Component
class SomeClassWithAspectedMethodCall {
  @ExampleAnnotation
  public boolean aspectedMethodCall() {
    return true;
  }
}

Execution-based Aspect #

Assuming a web endpoint is hit, the call from the servlet to the mapped method below would be instrumented;


@Component
class ExampleController {
  @RequestMapping("/")
  public void exampleRequest(SomeClassWithAspectedMethodCall thing) {
    return; // This would work
  }
}

Internal method calls #

Spring AOP support requires that that aspected instances are spring beans managed by the IoC container. Demonstrated below is a limitation to this approach;


@Component
class SomeComponent {
  public SomeComponent() {
    annotatedMethodCall(); // This won't work
  }
  @ExampleAnnotation
  public boolean annotatedMethodCall() {
    return true;
  }
}

As you can see from the examples, aspect oriented programming can provide clean way to decouple your cross-cutting concerns from implementation. I find this approach to be a great tool in any programmer's toolkit, and look forward to exploring AspectJ further.

Image of me

Michael Oldroyd

Michael is a Software Engineer working in the North West of England.