Question 25 · Section 5

Difference between @Component, @Service, @Repository, @Controller?

All these annotations create beans, but for different layers of the application:

Language versions: English Russian Ukrainian

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

  1. @Component -> base, use rarely
  2. @Service -> business logic
  3. @Repository -> for DAO only
  4. @RestController -> REST API
  5. AOP -> precise pointcuts by stereotypes
  6. 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]]