Spring Boot AOP does @AspectJ @Around annotations

Benefiting from Spring AOP support of @AspectJ annotations is easier than you think.

Read Up

If you have decided that you need to use the @AspectJ @Around annotation in your Spring Boot web application, you might find that there is a lot of conflicting information about using AspectJ on the Internet. A quick web search for @AspectJ @Around will return many links to articles, tutorials, and stack overflow questions dating back to 2010, and the information referenced does little to acknowledge how to do this in Spring Boot.

Here are a few references that should take precedence over anything you might read on the web:

You will have no doubt read about aspects and join points and pointcuts, and probably a lot more about AspectJ weaving vs Spring CGLIB Proxies and how to configure one or the other in Spring. It turns out that Aspect Oriented Programming is a very deep subject and that Java and Spring are a great place to make use of these concepts.

For now, I’m just going to show you how to use the @Around annotation from @AspectJ in your Spring Boot web application. It really is quite easy.

A Simple Spring Boot Web Application

Let’s start with the simplest Spring Boot web application I could write:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <description>Demo project for Spring Boot AOP</description>
                <relativePath /> <!-- lookup parent from repository -->


package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
public class ExampleApplication
	public static void main(String[] args)
		SpringApplication.run(ExampleApplication.class, args);


package com.example;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
public class ExampleController
	public boolean test()
		Logger log = LoggerFactory.getLogger(ExampleController.class);
		return (true);

Building and Running the Example Application

This will build and run any Spring Boot application:

	$ mvn clean install spring-boot:run

Though building and running a Spring Boot application using Maven is childsplay, the verbosity of your Spring Boot applications startup logging can be temporarily eliminated like this:

	$ java -jar target/spring-aop-example-0.0.1-SNAPSHOT.jar --logging.level.org=WARN

You can use the java command and add the --logging.level.org=WARN parameter to get rid of the logging output from all the org packages (mostly org.springframework and org.apache).

Once the ExampleApplication is up and running, try hitting the test service:

	$curl localhost:8080/test

Your console may look something like this:

2017-11-10 16:02:39.479  INFO 20271 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2017-11-10 16:02:39.483  INFO 20271 --- [           main] com.example.ExampleApplication           : Started ExampleApplication in 2.158 seconds (JVM running for 5.846)
2017-11-10 16:02:42.253  INFO 20271 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring FrameworkServlet 'dispatcherServlet'
2017-11-10 16:02:42.254  INFO 20271 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization started
2017-11-10 16:02:42.264  INFO 20271 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : FrameworkServlet 'dispatcherServlet': initialization completed in 10 ms
2017-11-10 16:02:42.283  INFO 20271 --- [nio-8080-exec-1] com.example.ExampleController            : Testing.

Add This Maven Dependency for Spring AOP Support

The only dependency you need to add to your pom.xml for Spring AOP is this:


This is important to know. Don’t be tempted by tutorials to add other things.

Create the Annotation

Every good aspect needs an annotation interface.

package com.example;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public @interface Example
	public String msg();

Although declaring methods is not a requirement, it provides us with a mechanism for parameterizing the aspect. In this example, we are declaring a msg parameter that will be logged when the annotated method successfully returns.

Create the Aspect

This is the aspect class which effectively intercepts calls to the method where our @Example annotation is used:

package com.example;
import java.util.Collection;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ExampleAspect
	public Object executeAround(final ProceedingJoinPoint proceedingJoinPoint, Example example) throws Throwable
		Object result = null;
		// Use the target for logger naming.
		Object target = proceedingJoinPoint.getTarget();
		Logger log = LoggerFactory.getLogger(target.getClass());
			// Do something before calling the JoinPoint:
			log.info("Calling {}", proceedingJoinPoint.getSignature().toString());
			result = proceedingJoinPoint.proceed();
			// Do something after calling the JoinPoint:
		catch (Throwable e)
			//Do something if calling the JoinPoint fails:
			log.trace("Rethrowing", e);
			throw e;
		return result;

I tried to keep it simple. This basically logs the join point signature of the annotated method before calling it. Upon returning (without a Throwable) our msg parameter is logged. Note how Example is automatically passed as a parameter to the executeAround() method for us to use.

Enable AspectJ AutoProxy

You’ll need to enable AspectJ AutoProxy using the @EnableAspectJAutoProxy annotation:

 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.context.annotation.EnableAspectJAutoProxy;
 public class ExampleApplication

Just add it to the application class where @SpringBootApplication is usually found.

Using the Annotation

This part couldn’t be easier. Just use the @Example annotation on any Spring service method, such as our request mapped test method from ExampleController.java:

	@Example(msg="Completed test.")
	public boolean test(ServletRequest request)
		return (true);

Here the Example annotation interface provides the value for msg that is logged upon successful completion of Example.test():

	2017-11-10 14:48:42.229  INFO 15203 --- [           main] com.example.ExampleApplication           : Started ExampleApplication in 4.332 seconds (JVM running for 4.808)
	2017-11-10 14:48:53.919  INFO 15203 --- [nio-8080-exec-1] com.example.ExampleController            : Proceeding with JoinPoint -> boolean com.example.ExampleController.test()
	2017-11-10 14:48:53.926  INFO 15203 --- [nio-8080-exec-1] com.example.ExampleController            : Testing.
	2017-11-10 14:48:53.926  INFO 15203 --- [nio-8080-exec-1] com.example.ExampleController            : Completed test.

Information About Join Points

You can also see from the preceding output that the method boolean com.example.ExampleController.test() is the target method of our aspect. We can get this information via the ProceedingJoinPoint argument passed to our aspect.

Convenient Way To Add a Filter

It’s important to know that you can intercept a method’s passed arguments, return result, and any thrown exceptions from this vantage point. Our example aspect simply logs and re-throws any exceptions it catches.

Some potential uses:

  • benchmarking annotated methods
  • logging method entry/exit
  • unwrapping exceptions

This Just Scratches the Surface of AOP

Just using the @Around annotation in Spring doesn’t make you an AspectJ programmer, and you may never need to fully understand the benefits of AOP to take advantage of this useful and integral functionalty in Spring.