Spring AOP

Solves problem of cross cutting concerns, like:

  • logging & tracing
  • transaction management
  • security
  • caching
  • error handling
  • performance metrics instrumentation

Goals of Spring AOP:

  • avoid mixing of unrelated concerns in the same code (‘tangling‘ – e.g. business logic and security code)
  • avoid duplication of same/boilerplate code throughout many locations (‘scattering‘, e.g. transaction management)

Spring AOP only works with Spring Beans – cannot be used for Java Classes not managed by Spring (unlike AspectJ)

Pointcut expression matching syntax:

  • designator(return_type package.classname.methodname(params))

designator: e.g. execute – match when method called

return_type: *=wildcard, void, or specific type

package and classname can use * anywhere in the pattern as a wildcard:

  • package and classname are optional and can be omitted, eg perform(*) would match perform method on any class in any package
  • packageA.*.packageC : one wildcard package name between packageA and packageC
  • packageA..packageC: any number of packages
  • classname+ : + indicates any subclass of this class type, eg execution(* *..SomeRepository+.*(*)) – matches any implementation (+) of SomeRepository in any package (*..), and any method with any parameters

methodname can also use wildcard

params

  • ‘..’ indicates any parameters
  • methodname(int, ..) : indicates one int param followed by any other params

Using Annotations to declare an Aspect

@Aspect
public class LoggerAspect
{
    @Before(execution(* *ServiceImpl.*(*))
    public void logMethodCall()
    {
    ....
    }

}

– this pointcut declares an aspect for any method with any params on any class with name ending *ServiceImpl

Equivalent Bean configuration:

<context:component-scan base-package="example"/>
<aop:aspectj-autoproxy/>

<aop:config>
    <aop:aspect ref="loggerAspect">
        <aop:before pointcut="execution(* *ServiceImpl.*(*)" method="logMethodCall"/>
    </aop:aspect>
</aop:config>

<bean id="loggerAspect" class="example.LoggerAspect"/>

Getting Context on matching join points

  • Use JoinPoint as param on Advice impl method
  • Allows access to matching method signature (eg package, name, params)

Advice Types:

@Before

  • before call is made to matching method

@AfterReturning

  • on return from call to matching method

@AfterThrowing

  • matches if target throws an exception
  • Can rethrow as a new exception, but if you do, wrap the original exception so the original context from the exception is preserved

@Around

  • executes before and after method call
  • allows you to either continue with the about-to-be-called method or skip the call ( proceed() )

Methods that call other public methods that are ‘under advice’ in the same class do not get matched with the pointcut. For example, if Class A has methods a1() and a2(), and if the pointcut pattern matches both a1() and a2(), if a1() calls a2() internally, a1() will get the advice, but a2() will not. (KH TODO: would be a nice example to demonstrate this, and the following part too)

If two methods ‘under advice’ are in different classes, and one calls the other, then both methods will get the advice.