Spring

Spring AOP @Before Advice with Examples

This is a Hands on guide to Spring AOP @Before advice. Contains examples to do initial setup and use @Before advice in a Spring or Spring Boot application.

Before Advice Introduction

In Aspect Oriented Programming the cross cutting concerns are segregated in Aspects and they are applied on the classes in the form of advices. Spring AOP supports different types of advices, and the Before advice is one of them.

This type of advice runs before a target method and take care of the cross cutting concerns before the target method is executed.

Next, are a few important points about the Before advice.

  1. Before Advice runs before target method execution
  2. It cannot stop execution of the target method, unless it throws.
  3. Before advice can access all arguments from the Target method.
  4. It cannot alter the argument values to the original method.
  5. Before advice has to specify a Pointcut expression unless we are using a separate @Pointcut expression provider.

Setup

Spring AOP is easy to use and it doesn’t really need too much of a setup. However, in this section we will add dependencies and setup a few classes for this example.

Dependency

First, we will add dependencies on spring-aspects module.

<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>{spring.aop.version}</version> </dependency>
Code language: HTML, XML (xml)

Enable Aspects

In an application based on Spring Framework, we need to enable the aspects and advices using this annotation.

@Configuration @EnableAspectJAutoProxy public class ApplicationConfig {
Code language: Java (java)

If the application is a Spring Boot project, we can skip this step. Spring Boot’s auto configuration feature automatically enables the proxy, when it sees related dependency on the class path.

Create Target Class

The target is the class, that we want to advice. It can be any normal class. For this example, next is our target class that has one method. The target method takes an argument of type String and returns a list of string values.

Target Class

@Service public class FileSystemStorageService { public List<String> readFile(String name) { log.info("Reading file: {}", name); // Skipped return List.of("Text from file"); } }
Code language: Java (java)

Create Aspect

An Aspect is a normal Java class, and to make it an aspect we need to annotate it with @Aspect annotation. Also, we want Spring component scan to discover this class. Thus, we will mark with a Spring Stereotype annotation of @Compoenent.

An empty Aspect

@Aspect @Component public class LoggingAspect { }
Code language: Java (java)

Now, we have got the dependency set, we have enabled aspect oriented programming in Spring, and we have created a target class as well as an aspect class. Next, we will write a Before Advice.

Spring AOP Before Advice Example

In this section, we will write our first Before advice example in Spring AOP. We need to use @Before annotation to make advice out of a method.

Before Advice on a Specific Method

Now, we will create an example of Before advice on a particular method. To do that, we need to provide a Pointcut expression that exactly matches with a method.

In the next example, the pointcut expression points to a particular method from a particular class.

Aspect with Before Advice

@Slf4j @Aspect @Component public class LoggingAspect { @Before("execution(* com.amitph.spring.aop.service.FileSystemStorageService.readFile(..))") public void logBeforeMethodCall() { log.info("Inside Before Advice"); } }
Code language: Java (java)

Note that, we have used an expression in the @Before annotation, which expresses the fully qualified class name and method name. With this expression, any polymorphic method named as readFile, that belongs to the given class will be treated as a target.

Now, we will auto wire the target class and execute the method on it.

Executing method on the target class

@Autowired FileSystemStorageService service; @PostConstruct public void processFile() { service.readFile("test.txt"); }
Code language: Java (java)

Although, we auto wired the service instance, from the advice and the expression Spring knows the service is the target class. Thus, Spring AOP injects a proxy instead of an actual instance of the target class. When we start the Spring or Spring Boot application, we see Spring executes the advice before the actual method.

INFO | [main] c.a.s.a.s.LoggingAspect:14 - Inside Before Advice INFO | [main] c.a.s.a.s.FileSystemStorageService:13 - Reading file: test.txt
Code language: plaintext (plaintext)

Before Advice on all Methods of a Class

In order to apply a Before Advice on all methods of a class, we can use wildcard expression as shown next.

@Before("execution(* com.amitph.spring.aop.service.FileSystemStorageService.*(..))") public void logBeforeMethodCall() { log.info("Inside Before Advice"); }
Code language: Java (java)

Before Advice on all Methods in a Package

Similarly, we can use wildcard expression on the class name so that Before Advice is applied on all methods of all classes in a package.

@Before("execution(* com.amitph.spring.aop.service.*.*(..))") public void logBeforeMethodCall() { log.info("Inside Before Advice"); }
Code language: Java (java)

Access Method Parameters in Before Advice

We can also read, the signature, name, class name, and all the arguments of target method in the Before advice. However, Before Advice cannot change any value of the method arguments.

Get Method Arguments using JoinPoint

The JoinPoint in AOP is the target, on which the advice is applied. AspectJ provides a JoinPoint class to store some information about the target. We can simply change the signature of the Before Advice method to accept an argument of JoinPoint type.

Next is an example of Before Advice with JoinPoint as argument.

@Before("execution(* com.amitph.spring.aop.service.FileSystemStorageService.readFile(..))") public void logBeforeMethodCall(JoinPoint joinPoint) { String className = joinPoint.getTarget().getClass().getSimpleName(); String methodName = joinPoint.getSignature().getName(); String argumentName = joinPoint.getArgs()[0].toString(); log.info("Executing {} with argument: {}", className + methodName, argumentName); }
Code language: Java (java)

Output:

INFO | [main] c.a.s.a.s.LoggingAspect:20 - Executing FileSystemStorageServicereadFile with argument: test.txt INFO | [main] c.a.s.a.s.FileSystemStorageService:13 - Reading file: test.txt
Code language: plaintext (plaintext)

Get Method Arguments in Before Advice

Although, the JoinPoint instance provides a lot of information about the target method, alternatively we can also map direct method arguments into the advice. To do that, we need to add args expression in the Pointcut.

Get Method Arguments

@Before("execution(* com.amitph.spring.aop.service.FileSystemStorageService.readFile(..)) " + "&& args(name)") public void logBeforeMethodCall(String name) { log.info("Executing target with argument: {}", name); }
Code language: Java (java)

Also, we can specify the args expression for polymorphic arguments.

@Before("execution(* com.amitph.spring.aop.service.FileSystemStorageService.readFile(..)) " + "&& args(name,..)")
Code language: Java (java)

This expression will match all the readFile methods from the target class, whose first argument is a String.

Get Arguments along with JoinPoint

To get JoinPoint instance along with method argument, we can put it in the first argument of advice method.

@Before("execution(* com.amitph.spring.aop.service.FileSystemStorageService.readFile(..)) " + "&& args(name)") public void logBeforeMethodCall(JoinPoint joinPoint, String name) { log.info("Executing target with argument: {}", name); }
Code language: Java (java)

If the JoinPoint is first argument to the advice, we do not need to provide an expression for it.

Summary

This article provided detailed introduction to Spring AOP Before Advice. With the helps of plenty of examples, we understood that before advice can specify pointcut expressions to map to target classes, and methods. Also, we have seen how to read method arguments from the Joinpoint as well as mapping arguments directly.

For more on Spring & Spring Boot, please visit Spring Tutorials.