📘 Premium Read: Access my best content on Medium member-only articles — deep dives into Java, Spring Boot, Microservices, backend architecture, interview preparation, career advice, and industry-standard best practices.
✅ Some premium posts are free to read — no account needed. Follow me on Medium to stay updated and support my writing.
🎓 Top 10 Udemy Courses (Huge Discount): Explore My Udemy Courses — Learn through real-time, project-based development.
▶️ Subscribe to My YouTube Channel (172K+ subscribers): Java Guides on YouTube
- @Before – Run before the method execution
- @After – Run after the method returned a result
- @AfterReturning – Run after the method returned a result, and intercept the returned result as well.
- @AfterThrowing – Run after the method throws an exception
- @Around – Run around the method execution, and combine all three advices above.
AspectJ @Before Annotation Usage [Snippet]
@Aspect
@Component
public class LoggingAspect {
private final Logger log = LoggerFactory.getLogger(this.getClass());
/**
* Run before the method execution.
* @param joinPoint
*/
@Before("execution(* net.guides.springboot2.springboot2jpacrudexample.service.EmployeeService.addEmployee(..))")
public void logBefore(JoinPoint joinPoint) {
log.debug("logBefore running .....");
log.debug("Enter: {}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
}
}
- @Aspect - Indicates that this is an Aspect
- @Component - This annotation mark the beans as Spring’s managed components
- @Before annotated methods run exactly before all methods match with pointcut expression
AspectJ @After Annotation Usage [Snippet]
@Aspect
@Component
public class LoggingAspect {
private final Logger log = LoggerFactory.getLogger(this.getClass());
/**
* Run after the method returned a result.
* @param joinPoint
*/
@After("execution(* net.guides.springboot2.springboot2jpacrudexample.service.EmployeeService.addEmployee(..))")
public void logAfter(JoinPoint joinPoint) {
log.debug("logAfter running .....");
log.debug("Enter: {}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
}
}
- @Aspect - Indicates that this is an Aspect
- @Component - This annotation mark the beans as Spring’s managed components
- @After annotated methods run exactly after all methods match with a pointcut expression
AspectJ @Around Annotation Usage [Snippet]
@Aspect
@Component
public class LoggingAspect {
private final Logger log = LoggerFactory.getLogger(this.getClass());
/**
* Run around the method execution.
* @param joinPoint
* @return
* @throws Throwable
*/
@Around("execution(* net.guides.springboot2.springboot2jpacrudexample.service.EmployeeService.getEmployeeById(..))")
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
log.debug("logAround running .....");
if (log.isDebugEnabled()) {
log.debug("Enter: {}.{}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
}
try {
Object result = joinPoint.proceed();
if (log.isDebugEnabled()) {
log.debug("Exit: {}.{}() with result = {}", joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(), result);
}
return result;
} catch (IllegalArgumentException e) {
log.error("Illegal argument: {} in {}.{}()", Arrays.toString(joinPoint.getArgs()),
joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName());
throw e;
}
}
}
- @Aspect - Indicates that this is an Aspect
- @Component - This annotation mark the beans as Spring’s managed components
- @Around annotated methods run before and after all methods matching with a pointcut expression
AspectJ @AfterReturning Annotation Usage [snippet]
@Aspect
@Component
public class LoggingAspect {
private final Logger log = LoggerFactory.getLogger(this.getClass());
/**
* Run after the method returned a result, intercept the returned result as well.
* @param joinPoint
* @param result
*/
@AfterReturning(pointcut = "execution(* net.guides.springboot2.springboot2jpacrudexample.service.EmployeeService.deleteEmployee(..))", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
log.debug("logAfterReturning running .....");
log.debug("Enter: {}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
}
}
- @Aspect - Indicates that this is an Aspect
- @Component - This annotation mark the beans as Spring’s managed components
- @AfterReturning - Run after the method returned a result, intercept the returned result as well
AspectJ @AfterThrowing Annotation Usage [Snippet]
@Aspect
@Component
public class LoggingAspect {
private final Logger log = LoggerFactory.getLogger(this.getClass());
/**
* Advice that logs methods throwing exceptions.
*
* @param joinPoint join point for advice
* @param e exception
*/
@AfterThrowing(pointcut = "execution(* net.guides.springboot2.springboot2jpacrudexample.service.EmployeeService.updateEmployee(..))", throwing = "error")
public void logAfterThrowing(JoinPoint joinPoint, Throwable error) {
log.debug("logAfterThrowing running .....");
log.error("Exception in {}.{}() with cause = {}", joinPoint.getSignature().getDeclaringTypeName(),
joinPoint.getSignature().getName(), error.getCause() != null ? error.getCause() : "NULL");
}
}
- @Aspect - Indicates that this is an Aspect
- @Component - This annotation mark the beans as Spring’s managed components
- @AfterThrowing annotated methods run after the method (matching with pointcut expression) exits by throwing an exception.
Develop Complete Spring AOP Example with AspectJ Annotations
1. Creating a Spring Boot Application
>> Create Spring Boot Project in Spring Tool Suite [STS]
3. Maven Dependencies - Pom.xml
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.guides.springboot2</groupId>
<artifactId>springboot2-springaop-example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springboot2-springaop-example</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.4</version>
<relativePath />
<!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</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.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
4. Domain Layer
import jakarta.persistence.*;
@Entity
@Table(name = "employees")
public class Employee {
private long id;
private String firstName;
private String lastName;
private String emailId;
public Employee() {
}
public Employee(String firstName, String lastName, String emailId) {
this.firstName = firstName;
this.lastName = lastName;
this.emailId = emailId;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@Column(name = "first_name", nullable = false)
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
@Column(name = "last_name", nullable = false)
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Column(name = "email_address", nullable = false)
public String getEmailId() {
return emailId;
}
public void setEmailId(String emailId) {
this.emailId = emailId;
}
@Override
public String toString() {
return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", emailId=" + emailId +
"]";
}
}
5. The Controller Layer
import java.util.List;
import java.util.Map;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/v1")
public class EmployeeController {
@Autowired
private EmployeeService employeeService;
@GetMapping("/employees")
public List < Employee > getAllEmployees() {
return employeeService.getAllEmployees();
}
@GetMapping("/employees/{id}")
public ResponseEntity < Employee > getEmployeeById(@PathVariable(value = "id") Long employeeId)
throws ResourceNotFoundException {
Employee employee = employeeService.getEmployeeById(employeeId)
.orElseThrow(() - > new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
return ResponseEntity.ok().body(employee);
}
@PostMapping("/employees")
public Employee createEmployee(@Valid @RequestBody Employee employee) {
return employeeService.createEmployee(employee);
}
@PutMapping("/employees/{id}")
public ResponseEntity < Employee > updateEmployee(@PathVariable(value = "id") Long employeeId,
@Valid @RequestBody Employee employeeDetails) throws ResourceNotFoundException {
Employee updatedEmployee = employeeService.updateEmployee(employeeId, employeeDetails);
return ResponseEntity.ok(updatedEmployee);
}
@DeleteMapping("/employees/{id}")
public Map < String, Boolean > deleteEmployee(@PathVariable(value = "id") Long employeeId)
throws ResourceNotFoundException {
return employeeService.deleteEmployee(employeeId);
}
}
6. The Service Layer
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* Employee Service
* @author Ramesh
*
*/
@Service
public class EmployeeService {
@Autowired
private EmployeeRepository employeeRepository;
public List < Employee > getAllEmployees() {
return employeeRepository.findAll();
}
public Optional < Employee > getEmployeeById(Long employeeId)
throws ResourceNotFoundException {
return employeeRepository.findById(employeeId);
}
public Employee createEmployee(Employee employee) {
return employeeRepository.save(employee);
}
public Employee updateEmployee(Long employeeId,
Employee employeeDetails) throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() - > new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
employee.setEmailId(employeeDetails.getEmailId());
employee.setLastName(employeeDetails.getLastName());
employee.setFirstName(employeeDetails.getFirstName());
final Employee updatedEmployee = employeeRepository.save(employee);
return updatedEmployee;
}
public Map < String, Boolean > deleteEmployee(Long employeeId)
throws ResourceNotFoundException {
Employee employee = employeeRepository.findById(employeeId)
.orElseThrow(() - > new ResourceNotFoundException("Employee not found for this id :: " + employeeId));
employeeRepository.delete(employee);
Map < String, Boolean > response = new HashMap < > ();
response.put("deleted", Boolean.TRUE);
return response;
}
}
7. The Repository Layer
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
public interface EmployeeRepository extends JpaRepository < Employee, Long > {
}
8. The Logging Aspect
import java.util.Arrays; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** * Aspect for logging execution. * * @author Ramesh Fadatare * */ @Aspect @Component public class LoggingAspect { private final Logger log = LoggerFactory.getLogger(this.getClass()); /** * Run before the method execution. * @param joinPoint */ @Before("execution(* net.guides.springboot2.springboot2jpacrudexample.service.EmployeeService.addEmployee(..))") public void logBefore(JoinPoint joinPoint) { log.debug("logBefore running ....."); log.debug("Enter: {}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs())); } /** * Run after the method returned a result. * @param joinPoint */ @After("execution(* net.guides.springboot2.springboot2jpacrudexample.service.EmployeeService.addEmployee(..))") public void logAfter(JoinPoint joinPoint) { log.debug("logAfter running ....."); log.debug("Enter: {}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs())); } /** * Run after the method returned a result, intercept the returned result as well. * @param joinPoint * @param result */ @AfterReturning(pointcut = "execution(* net.guides.springboot2.springboot2jpacrudexample.service.EmployeeService.deleteEmployee(..))", returning = "result") public void logAfterReturning(JoinPoint joinPoint, Object result) { log.debug("logAfterReturning running ....."); log.debug("Enter: {}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs())); } /** * Run around the method execution. * @param joinPoint * @return * @throws Throwable */ @Around("execution(* net.guides.springboot2.springboot2jpacrudexample.service.EmployeeService.getEmployeeById(..))") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { log.debug("logAround running ....."); if (log.isDebugEnabled()) { log.debug("Enter: {}.{}() with argument[s] = {}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs())); } try { Object result = joinPoint.proceed(); if (log.isDebugEnabled()) { log.debug("Exit: {}.{}() with result = {}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), result); } return result; } catch (IllegalArgumentException e) { log.error("Illegal argument: {} in {}.{}()", Arrays.toString(joinPoint.getArgs()), joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName()); throw e; } } /** * Advice that logs methods throwing exceptions. * * @param joinPoint join point for advice * @param e exception */ @AfterThrowing(pointcut = "execution(* net.guides.springboot2.springboot2jpacrudexample.service.EmployeeService.updateEmployee(..))", throwing = "error") public void logAfterThrowing(JoinPoint joinPoint, Throwable error) { log.debug("logAfterThrowing running ....."); log.error("Exception in {}.{}() with cause = {}", joinPoint.getSignature().getDeclaringTypeName(), joinPoint.getSignature().getName(), error.getCause() != null ? error.getCause() : "NULL"); } }
9. Exception Handling
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(value = HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends Exception{
private static final long serialVersionUID = 1L;
public ResourceNotFoundException(String message){
super(message);
}
}
Let’s define a simple error response bean:
import java.util.Date;
public class ErrorDetails {
private Date timestamp;
private String message;
private String details;
public ErrorDetails(Date timestamp, String message, String details) {
super();
this.timestamp = timestamp;
this.message = message;
this.details = details;
}
public Date getTimestamp() {
return timestamp;
}
public String getMessage() {
return message;
}
public String getDetails() {
return details;
}
}
import java.util.Date;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<?> resourceNotFoundException(ResourceNotFoundException ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<?> globleExcpetionHandler(Exception ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(), request.getDescription(false));
return new ResponseEntity<>(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
10. Running the Application
package net.guides.springboot2.springboot2jpacrudexample;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class Application {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
11. Spring Rest Client
package net.guides.springboot2.springboot2jpacrudexample;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import net.guides.springboot2.springboot2jpacrudexample.model.Employee;
public class SpringRestClient {
private static final String GET_EMPLOYEES_ENDPOINT_URL = "http://localhost:8080/api/v1/employees";
private static final String GET_EMPLOYEE_ENDPOINT_URL = "http://localhost:8080/api/v1/employees/{id}";
private static final String CREATE_EMPLOYEE_ENDPOINT_URL = "http://localhost:8080/api/v1/employees";
private static final String UPDATE_EMPLOYEE_ENDPOINT_URL = "http://localhost:8080/api/v1/employees/{id}";
private static final String DELETE_EMPLOYEE_ENDPOINT_URL = "http://localhost:8080/api/v1/employees/{id}";
private static RestTemplate restTemplate = new RestTemplate();
public static void main(String[] args) {
SpringRestClient springRestClient = new SpringRestClient();
// Step1: first create a new employee
springRestClient.createEmployee();
// Step 2: get new created employee from step1
springRestClient.getEmployeeById();
// Step3: get all employees
springRestClient.getEmployees();
// Step4: Update employee with id = 1
springRestClient.updateEmployee();
// Step5: Delete employee with id = 1
springRestClient.deleteEmployee();
}
private void getEmployees() {
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity < String > entity = new HttpEntity < String > ("parameters", headers);
ResponseEntity < String > result = restTemplate.exchange(GET_EMPLOYEES_ENDPOINT_URL, HttpMethod.GET, entity,
String.class);
System.out.println(result);
}
private void getEmployeeById() {
Map < String, String > params = new HashMap < String, String > ();
params.put("id", "1");
RestTemplate restTemplate = new RestTemplate();
Employee result = restTemplate.getForObject(GET_EMPLOYEE_ENDPOINT_URL, Employee.class, params);
System.out.println(result);
}
private void createEmployee() {
Employee newEmployee = new Employee("admin", "admin", "admin@gmail.com");
RestTemplate restTemplate = new RestTemplate();
Employee result = restTemplate.postForObject(CREATE_EMPLOYEE_ENDPOINT_URL, newEmployee, Employee.class);
System.out.println(result);
}
private void updateEmployee() {
Map < String, String > params = new HashMap < String, String > ();
params.put("id", "1");
Employee updatedEmployee = new Employee("admin123", "admin123", "admin123@gmail.com");
RestTemplate restTemplate = new RestTemplate();
restTemplate.put(UPDATE_EMPLOYEE_ENDPOINT_URL, updatedEmployee, params);
}
private void deleteEmployee() {
Map < String, String > params = new HashMap < String, String > ();
params.put("id", "1");
RestTemplate restTemplate = new RestTemplate();
restTemplate.delete(DELETE_EMPLOYEE_ENDPOINT_URL, params);
}
}
Comments
Post a Comment
Leave Comment