Spring Core - How to implement and deploy Advices using Spring AOP
AOP solves critical issues related to cross-cutting concerns by modularizing them into reusable and maintainable aspects. It simplifies code, reduces duplication, and enhances the separation of concerns, making it a powerful tool in modern application development.
Add Spring AOP Dependency
Add the necessary Spring AOP dependency to your pom.xml, if you're using Maven, or build.gradle in case of Gradle:
// MAven
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.26</version> <!-- Use the latest compatible version -->
</dependency>
// Gradle
implementation 'org.springframework:spring-aspects:5.3.26'
Enable AOP in Your Spring Application
Enable AspectJ Auto Proxying in your Spring configuration by adding the @EnableAspectJAutoProxy annotation.
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
// Other bean definitions
}
Define the Target Service
Create a service class that will have methods where you want to apply the advice.
package com.example.service;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
public void placeOrder() {
System.out.println("Order placed successfully!");
}
public void cancelOrder() {
System.out.println("Order canceled.");
}
}
Create the Aspect
Define an aspect class to implement the advice. An aspect contains:
- Pointcuts: Specify where the advice should be applied.
- Advices: Define the behavior to apply.
package com.example.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
// Pointcut: Matches all methods in the service package
@Before("execution(* com.example.service.*.*(..))")
public void logBefore() {
System.out.println("Logging BEFORE method execution.");
}
@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result")
public void logAfterReturning(Object result) {
System.out.println("Logging AFTER method returned successfully.");
}
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "exception")
public void logAfterThrowing(Exception exception) {
System.out.println("Logging AFTER method threw an exception: " + exception.getMessage());
}
@Around("execution(* com.example.service.*.*(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Logging AROUND method execution: BEFORE");
Object result;
try {
result = joinPoint.proceed(); // Proceed with the target method
} catch (Throwable ex) {
System.out.println("Logging AROUND method execution: EXCEPTION");
throw ex;
}
System.out.println("Logging AROUND method execution: AFTER");
return result;
}
}
Run the Application
Create a main method or use a Spring Boot application class to run the application.
package com.example;
import com.example.service.OrderService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class AopDemoApplication {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(AopDemoApplication.class, args);
// Get the OrderService bean and call its methods
OrderService orderService = context.getBean(OrderService.class);
orderService.placeOrder();
orderService.cancelOrder();
}
}
Output Example
When the application runs, the following output will appear in the console:
Logging BEFORE method execution.
Order placed successfully!
Logging AFTER method returned successfully.
Logging AROUND method execution: BEFORE
Order canceled.
Logging AROUND method execution: AFTER
If an exception occurs in the placeOrder or cancelOrder method, the @AfterThrowing advice will log it.
