Cleaner Spring MVC Controllers Using AOP and Filters

Marcos Abel
Trabe
Published in
2 min readJan 25, 2021
Photo by Isaac Benhesed on Unsplash

I use AOP for all kinds of stuff. I love having a clear separation between the main code and the cross-cutting concerns and, once you understand how AOP works in Spring and get used to the terminology, there is no coming back.

One scenario where I use AOP extensively is to advise controller methods. But I have a problem with what I consider to be the “classic way” of doing AOP.

Let me explain.

The classic way: get parameters from joinpoint

I call “the classic way” of doing AOP to an implementation with the following characteristics:

  • The advised method includes in its signature all the parameters needed for the advice to perform its function.
  • The advice gets whatever bits of data it needs from those parameters.

Let’s refactor the tracing functionality of a simple controller using AOP “the classic way”:

As you can see, we have a controller method that prints some tracing information and then performs its main task. The method receives a parameter of the type ContextInformation which is resolved from a header using a HandlerMethodArgumentResolver:

We can split the controller into a controller and an Aspect. Let’s start defining a custom annotation:

Now we can define a @Before aspect and write a pointcut to force its execution for every method annotated with our annotation:

We use an AopUtils component for this project in order to keep our @Aspect as clean as possible:

With all the AOP bits in place, we can rewrite our controller as follows:

We have now a cleaner controller, focused on its main task and we can handle the tracing functionality using a declarative approach.

The problem with this approach is that we need to keep the ContextInformation parameter in our controller method’s signature.

This is really ugly and it is also dangerous: a member of the team can see an unused parameter and just remove it not being aware of the Aspect working with that parameter.

A better way: attach the parameters to the request

In my previous story, I wrote about how attaching objects to the request using filters helped with the optimization of argument resolvers.

We are going to apply the same trick here:

We add a filter that stores the information we need in the request. The storage/retrieval is delegated to a RequestUtils component:

We can now rewrite our TraceAccessDetailsAspect:

And finally, get rid of the parameter in our controller method:

Wrapping up

We usually do things based on habits. But sometimes it pays off to think outside the box and combine different techniques to keep our code cleaner.

--

--