Aspect-Oriented Programming (AOP) provides a way to modularize cross-cutting concerns, such as logging, transaction management, and security. This guide demonstrates how to implement AOP in Spring Boot with examples in Java and Kotlin.
Written by
Şuayb Şimşek
Backend-focused fullstack developer sharing practical notes on Spring Boot, security, microservices, and cloud-native architecture.
Get practical backend + fullstack notes when new articles are published.
Social
🌟 Why Use AOP?
AOP enables developers to separate concerns that affect multiple parts of an application, like logging or security, into reusable aspects. This approach promotes cleaner code, improved maintainability, and reduced redundancy.
📋 Prerequisites
📋 Ensure you have the following:
☕ Java Development Kit (JDK) 17+
📦 Maven or Gradle installed
🔤 A Java IDE (e.g., IntelliJ IDEA, Eclipse)
🛠️ Step 1: Add Dependencies
Include the following dependencies in your project:
Expose the service methods through a REST controller.
▶️ Running the Application
Run the application using the following commands:
Spring Boot (Java/Kotlin):
Run the application with either stack to confirm the baseline setup is working before deeper tests.
BASH
./mvnw spring-boot:run
Access the API at http://localhost:8080/api/users.
🧪 Testing the API
You can test the API using the following cURL commands:
Fetch all users:
BASH
curl -X GET http://localhost:8080/api/users
Fetch a user by ID:
BASH
curl -X GET http://localhost:8080/api/users/1
🏁 Conclusion
You now have a practical Aspect-Oriented Programming in Spring Boot implementation with a clear, production-friendly Spring Boot structure. As a next step, adapt configuration and tests to your own domain, then validate behavior under realistic traffic and failure scenarios.
Service
JAVAUserService.java
package com.example.demo.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
public String getUserById(String id) {
return "User with ID: " + id;
}
public String getAllUsers() {
return "Fetching all users.";
}
}
Service
KOTLINUserService.kt
package com.example.demo.service
import org.springframework.stereotype.Service
@Service
class UserService {
fun getUserById(id: String): String {
return "User with ID: $id"
}
fun getAllUsers(): String {
return "Fetching all users."
}
}
Aspect
JAVALoggingAspect.java
package com.example.demo.aspect;
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
@Component
public class LoggingAspect {
private static final Logger logger = LoggerFactory.getLogger(LoggingAspect.class);
@Before("execution(* com.example.demo.service.UserService.*(..))")
public void logBefore() {
logger.info("Method execution started.");
}
}
Aspect
KOTLINLoggingAspect.kt
package com.example.demo.aspect
import org.aspectj.lang.annotation.Aspect
import org.aspectj.lang.annotation.Before
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
@Aspect
@Component
class LoggingAspect {
private val logger = LoggerFactory.getLogger(LoggingAspect::class.java)
@Before("execution(* com.example.demo.service.UserService.*(..))")
fun logBefore() {
logger.info("Method execution started.")
}
}
Controller
JAVAUserController.java
package com.example.demo.controller;
import com.example.demo.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/users")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@GetMapping("/{id}")
public String getUserById(@PathVariable String id) {
return userService.getUserById(id);
}
@GetMapping
public String getAllUsers() {
return userService.getAllUsers();
}
}
Controller
KOTLINUserController.kt
package com.example.demo.controller
import com.example.demo.service.UserService
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping("/api/users")
class UserController(
private val userService: UserService
) {
@GetMapping("/{id}")
fun getUserById(@PathVariable id: String): String = userService.getUserById(id)
@GetMapping
fun getAllUsers(): String = userService.getAllUsers()
}