Difference between @Component, @Service, @Repository, @Controller?
All these annotations create beans, but for different layers of the application:
Junior Level
All these annotations create beans, but for different layers of the application:
| Annotation | For what | Feature |
|---|---|---|
| @Component | General bean | Base annotation |
| @Service | Business logic | Semantic marker |
| @Repository | Database access | Automatic exception translation |
| @Controller | Web MVC | Returns View (HTML) |
| @RestController | REST API | Returns JSON |
@Repository
public class UserRepository { }
@Service
public class UserService { }
@RestController
public class UserController { }
Middle Level
@Repository - Exception Translation
Translation is performed NOT by the @Repository annotation itself, but by PersistenceExceptionTranslationPostProcessor.
It creates a proxy around the bean and intercepts exceptions. Without connected
JPA/Hibernate there will be NO translation - exceptions pass through as-is.
@RestController
// @RestController = @Controller + @ResponseBody. @ResponseBody tells Spring: do not look for
// View (HTML template), but serialize the returned object into HTTP response (usually JSON via Jackson).
// @Controller -> returns View (HTML)
@Controller
public class PageController {
@GetMapping("/page")
public String page() { return "page.html"; } // View
}
// @RestController -> returns JSON
@RestController
public class ApiController {
@GetMapping("/api/user")
public User user() { return new User(); } // JSON
}
AOP Pointcuts
// Apply aspect only to services:
@Before("within(@org.springframework.stereotype.Service *)")
public void logServiceCall() { }
Senior Level
PersistenceExceptionTranslationPostProcessor
@Repository -> proxy -> intercepts exceptions
-> PersistenceExceptionTranslator
-> JpaDialect, HibernateExceptionTranslator
-> Translates to DataAccessException
Component Scanning Optimization
spring-context-indexer:
-> META-INF/spring.components at compile time
-> Spring reads list instead of scanning
-> +50% to startup speed
Proxy Overhead
@Repository creates a proxy for exception translation.
Overhead is measured in nanoseconds - negligible for most applications.
Matters at >100K calls/sec.
Production Experience
Real scenario: Repository does not translate
@Repository on class
-> Self-invocation method call
-> Proxy did not work
-> SQL Exception instead of DataAccessException
Solution: extract to separate bean
Best Practices
- @Component -> base, use rarely
- @Service -> business logic
- @Repository -> for DAO only
- @RestController -> REST API
- AOP -> precise pointcuts by stereotypes
- Avoid @Component for DAO/Controller
Summary for Senior
- @Repository -> exception translation via proxy
- @Service -> semantics, AOP pointcuts
- @RestController -> JSON, not View
- Proxy overhead -> 1-5 microseconds per call
- Self-invocation -> proxy does not work
- spring-context-indexer -> scanning speedup
Interview Cheat Sheet
Must know:
- All 4 annotations are @Component stereotypes, but for different architecture layers
- @Repository: PersistenceExceptionTranslationPostProcessor translates SQLException -> DataAccessException
- @Service: semantic marker + point for AOP (within(@Service *))
- @Controller: returns View (HTML template), @RestController = @Controller + @ResponseBody -> JSON
- Exception translation only works with connected JPA/Hibernate and through proxy
- Self-invocation (calling own method inside a bean) does not go through proxy - exceptions are not translated
- Proxy overhead: 1-5 microseconds per call, noticeable at >100K calls/sec
Common follow-up questions:
- Why does @Repository translate exceptions but @Service does not? - PersistenceExceptionTranslationPostProcessor creates a proxy only around @Repository.
- What happens with self-invocation in @Repository? - Proxy will not work, SQLException will not be translated.
- What is the difference between @Controller and @RestController? - @Controller returns View name, @RestController serializes object to JSON (@ResponseBody).
- Why are different annotations needed if they all = @Component? - Semantics, AOP pointcuts, automatic processing (exceptions, web).
Red flags (DO NOT say):
- “@Service also translates exceptions” - no, only @Repository.
- “@RestController is a separate annotation unrelated to @Controller” - no, it is @Controller + @ResponseBody.
- “@Repository proxy works on self-invocation” - no, Spring AOP does not intercept internal calls.
- “@Component is fine for DAO” - no, use @Repository for exception translation.
Related topics:
- [[23. What does the ComponentScan annotation do]]
- [[26. What does the Autowired annotation do]]
- [[24. What is a Configuration class]]
- [[27. What to do if there are multiple beans of the same type]]