Some Spring Boot annotations by default use Spring AOP to create proxy classes. Of course, Spring allows using other libraries like AspectJ that can provide some advantages. In this article, I cover how to configure AspectJ in Spring Boot.

Introduction

To handle annotations like @Cacheable and @Transactional Spring Boot relies on Spring AOP which by default uses JDK dynamic proxy if the target class implements an interface. Otherwise, uses CGLIB to create a dynamic proxy of the class by subclassing.

Spring AOP is configured at run time and removes the need for a compilation step or load-time weaving that makes things much simpler. On the other hand, it only works on public methods that are not invoked in the same class. To overcome the drawback of Spring AOP, we can swap it with AspectJ at the cost of some configurations and an extra compilation step.

An imaginary use case

Let say we have a User microservice that has an endpoint to return a list of users. Assuming hypothetically, we have a situation that we must intercept a private method on the user controller to log some stuff. Additionally, we need to use @Cacheable on a private method. Naturally, Spring AOP is unable to cater to the above scenarios but they are easily achievable using AspectJ.

These are the codes for UserController , UserService , and LoggingInterceptor ,

As you can see @Cacheable annotation is applied to a private method. And the interceptor is set on a private method, getUsersInternal , too.

Using AspectJ in Spring Boot

Configuring AspectJ in Spring Boot involves multiple changes. To make it easy to grasp, I have broken it down to multiple steps as follows.

Adding AspectJ dependencies

We need to add all AspectJ dependencies to the project. That means we must have spring-aspects , aspectjweaver , and aspectjrt dependencies as well as configuring aspectj-maven-plugin Maven plugin to weave AspectJ aspects into the classes using the AspectJ compiler (“ajc”).

Let’s add the dependencies for the starter,

Adding AspectJ maven plugin

AspectJ supports two types of weaving, compile-time weaving (CTW) and load-time weaving (LTW) . The former is simpler since ajc compiles source codes and produces woven class files. Whereas, in LTW the binary weaving is deferred until the point that a class loader loads a class file and defines the class to the JVM. That means we have to use Spring Agent when running the project to add classes to the class loader at runtime.

Here we stick to CTW for simplicity’s sake and to avoid configuring more stuff. To use CTW we need to configure aspectj-maven-plugin in pom.xml as follows,

Important note: Mojo aspectj-maven-plugin yet does not support JDK 11, hence we have to use a forked plugin, Nickwongdev’s aspectj-maven-plugin , instead. If your project uses JDK 8, you can rely on Mojo’s one.

Enabling AspectJ in the app

Since we are using @SpringBootApplication annotation we don’t need to add @EnableAspectJAutoProxy anymore. If you use plain Spring, still you need to add that.

But still we need to change the cache configuration in the Spring Boot app. For that, we just need to modify the caching config annotation to this,

Running the app

To run the app use this command,

And then open the browser, head to localhost:8080/v1/users and hit the enter. Following messages should be logged,

The first is the interceptor message, and the second one is from getMockUsers private method that’s annotated with @Cacheable . If you refresh the page, you should only see the interceptor message and not the other one.

That means we successfully managed not only to intercep a private method but also made @Cacheable to work on a private method 🙂

You can find this article source code on GitHub,

https://github.com/kasramp/sample-spring-aspectj

Inline/featured images credits