spring

@Component vs @Service vs @Repository vs @Controller

The Hierarchy

All four are stereotype annotations used for auto-detection via @ComponentScan. They form a hierarchy:

@Component          ← Generic base
  ├── @Service      ← Business logic layer
  ├── @Repository   ← Data access layer
  └── @Controller   ← Presentation layer (MVC)

Detailed Comparison

AnnotationLayerPurposeSpecial Behavior
@ComponentGenericGeneral-purpose Spring beanNone — just registers a bean
@ServiceBusinessService/business logicNone — purely semantic (documentation intent)
@RepositoryPersistenceDAO / data accessException Translation — converts JDBC/JPA exceptions to Spring's DataAccessException
@ControllerWebMVC Controller✅ Works with @RequestMapping, returns view names
@RestControllerWebREST API Controller@Controller + @ResponseBody — returns JSON/XML directly

Key Insight: They Are Technically Interchangeable (But Don't!)

// This WORKS — Spring treats it as a bean @Component public class UserService { } // But this is CORRECT — communicates intent @Service public class UserService { }

Internally, @Service, @Repository, and @Controller are all meta-annotated with @Component. Spring detects them through @ComponentScan identically.

Why Use Specific Annotations?

1. Readability & Architecture

@Repository // → "This talks to the database" public class UserRepository { } @Service // → "This contains business rules" public class UserService { } @Controller // → "This handles web requests" public class UserController { }

2. @Repository's Exception Translation

@Repository public class OrderDao { public Order findById(Long id) { // If this throws a JDBC SQLException... // Spring wraps it in DataAccessException automatically return jdbcTemplate.queryForObject("SELECT ...", mapper, id); } }

Without @Repository, raw JDBC/JPA exceptions would leak into service layers.

3. AOP Targeting

You can apply Aspect-Oriented Programming advice to specific stereotypes:

@Around("@within(org.springframework.stereotype.Service)") public Object logServiceMethods(ProceedingJoinPoint jp) throws Throwable { // Log all methods in @Service classes log.info("Calling: {}", jp.getSignature()); return jp.proceed(); }

Best Practice

Always use the most specific stereotype annotation. It documents your architecture, enables framework features (like exception translation), and allows targeted AOP.

@Component vs @Service vs @Repository vs @Controller | DevExCode