Spring AOP provides a simple framework for wiring crosscutting concerns into applicable functionality without intrusion into the source code.

This example will walk through creating an aspect with a method logging advice, and wiring it to a sample service.

The service interface is Greeter, which defines a simple getGreeting() method. The service implementation, DefaultGreeter, simply returns the ubiquitous "Hello World!".

public interface Greeter {
  String getGreeting();
}
public class DefaultGreeter implements Greeter {
  public String getGreeting() {
    return "Hello World!";
  }
}

The crosscutting concern is method logging. This means that for applicable services (Greeter in this case), all method calls are to be logged. The aspect, called MethodLogger, will implement a single around advice to accomplish this.

@Component
@Aspect
public class MethodLogger {

  @Around("execution(* com.earldouglas..*.*(..))")
  public Object timeMethod(ProceedingJoinPoint joinPoint) throws Throwable {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();

    Object retVal = joinPoint.proceed();

    stopWatch.stop();

    StringBuffer logMessageStringBuffer = new StringBuffer();
    logMessageStringBuffer.append(joinPoint.getTarget().getClass().getName());
    logMessageStringBuffer.append(".");
    logMessageStringBuffer.append(joinPoint.getSignature().getName());
    logMessageStringBuffer.append("(");
    logMessageStringBuffer.append(joinPoint.getArgs());
    logMessageStringBuffer.append(")");
    logMessageStringBuffer.append(" execution time: ");
    logMessageStringBuffer.append(stopWatch.getTotalTimeMillis());
    logMessageStringBuffer.append(" ms");

    Logger.getLogger(this.getClass()).info(logMessageStringBuffer.toString());

    return retVal;
  }
}

There are several important things going on here. First, the class is annotated as a @Component. This will let Spring know that this class is eligible for instantiation using the <context:component-scan /> element. Next, the class is annotated as an @Aspect. This is an @AspectJ annotation which simply indicates that this class is an aspect intended to contain advice. Next, the timeMethod() method is annotated with @Around, which contains a pointcut expression. @Around defines this method as an around advice, which runs before and after (or around) a given method. The pointcut execution(* com.earldouglas..*.*(..)) means that any method with any method signature residing in any class within any sub-package of com.earldouglas is to be wired with this advice. Finally the advice itself is implemented. A StopWatch is started, the method under question is executed with joinPoint.proceed(), and a log message is written with information about the method execution.

A simple test case is implemented in MethodLoggerTest, which is wired with a Greeter. The Greeter's getGreeting() method is called, and the test is complete. By monitoring standard out, the expected log messages (including the execution time of getGreeting()) generated by the advice can be seen.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class MethodLoggerTest {

  @Autowired
  private Greeter greeter;
  
  @Test
  public void testMethodLogger() {
    greeter.getGreeting();
  }
}

The context configuration for MethodLoggerTest enables @AspectJ aspects, component-scans for @Components, and instantiates a Greeter.

<beans>
  <aop:aspectj-autoproxy />
  <context:component-scan base-package="com.earldouglas.aoplogging" />
  <bean class="com.earldouglas.greeter.DefaultGreeter" />
</beans>

For more detailed information (of particular importance is the difference in how interfaces are proxied by JDK dynamic proxies vs. how classes are proxied by CGLIB), see the Spring Reference.