This project is based on chapter 6.2. Implementing aspects with Spring AOP from book Spring Starts here (2021) by Laurentiu Spilca.
File > New project > Java
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.1.10</version>
</dependency>
@Service
public class MessageService {
// create logger
private Logger logger = Logger.getLogger(MessageService.class.getName());
// log message
public void processMessage(final String message) {
logger.info("Processing message: " + message);
}
}
@Configuration
@ComponentScan(basePackages = "org.example")
public class ApplicationConfiguration {
}
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>6.1.10</version>
</dependency>
@Configuration
+ @EnableAspectJAutoProxy
@ComponentScan(basePackages = "org.example")
public class ApplicationConfiguration {
}
- use
@Aspect
annotation to mark bean as aspect
@Aspect
@Component
public class LoggingAspect {
}
-
explanation of the pointcut expression in
@Around
annotation:-
*
- this wildcard symbol indicates any return type of the method. It means the advice applies regardless of what the method returns. -
org.example.MessageService
- This is the fully qualified name of the class containing the method to be advised. It specifies that the target method is within the MessageService class in the org.example package. -
processMessage
- this is the name of the method to be advised. The advice will be applied to methods with this name. -
(..)
- these parentheses with two dots inside signify any number and type of arguments to the method. It means the advice applies to processMessage methods regardless of what parameters they take.
-
@Aspect
@Component
public class LoggingAspect {
private Logger logger = Logger.getLogger(LoggingAspect.class.getName());
@Around("execution(* org.example.MessageService.processMessage(..))")
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
logger.info("Before processing message");
Object result = joinPoint.proceed();
logger.info("After processing message");
return result;
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ArgumentsLog {
}
@Aspect
@Component
public class ArgumentsAspect {
private Logger logger = Logger.getLogger(ArgumentsAspect.class.getName());
@Before("@annotation(ArgumentsLog)")
public void logArguments(JoinPoint joinPoint) {
final String methodName = joinPoint.getSignature().getName();
final Object [] arguments = joinPoint.getArgs();
logger.info("Method " + methodName + " with parameters " + Arrays.asList(arguments) + " will execute");
}
}
@Service
public class MessageService {
private Logger logger = Logger.getLogger(MessageService.class.getName());
+ @ArgumentsLog
public void processMessage(final String message) {
logger.info("Processing message: " + message);
}
}
ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class);
MessageService messageService = context.getBean(MessageService.class);
messageService.processMessage("Hello World!");
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.11.0-M2</version>
<scope>test</scope>
</dependency>
public class ApplicationTests {
@Test
@DisplayName("Checks that Application Context is created")
public void checkApplicationContextCreated() {
ApplicationContext context = new AnnotationConfigApplicationContext();
assertNotNull(context);
}
}