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
@Aspectannotation to mark bean as aspect
@Aspect
@Component
public class LoggingAspect {
}-
explanation of the pointcut expression in
@Aroundannotation:-
*- 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);
}
}