Stereotype Annotations
Same bean, different hat. Semantics matter in enterprise code.
The Hyderabad Software Office Roles Analogy:
In an IT company, everyone doesn't do the same job. There are roles:
- Receptionist (@Controller): Talks to the client. Sends outsiders to the right room. (Handles web requests).
- Developer (@Service): Writes the actual business logic. Calculations and rules happen here.
- Database Admin (@Repository): Fetches data from the database and saves it.
- Utility Worker (@Component): Does general work with no specific role (like date formatting).
Technically, whether you write @Component, @Service, or @Repository — Spring treats them all the same (as a Bean). But they have different names for semantics (so the developer reading the code knows what the class does).
- @Component: The parent annotation. Tells Spring "Make me a bean".
- @Service: Tells Spring "I hold business logic". Functionally identical to @Component.
- @Repository: Tells Spring "I talk to the database". Has a special superpower: it catches raw SQL exceptions and converts them into Spring's unified
DataAccessException. - @Controller: Used for web layers (returns HTML views in traditional MVC).
package com.devinhyderabad;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Repository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
private OrderController orderController;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... args) throws Exception {
orderController.placeOrder("Laptop");
}
}
@Component
class OrderController {
@Autowired
private OrderService orderService;
public void placeOrder(String item) {
System.out.println("Controller: Received order for " + item);
orderService.processOrder(item);
}
}@Service
class OrderService {
@Autowired
private OrderRepository orderRepository;
public void processOrder(String item) {
System.out.println("Service: Applying 10% discount for " + item);
orderRepository.saveToDb(item);
}
}
@Repository
class OrderRepository {
public void saveToDb(String item) {
System.out.println("Repository: Saved " + item + " to H2 Database.");
}
}The flow is: Controller → Service → Repository. A @Service should never directly call another @Service if it breaks domain boundaries, and a Controller must never touch a Repository directly.
Interview Question: "If @Component, @Service, and @Repository all do the same thing (create beans), why do we have three different annotations?"
Answer: They exist for Separation of Concerns and readability. However, @Repository is technically different — it acts as a marker to enable automatic exception translation. Spring intercepts raw SQLException thrown by database drivers and converts them into Spring's consistent DataAccessException hierarchy.
Enterprise Note: Strict architecture rules dictate Controller → Service → Repository flow. Breaking this leads to tightly coupled, untestable code.
Key Takeaways
- ✅ @Component, @Service, @Repository all create beans — semantics differ
- ✅ @Repository auto-translates SQLExceptions to Spring DataAccessException
- ✅ Layered architecture: Controller → Service → Repository
- ✅ Always follow the layered flow to keep code decoupled and testable
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login