DEV Community

loading...

Aspect Oriented Programming with Java and SpringBoot

pmgysel profile image Philipp Gysel Updated on ・6 min read

This blog covers the basics of Aspect Oriented Programming (AOP). I’ll show a simple working example of AOP: a common task like logging of REST calls can be generically defined in an Advice, which can then be applied to various target places in our code (so called Pointcuts) via an Aspect.

For the impatient: you can find the end result on my Github repo🏎️

GitHub logo pmgysel / aop-demo

Demo for Aspect Oriented Programming

Programming Paradigms

Back in the 1996, when Java 1.0 was released, Java developers were all hyped up about object oriented programming, also called OOP. While OOP was one of the foundational drivers for Java, the programming language itself has gone a long way since then and now supports many programming paradigms.

Here’s a list of the primary programming paradigms supported in Java (in historical order):

  • Procedural programming
  • Object oriented programming (OOP)
  • Functional programming
  • Aspect oriented programming (AOP)

For this post, we focus on AOP and show how to create Aspects. You’ll learn both the basics of AOP as well as how to use it with SpringBoot.

Why AOP?

Most bigger companies have programming guidelines, and so does mine. One of our guidelines states that every REST endpoint execution must be logged (name of the Java method + the parameters).

Here’s how you could solve this:

@RestController
public class MyRestController {
  @GetMapping(path = "/api/hello/")
  public String hello() {
    System.out.println("Method [hello] gets called with 0 parameters");
    return "Hello world!";
  }
}
Enter fullscreen mode Exit fullscreen mode

The code snippet above does the following:

  • @RestController: Make sure SpringBoot knows this class contains REST endpoints
  • @GetMapping: A method which replies to HTTP GET requests
  • System.out.println(...): adhere to the aforementioned coding guidelines
  • return value: the method simply returns a greeting message of type String

In a realistic app, you will have many such REST calls, in many different classes. Doing the exact same logging in all those methods is cumbersome. Moreover, if the coding guidelines slightly change, you will have to change the logging message in each method.

Here’s where AOP comes to the rescue: with the help of AOP, we can nicely add common functionality to many different places in our code, without interfering with existing code. In literature jargon, AOP is all about the separation of cross-cutting concerns.🤓 In more human understandable language, AOP enables the modularization of common tasks across different objects.😎

Maven Dependency

To start using AOP in SpringBoot with AspectJ annotations, we need to import the following dependencies in our pom.xml:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
</dependency>
Enter fullscreen mode Exit fullscreen mode

Advice

Let’s create a function which performs our required logging in a generic way:

public void logMethodExecution(JoinPoint joinPoint) {
  String method = joinPoint.getSignature().getName();
  String params = Arrays.toString(joinPoint.getArgs());
  System.out.println("Method [" + method + "] gets called with parameters " + params);
}
Enter fullscreen mode Exit fullscreen mode

This generic function is called an Advice. Note that it can log the name and parameters of any method; let’s break the Advice down step by step:

  • JoinPoint: this object contains all information about the Join point, that is, the "location" where our Aspect will be inserted. In our case, this would be the REST method for which we want to create a log message for.
  • joinPoint.getSignature() and joinPoint.getArgs() extracts the method signature as well as the calling arguments
  • System.out.println(...): do the necessary logging

Pointcut

So where do we want to insert the above Advise method? Well, we want each REST endpoint to be tracked. While there are many ways to mark our REST endpoints, we choose to use a custom annotation to define the Pointcut:

@Before("@annotation(LogMethod)")
public void logMethodExecution(JoinPoint joinPoint) {...}
Enter fullscreen mode Exit fullscreen mode

As you can see, the Pointcut definition is just a one-liner:

  • @Before: we run the Advice before the REST call gets answered
  • @annotation: we mark Pointcuts via an annotation
  • LogMethod: this is the name of our custom annotation

Now we’re ready to mark our REST method with our custom annotation:

@LogMethod
@GetMapping(path = "/api/hello/")
public String hello() {
  return "Hello world!";
}
Enter fullscreen mode Exit fullscreen mode

Note that we prepended the REST method with the annotation @LogMethod. Moreover, we removed the logging inside the method, this is now done by our Aspect.

Aspect

An Aspect is a Pointcut plus an Advice. So, let’s put the two together, and we get:

@Aspect
@Component
public class LoggingAspect {

  @Before("@annotation(LogMethod)")
  public void logMethodName(JoinPoint joinPoint) {
    String method = joinPoint.getSignature().getName();
    String params = Arrays.toString(joinPoint.getArgs());
    System.out.println("Method [" + method + "] gets called with parameters " + params);
  }
}
Enter fullscreen mode Exit fullscreen mode

Here’s what we have:

  • @Aspect: SpringBoot expects all Aspects to be in classes annotated with @Aspect
  • @Before(...): the Pointcut
  • logMethodName(...){...}: the Advice

So all we did here was just bring together the previously shown Pointcut expression plus the Advice, and wrap everything in a class. Bring out the champagne, we have our Aspect all finished and working 🥂

Enable AOP

To wrap up, we have to enable AspectJ for our Spring configuration:

@Configuration
@EnableAspectJAutoProxy
public class AspectConfig {

}
Enter fullscreen mode Exit fullscreen mode

Remember that we want to be able to work with Beans when using Spring. At the moment, our @RestController class only contains the REST-call logic, but not our Advice. Spring can create Proxies for such Beans which contain this additional logic (the Advice), and this is enabled by @EnableAspectJAutoProxy.

Conclusion

That’s all! You now have a fully working example of AOP😀💪🍾

We implemented an Advice to be run anytime a method with annotation @LogMethod is executed. Thanks to our AOP approach, we can add this annotation to future REST methods which will then be advised with the same Aspect!

Checkout the fully working example on Github:

GitHub logo pmgysel / aop-demo

Demo for Aspect Oriented Programming

Demo for Aspect Oriented Programming

This is a simple web service which uses AOP. The REST methods are advised by multiple Aspects.

Dependencies

  • Java JDK 15
  • Maven:
    • spring-boot-starter-aop
    • aspectjweaver

Aspects for REST calls

  • Log method name and parameters
  • Log duration of method

Usage

  • Compile and run web service:
mvn clean install
mvn spring-boot:run
Enter fullscreen mode Exit fullscreen mode
  • Sample REST calls:
GET http://localhost:8080/api/greeting/{name}
GET http://localhost:8080/api/order/{menu}
Enter fullscreen mode Exit fullscreen mode

Sample aspect output

Method [greeting] gets called with parameters [John]
Exeution took [21ms]
Enter fullscreen mode Exit fullscreen mode

This Github repo also contains a second advice of type @Around: Each time a REST method is called, we log the execution time. This can come in handy to measure, monitor and compare the performance of different REST endpoints.

Thanks for reading, please leave a comment if you have any feedback or questions!😀


Further readings

For the curious, here’s some more reading material:

AOP primer and Advice types:
In our example, we used an Advice of type @Before. Alternatively, you can use @After, @Around or @AfterThrowing.

Pointcuts are predicates that match a set of Join points. We used annotation-driven Pointcuts, but Spring supports many more designator types. For example, Spring supports execution Pointcuts where a method name has to match a given pattern.

AOP Proxies: an explanation in the official Spring documentation.

Discussion (0)

Forem Open with the Forem app