Issue
I was trying to follow this video tutorial to add AOP to my Spring Boot project in order to perform log operation: https://www.youtube.com/watch?v=RVvKPP5HyaA
But it is not working, it is not logging anything.
So this is my pom.xml file:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.easydefi</groupId>
<artifactId>GET-USER-WS</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>GET-USER-WS</name>
<description>Microservice that retrieves users from DB</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<!-- Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>nl.martijndwars</groupId>
<artifactId>web-push</artifactId>
<version>5.1.1</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.6.3</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
As you can see I added this dependency to it:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.6.3</version>
</dependency>
Then I created this LoggingAOP class in order to configure AOP behavior:
package com.easydefi.aop.logging;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.java.Log;
@Aspect
@Component
@Log
public class LoggingAOP {
@Pointcut(value = "execution(* com.easydefi.users.*.*.*(..))")
public void myPointcut() {
}
@Around("myPointcut()")
public Object applicationLogger(ProceedingJoinPoint pjp) throws Throwable {
ObjectMapper mapper = new ObjectMapper();
String methodName = pjp.getSignature().getName();
String className = pjp.getTarget().getClass().toString();
Object[] argsArray = pjp.getArgs();
log.info("Method invoked " + className + ":" + methodName + "() arguments: " + mapper.writeValueAsString(argsArray));
Object response = pjp.proceed();
log.info(className + ":" + methodName + "() Response: " + mapper.writeValueAsString(response));
return response;
}
}
In theory the used @Pointcut expression:
@Pointcut(value = "execution(* com.easydefi.users.*.*.*(..))")
should define the execution o all method into all class of all package defined into the project root that is com.easydefi.users but it is logging nothing.
Running my application and calling a controller method or a service method I expected that he would enter into the applicationLogger() method. But it is not working (I also tried in debug mode and it never enter into this method).
This is my project structure:
So what is wrong? What am I missing? How can I try to fix it?
Solution
Your pointcut
execution(* com.easydefi.users.*.*.*(..))
looks a bit unflexible, but it works perfectly for intercepting methods like
public void com.easydefi.users.service.CoinService.doSomething()
public boolean com.easydefi.users.specification.MySpec.fooBar(int, String)
It works not for
public String com.easydefi.users.specification.criteria.MyCriteria.zot()
public void com.easydefi.users.aa.bb.cc.SomeService.zot()
for reasons M. Deinum has mentioned already. His suggestion to use the ..*
notation, which means "any method in any class in the package preceded by ..*
", is exactly right:
execution(* com.easydefi.users..*(..))
I also want to stress that the credit for this answer should be his, and if he likes to simply copy my answer and post it under his own name instead of just a comment, I shall remove this one gladly instead. But I do think questions deserve comprehensive answers.
Answered By - kriegaex
Answer Checked By - Pedro (JavaFixing Volunteer)