Stereotype Annotations
Understand @Service, @Repository, and @Controller, the specialized stereotype annotations that describe the role a bean plays in a layered application.
Introduction
You could annotate every class in your application with plain @Component and it would still work, functionally speaking. But Spring provides more specific annotations, @Service, @Repository, and @Controller, that tell both the framework and other developers exactly what role a class plays in your architecture.
- Why stereotype annotations exist on top of @Component
- What @Service signals about the business layer
- What extra behavior @Repository adds
- What @Controller marks a class for
They Are All @Component Underneath
@Service, @Repository, and @Controller are all themselves annotated with @Component. This means component scanning picks them up exactly the way it picks up plain @Component classes; the difference is purely one of semantic meaning and, in @Repository's case, extra runtime behavior.
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Componentpublic @interface Service { String value() default "";}@Service
@Service marks a class that holds business logic, orchestration, and use-case rules. It typically sits between controllers and repositories, coordinating calls between them.
@Servicepublic class OrderService {
private final OrderRepository orderRepository;
public OrderService(OrderRepository orderRepository) { this.orderRepository = orderRepository; }
public Order placeOrder(Order order) { order.setStatus("PLACED"); return orderRepository.save(order); }}@Repository
@Repository marks a class responsible for data access. Beyond signaling intent, it also enables a real feature: Spring wraps @Repository beans with exception translation, converting persistence-technology-specific exceptions (like a raw JDBC SQLException) into Spring's consistent, unchecked DataAccessException hierarchy.
@Repositorypublic class OrderRepository {
public Order save(Order order) { // In a real application this would use JDBC, JPA, or another data layer System.out.println("Saving order: " + order.getId()); return order; }}@Controller
@Controller marks a class that handles incoming web requests as part of Spring MVC. Methods inside it are typically mapped to URLs and are responsible for returning a view name or, when combined with @ResponseBody (or using @RestController), the response body directly.
@Controller@RequestMapping("/orders")public class OrderController {
private final OrderService orderService;
public OrderController(OrderService orderService) { this.orderService = orderService; }
@PostMapping @ResponseBody public Order create(@RequestBody Order order) { return orderService.placeOrder(order); }}A Typical Layered Application
Controller layer
Receives HTTP requests, delegates to services, and shapes the response. Annotated with @Controller or @RestController.
Service layer
Contains business rules and coordinates one or more repositories. Annotated with @Service.
Repository layer
Talks to the database or another data source, and translates low-level exceptions. Annotated with @Repository.
Common Mistakes
- Using plain @Component everywhere instead of the more specific stereotype, which hides the class's role from anyone reading the code.
- Putting business logic directly inside a @Controller instead of delegating it to a @Service.
- Skipping @Repository on a data-access class and losing automatic exception translation.
- Mixing data-access code directly into a @Service class instead of isolating it behind a @Repository.
Best Practices
- Choose the most specific stereotype annotation available for a class's role.
- Keep controllers thin: parse input, call a service, shape the response.
- Keep business rules in the service layer, not scattered across controllers and repositories.
- Isolate all direct data-access code behind repositories so the rest of the application does not depend on persistence details.
Frequently Asked Questions
For basic dependency injection, no, both are discovered and registered the same way. But you lose the readability benefit, and for @Repository specifically you also lose automatic exception translation.
@RestController is @Controller combined with @ResponseBody applied to every handler method, so return values are written directly to the response body (typically as JSON) instead of being resolved as a view name.
No, a class should carry exactly one stereotype annotation that reflects its primary role. Mixing multiple stereotypes on the same class is not a supported pattern.
Key Takeaways
- @Service, @Repository, and @Controller are specialized forms of @Component.
- @Service marks business/use-case logic.
- @Repository marks data-access code and enables exception translation.
- @Controller marks classes that handle web requests in Spring MVC.
- Using the right stereotype communicates architecture intent and, for @Repository, adds real behavior.
Summary
Stereotype annotations turn a flat pile of @Component classes into a readable, layered architecture, with each annotation signaling exactly what role a class plays. Next, you will look at a different kind of annotation feature: the Spring Expression Language, which lets you compute and inject values dynamically.