Skip to content

@Component、@Controller、@Repository 和@Service 的区别? ​

  • 标签:后端、Spring

🏛 业务架构师 ​

@Component、@Controller、@Repository、@Service 在容器注册层面完全等价(后三个都是 @Component 的语义化派生注解),区别在于表达的业务分层语义和框架附加行为:

  • @Component:通用组件,不属于典型三层的都归它(工具类、配置相关 Bean);
  • @Controller:Web 接入层标识,Spring MVC 靠它做 URL 映射(配合 @RequestMapping),是功能性的,不只是语义;
  • @Service:业务逻辑层标识,标记业务服务、事务边界;
  • @Repository:数据访问层标识,附带实际功能:持久层异常翻译(把各 ORM/DB 的异常统一转成 Spring 的 DataAccessException 体系)。

架构师视角,这个问题的价值在于注解承载了架构分层的可读性与治理:

  1. 分层注解让代码职责一目了然,新人 review 时能快速判断"这段逻辑放对层了吗";
  2. 配合 ArchUnit 等工具可以做架构约束自动化检查——DAO 不许调 Controller、Service 之间只允许单向依赖,违规直接挂构建;
  3. 我的团队规范:Controller 只做参数校验和编排(薄),Service 承载业务规则,Repository 只管存取。注解是分层的显式契约,配套的检查规则才是分层不被腐蚀的保障。

一句话:语义等价但职责不同,注解选对是架构表达,配套约束才是治理。

🏗 系统架构师 ​

功能上完全等价(都是 @Component 的语义化别名,都会被组件扫描捕获),区别只在语义与治理:

  • @Controller:Web 层入口,MVC 只认它(或组合了 @RequestMapping 的注解)做 Handler 映射;
  • @Service:业务逻辑层;
  • @Repository:持久层,额外做持久层异常翻译——把各家 ORM 异常统一转成 DataAccessException 体系;
  • @Component:不属于以上三层的通用组件。

我的架构用法:注解是给人和工具看的元数据——AOP 切点按层定向拦截(如「所有 @Service 方法打点」),ArchUnit 用它校验分层依赖(Controller 不得直接依赖 Repository)。另外我倾向 package-by-feature 而非 package-by-layer:包结构承担业务域划分,注解承担「层」的显式化,两者配合让边界既机器可查又人可读。

💻 全栈开发专家 ​

四个都是"把类交给容器",@Controller/@Service/@Repository 本质是 @Component 的语义化派生注解。区别在语义和附带能力:

  • @Component:通用组件,不属于下面三层的都用它
  • @Controller:Web 层,会被 RequestMappingHandlerMapping 识别注册为 handler——只有它能映射 URL,换成 @Component 接口直接 404
  • @Service:业务层标记,容器没给特殊功能,价值在可读性和 AOP 切点表达(within(@org.springframework.stereotype.Service *))
  • @Repository:持久层,附带持久层异常翻译——把各家 ORM/JDBC 异常统一转成 Spring 的 DataAccessException 体系,全局异常处理器才能一套代码处理多种存储异常

工程意义大于技术差异:分层注解让代码自解释;我还会配合 ArchUnit 在 CI 校验依赖方向(Controller 不许直接注入 Repository),扫描也可以按分层配置粒度。

真实教训:接手过一个全用 @Component 的老项目,没人分得清入口和工具类,review 成本翻倍——这就是语义化注解的价值,答题时讲这个故事比背区别有说服力。