Layered Architecture in Spring Boot 🗂️
What is Layered Architecture?
Layered architecture is a design pattern that organizes your application into logical layers, each with a clear responsibility. It's the most common pattern for Java REST APIs using Spring Boot.
| Layer | Responsibility |
|---|---|
| Controller | Handles HTTP requests and responses, maps endpoints, delegates to service |
| Service | Contains business logic, validation, orchestration of data |
| Repository | Manages data access, such as database operations |
Key Benefits
- 🧩 Clear separation of concerns
- 🧪 Easier to test and maintain
- 🚀 Promotes code reuse and scalability
Why Layers?
In the Java ecosystem, we follow the Principle of Single Responsibility. By isolating the database logic from the REST logic, we can swap a MySQL database for MongoDB without ever touching our REST Controller.
The "Angular Developer" Mental Map
| Java Layer | Angular Equivalent | Responsibility |
|---|---|---|
| Controller | Component / Route | Receiving the "event" (HTTP call) and returning a View/Data |
| Service | Service (@Injectable) | Calculating data, handling state, and sharing logic |
| Repository | HttpClient + Store | Interacting with the external data source (the DB) |
| DTO/Entity | Interface / Model | Defining the shape of the data |
Implementation Example
We’ll use a Book Management system. Notice the use of @RequiredArgsConstructor—it's the modern Java way to do Dependency Injection (instead of the older @Autowired on fields).
1. The Controller (The API Surface)
@RestController
@RequestMapping("/api/v1/books")
@RequiredArgsConstructor
public class BookController {
private final BookService bookService; // Final fields + RequiredArgsConstructor = Clean DI
@GetMapping
public ResponseEntity<List<BookResponse>> getAllBooks() {
return ResponseEntity.ok(bookService.fetchAllBooks());
}
}
2. The Service (Business Logic)
@Service
@RequiredArgsConstructor
public class BookService {
private final BookRepository repository;
@Transactional(readOnly = true)
public List<BookResponse> fetchAllBooks() {
return repository.findAll().stream()
.map(book -> new BookResponse(book.getId(), book.getTitle()))
.toList(); // Java 17+ syntax
}
}
3. The Repository (Data Access)
@Repository
public interface BookRepository extends JpaRepository<BookEntity, Long> {
// You get CRUD for free! No implementation code needed.
}
Lab Instructions
- Create a new Spring Boot project with the above structure.
- Implement a simple REST API for managing books using Controller, Service, and Repository layers.
- Add a new endpoint to fetch all books.
- (Optional) Add endpoints for creating, updating, and deleting books.
Angular Perspective
- Similar to Angular's separation of concerns: Components (UI), Services (logic), and HttpClient (data access).
- Promotes modular, testable code in both frontend and backend.
Real-World Use Case
Suppose you’re building an online bookstore. The controller handles HTTP requests for books, the service layer contains business rules (e.g., discounts, stock checks), and the repository interacts with the database.
Comparison with Other Architectures
| Architecture | Pros | Cons |
|---|---|---|
| Layered | Simple, maintainable, testable | Can become rigid for large systems |
| Hexagonal | Flexible, good for integrations | More complex, steeper learning curve |
| Microkernel | Great for plugin-based systems | Overkill for most REST APIs |
Best Practices
- Keep controllers thin—move logic to services.
- Use interfaces for services and repositories for easier testing.
- Avoid direct database access in controllers or services.