Layered Architecture in Spring Boot — Controller → Service → Repository
Fast recall
Quick revision
Core answer
Layer responsibilities, what should NOT cross layers (entities to controller, business logic in repository), and how Spring annotations enforce the structure.
Returning JPA entities from controllers (leaks DB schema), business logic in controllers, or transactional annotations on the wrong layer.
Discuss the limits of layered architecture (anemic domain models, fat services), when to graduate to Hexagonal/Clean, and DTO mapping strategies (MapStruct).
Interview-ready guide
Interview answer
Three layers
Controller (@RestController): HTTP I/O, request validation, response shaping. No business logic, no DB access.
Service (@Service): business logic, orchestration, transaction boundary. Stateless. Calls repositories. No HTTP concepts.
Repository (Spring Data JPA): persistence only. One per aggregate. Returns entities. No business logic.
Dependencies flow strictly downward: Controller → Service → Repository. Never up.
DTOs vs entities — the critical boundary
Never return JPA entities from controllers. Reasons: leaks DB schema, lazy-loading triggers queries during serialization, sensitive fields accidentally exposed, schema changes break API contract.
DTOs explicit. CreateOrderRequest in, OrderResponse out, both with validation annotations.
Mapping: MapStruct for non-trivial (compile-time generated, type-safe), static factory for simple. Avoid reflection-based ModelMapper for production.
Transactions on the service
@Transactional belongs on service methods. A user action is one transaction — reserve inventory + persist order + emit event, atomically. Controller is HTTP, repository is too granular.
Read-only: @Transactional(readOnly=true) enables read replica routing and disables dirty checking.
Avoid @Transactional on private methods or self-invocation — Spring's proxy can't intercept; silently ignored.
What goes where — anti-patterns
Controller anti-patterns: DB access, business rules, returning entities. Service anti-patterns: HTTP handling, direct JDBC bypassing repository, anemic services that just delegate. Repository anti-patterns: business logic in queries, calling other services, returning DTOs.
Cross-cutting concerns (logging, metrics, security) via Spring AOP / interceptors, not in business code.
When layered architecture falls short
Layered works beautifully for CRUD with simple business logic. Strains when:
- Anemic domain model: entities are bag-of-getters; logic scattered in fat services
- Hard to test in isolation: service depends directly on Spring Data; business logic intertwined with framework
- Cross-cutting business workflows (sagas, complex orchestrations) have no obvious home
Graduate to Hexagonal or Clean Architecture when: rich domain logic, multiple input adapters (HTTP + Kafka + scheduled jobs), strict test isolation needed.
Recommendation
For most Spring Boot CRUD services: classic three-layer with @RestController + @Service + Spring Data JPA repositories. Strict DTO boundaries (MapStruct), transactions on services, validation in controllers, no business logic in repositories. Use AOP for cross-cutting. Graduate to Hexagonal Architecture when domain logic is rich, when multiple input/output adapters need to share business rules, or when framework-free testability is a goal. Layered isn't 'wrong' — it's the right default for the 80% of services that don't need more.
Layered Architecture in Spring Boot — Controller → Service → Repository
Direct Answer
A layered (N-tier) Spring Boot app organizes code by technical responsibility: Controller (HTTP I/O, request validation), Service (business logic, orchestration, transactions), Repository (data access). Dependencies flow strictly downward; the layer above depends on the one below via interfaces. Controllers return DTOs (never entities); services own transactions; repositories are thin Spring Data interfaces. Simple, ubiquitous, and the right default for most CRUD-style services. For richer domain logic and high-test-isolation systems, graduate to Hexagonal or Clean Architecture.
Common Mistakes & Pitfalls
Returning JPA entities from controllers (leaks DB schema), business logic in controllers, or transactional annotations on the wrong layer.
Check your understanding
Answer these without looking back at the article.
- Why is putting @Transactional on the controller a bad idea?
- When does an anemic domain model become a problem? How do you fix it?
- Walk through migrating a layered Spring Boot service to Hexagonal Architecture.
- How do you test a service in isolation without spinning up the whole Spring context?
Related interview prep categories
1Want a guided curriculum order?
These modules are also sequenced in our flagship backend interview track — open it when you prefer an ordered path instead of browsing by topic.