《Spring Boot 入门》附录 A:常用注解速查

本附录把全书用到的 Spring Boot 注解按用途分成启动配置、依赖注入、生命周期、条件装配、Web、校验、数据事务、测试八类,每类一张表列出注解、作用、所在包与详见章节,末尾附一张 3.x 到 4.x 的注解与包名变更对照表,方便迁移时逐条核对。

本篇目标:把全书正文里散落的注解收拢成按用途分类的速查表,让你在写代码时能一眼查到「这个注解属于哪一层、在哪个包、对应哪一节」,并附一张 3.x 到 4.x 的变更对照表供迁移时核对。
适用版本:Spring Boot 4.1.x(Java 21)

附录 A 常用注解速查

正文 18 章把「为什么这样设计」讲透了,这一页只做一件事:把写代码时真正会去翻的注解压成表。建议第一次通读建立索引感,之后把它当案头卡片——写的时候不必回忆章节号,先在这里对号入座,再回正文看完整推导。

表里的「所在包」一列均按 4.x 口径给出。 4.0 起 Spring Boot 做了模块化重构,少数注解的包位置发生了变化(例如 @EntityScan 与 @PropertyMapping),这类差异集中列在本页末尾的「3.x → 4.x 注解与包名变更对照表」里,正文其余部分不再重复。

怎么用这张表

这张表按「注解在应用里扮演什么角色」分类,而不是按字母顺序。使用它的方式有三种:

  • 写代码时查包名:不记得某个注解该 import 哪个包,先在对应分类里找到它,再复制包名。
  • 读代码时反查:看到一个陌生注解,先在表里确认它属于哪一层,再翻到「详见章节」看它的完整行为。
  • 迁移时对照:从 3.x 项目迁到 4.x,先看末尾的变更对照表,把已移除或改名的注解一次性替换掉。

需要提醒的是,速查表只能帮你「定位」,不能帮你「理解」。一个注解为什么存在、什么时候该用、什么时候不该用,仍然要看正文。尤其是 @Transactional、@ConditionalOnMissingBean、@Validated 这几个,写法只有一行,但行为受很多条件影响,值得回到对应章节读透。

① 启动与配置类

这一组注解决定「应用从哪启动、哪些类算配置、自动配置从哪来」。

注解作用所在包详见章节
@SpringBootApplication组合注解:@SpringBootConfiguration + @EnableAutoConfiguration + @ComponentScanorg.springframework.boot.autoconfigure4.1
@Configuration声明一个配置类,其中的 @Bean 方法会被容器处理org.springframework.context.annotation5.1
@AutoConfiguration声明一个自动配置类,4.x 编写自定义自动配置的推荐写法org.springframework.boot.autoconfigure4.2、7.1
@ComponentScan指定组件扫描的包与过滤规则org.springframework.context.annotation4.1
@Import导入普通配置类、ImportSelector 或 ImportBeanDefinitionRegistrarorg.springframework.context.annotation5.1
@EnableConfigurationProperties让指定的 @ConfigurationProperties 类生效并被注册为 Beanorg.springframework.boot.context.properties6.2
@ConfigurationPropertiesScan扫描并注册指定包下的全部 @ConfigurationProperties 类org.springframework.boot.context.properties6.2

@SpringBootApplication 是入口注解,但它本身几乎不做事,真正的启动逻辑由它引入的 @EnableAutoConfiguration 触发——这一层在 4.2 节会拆开讲。写自定义自动配置时,优先用 @AutoConfiguration 而不是裸的 @Configuration,因为前者额外携带了「什么时候该加载」的元数据约定。

② 组件与依赖注入

这一组注解决定「哪些对象交给容器、它们之间怎么互相拿到」。

注解作用所在包详见章节
@Component通用组件,交给容器管理org.springframework.stereotype5.1
@Service语义化组件,标注服务层org.springframework.stereotype5.1
@Repository语义化组件,标注数据访问层,并触发持久化异常转换org.springframework.stereotype5.1、12.2
@Controller语义化组件,标注 MVC 控制器org.springframework.stereotype8.1
@RestController@Controller 加 @ResponseBody,返回值直接作为响应体org.springframework.web.bind.annotation8.1
@Bean在配置类中声明一个由方法返回的 Beanorg.springframework.context.annotation5.1
@Autowired按类型注入依赖,可用在构造器、字段或方法上org.springframework.beans.factory.annotation5.2
@Qualifier在多个同类型 Bean 中按名字限定org.springframework.beans.factory.annotation5.2
@Primary多个候选时优先选择该 Beanorg.springframework.context.annotation5.2
@Value注入单个配置值(${...} 或 SpEL #{...})org.springframework.beans.factory.annotation6.2
@Scope指定 Bean 作用域(singleton / prototype 等)org.springframework.context.annotation5.2
@Lazy延迟初始化,直到第一次被使用才创建org.springframework.context.annotation5.2

一个常见困惑是「@Component、@Service、@Repository 到底有什么区别」。答案是:在容器眼里它们几乎等价,差别只在语义与少数副作用——@Repository 会额外把底层异常翻译成 Spring 的数据访问异常体系。选哪个,看这个类在架构里扮演什么角色,而不是看功能。

③ 生命周期

注解作用所在包详见章节
@PostConstruct依赖注入完成后执行一次,用于初始化jakarta.annotation5.3
@PreDestroy容器销毁 Bean 之前执行一次,用于释放资源jakarta.annotation5.3

这两个注解来自 Jakarta 规范而非 Spring 自身,因此包里是 jakarta.annotation。它们的执行时机与构造器不同:构造器执行时依赖还没注入完,@PostConstruct 执行时依赖已经就绪。要真正搞清它们的顺序,需要理解 Bean 的生命周期回调,见 5.3 节。

④ 条件装配

这一组是自动配置的核心,决定「一个配置类到底要不要生效」。

注解作用所在包详见章节
@ConditionalOnClassclasspath 上存在指定类时生效org.springframework.boot.autoconfigure.condition4.3、7.1
@ConditionalOnMissingBean容器中不存在指定 Bean 时生效org.springframework.boot.autoconfigure.condition4.3、7.1
@ConditionalOnProperty指定配置属性满足条件时生效org.springframework.boot.autoconfigure.condition4.3
@ConditionalOnWebApplication是 Web 应用时生效,可限定 servlet 或 reactiveorg.springframework.boot.autoconfigure.condition4.3
@ConditionalOnBean容器中存在指定 Bean 时生效org.springframework.boot.autoconfigure.condition4.3

其中 @ConditionalOnMissingBean 是「可被用户覆盖的默认值」这一设计的关键:框架先声明一个默认实现,但只要你自己的配置里提供了同类型 Bean,默认实现就让位。理解这一点,就能明白为什么「我写了一个 ObjectMapper,为什么自动配置的没生效」——答案往往就在这里。

⑤ Web

注解作用所在包详见章节
@RequestMapping映射请求路径与方法,类级与方法级均可用org.springframework.web.bind.annotation8.1
@GetMapping / @PostMapping / @PutMapping / @DeleteMapping / @PatchMapping@RequestMapping 的 HTTP 方法快捷注解org.springframework.web.bind.annotation8.1
@PathVariable绑定 URI 模板变量org.springframework.web.bind.annotation8.2
@RequestParam绑定查询参数或表单字段org.springframework.web.bind.annotation8.2
@RequestBody把请求体反序列化为对象org.springframework.web.bind.annotation8.2
@RequestHeader绑定请求头org.springframework.web.bind.annotation8.2
@ResponseStatus指定方法或异常处理返回的 HTTP 状态码org.springframework.web.bind.annotation10.1
@ControllerAdvice全局增强所有控制器,处理异常、数据绑定与模型org.springframework.web.bind.annotation10.2
@RestControllerAdvice@ControllerAdvice 加 @ResponseBody,直接返回 JSONorg.springframework.web.bind.annotation10.2
@ExceptionHandler在增强类或控制器内处理指定异常org.springframework.web.bind.annotation10.1
@CrossOrigin允许跨域请求org.springframework.web.bind.annotation11.2

这组注解有一个共同点:它们大多只是「声明」,真正让它们生效的是 DispatcherServlet 启动时建立的那张映射表。所以当某个注解「没起作用」时,排查思路通常是「这个处理器有没有被注册到映射表里」,而不是「注解拼错了没有」。

⑥ 校验

注解作用所在包详见章节
@Valid触发对参数或字段的级联校验(Jakarta Bean Validation)jakarta.validation9.1
@ValidatedSpring 变体,支持分组校验,可用于类级org.springframework.validation.annotation9.1、9.3
@NotNull不能为 nulljakarta.validation.constraints9.1
@NotBlank字符串不能为 null 且去除空白后非空jakarta.validation.constraints9.1
@Size集合或字符串长度在指定范围内jakarta.validation.constraints9.1
@Pattern字符串必须匹配指定正则jakarta.validation.constraints9.1
@Email必须是合法邮箱格式jakarta.validation.constraints9.1
@Min / @Max数值下界 / 上界jakarta.validation.constraints9.1

@Valid 与 @Validated 的区别值得记住:前者是标准注解,负责「触发校验」;后者是 Spring 的扩展,额外支持「分组」与「方法级校验」。需要按场景分组校验时用 @Validated,见 9.3 节。

⑦ 数据与事务

注解作用所在包详见章节
@Entity声明一个 JPA 实体jakarta.persistence12.2
@Table指定映射的表名与约束jakarta.persistence12.2
@Id声明主键jakarta.persistence12.2
@GeneratedValue指定主键生成策略jakarta.persistence12.2
@Column指定列名、可空性、长度等映射细节jakarta.persistence12.2
@OneToMany一对多关联jakarta.persistence13.1
@ManyToOne多对一关联jakarta.persistence13.1
@JoinColumn指定关联使用的外键列jakarta.persistence13.1
@Query声明 JPQL 或原生 SQL 查询org.springframework.data.jpa.repository13.2
@Modifying标记 @Query 为更新或删除语句org.springframework.data.jpa.repository13.2
@Transactional声明事务边界与传播行为org.springframework.transaction.annotation14.1

JPA 注解来自 jakarta.persistence,与 Spring 无关;@Query 与 @Modifying 是 Spring Data JPA 的扩展;@Transactional 则来自 Spring 的事务模块。三者分属不同层次,混在一起用时要清楚每个注解「归谁管」——尤其 @Transactional 是基于代理生效的,同类内部调用不会触发它,这是 14.3 节要讲的经典坑。

⑧ 测试

注解作用所在包详见章节
@SpringBootTest加载完整应用上下文org.springframework.boot.test.context17.3
@WebMvcTest只加载 MVC 切片org.springframework.boot.test.autoconfigure.web.servlet17.2
@DataJpaTest只加载 JPA 与数据源切片org.springframework.boot.test.autoconfigure.orm.jpa17.2
@AutoConfigureMockMvc为测试装配 MockMvc,4.x 需显式添加org.springframework.boot.test.autoconfigure.web.servlet17.2
@MockitoBean用 Mockito 替身替换容器中的 Beanorg.springframework.test.context.bean.override.mockito17.1、17.2
@AutoConfigureTestRestTemplate为测试装配 TestRestTemplate,4.x 需显式添加org.springframework.boot.test.autoconfigure.web.client17.3

这里最容易踩坑的是 4.x 的一条行为变更:@SpringBootTest 不再自动附带 MockMvc 与 TestRestTemplate,需要 @AutoConfigureMockMvc、@AutoConfigureTestRestTemplate 显式声明。如果你从 3.x 迁移测试代码,测试类会因为找不到这些组件而报错,补上对应的 @AutoConfigure* 注解即可。

3.x → 4.x 注解与包名变更对照表

从 3.x 迁移到 4.x 时,下面这些注解要么被移除,要么改了名,要么挪了包。先按这张表把代码过一遍,再启动项目,能省下大量「编译不过却看不出原因」的时间。

3.x 写法4.x 写法说明
@MockBean@MockitoBean@MockBean 已在 4.x 移除,替换为 @MockitoBean
@SpyBean@MockitoSpyBean@SpyBean 已在 4.x 移除,替换为 @MockitoSpyBean
@JsonComponent@JacksonComponent随 Jackson 3 改名
@JsonMixin@JacksonMixin随 Jackson 3 改名
org.springframework.boot.autoconfigure.domain.EntityScanorg.springframework.boot.persistence.autoconfigure.EntityScan@EntityScan 包位置变化
org.springframework.boot.test.autoconfigure.properties.PropertyMappingorg.springframework.boot.test.context.PropertyMapping@PropertyMapping 包位置变化
org.springframework.lang.Nullableorg.jspecify.annotations.Nullable空安全注解迁移到 JSpecify

几条配套说明:

  • @MockitoBean / @MockitoSpyBean 有一条硬约束:它们只能用在测试类上,不能用在 @Configuration 类里。3.x 时代有人把 @MockBean 塞进配置类做「测试专用装配」,4.x 起这条路径被明确堵死。
  • @MockitoBean 的包路径也变了,从 Spring 自己的包迁到了 org.springframework.test.context.bean.override.mockito,迁移时留意 import。
  • @SpringBootTest 不再自带 MockMvc 与 TestRestTemplate:这虽然不算注解改名,但同样是「按旧写法照抄会失效」的典型,故一并提醒。
  • 空安全注解的迁移影响面很广:org.springframework.lang.Nullable 被 org.jspecify.annotations.Nullable 取代后,凡是显式 import 旧包的位置都要替换。如果只是用注解而不 import,通常不受影响。

下面是一段符合 4.x 口径的最小组合示例,把上面几类注解放在同一个文件里,供你对照包名:

package com.example.book;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/books")
public class BookController {

    private final BookService service;

    public BookController(BookService service) {
        this.service = service;
    }

    @GetMapping("/{id}")
    public Book find(@PathVariable Long id) {
        return service.findById(id);
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Book create(@Valid @RequestBody BookForm form) {
        return service.create(form);
    }

    public record BookForm(@NotBlank String title) {
    }
}

这段代码没有写 import 之外的任何 Spring 配置,但它已经覆盖了「控制器、路由、路径变量、请求体、校验、状态码、依赖注入」七件事——这正是 Spring Boot「约定优于配置」的直观体现。

注解的层次关系

Spring Boot 的注解可以粗略分成三层,理解层次有助于判断一个注解「归谁管」:

  • Spring 核心层(org.springframework.context / org.springframework.beans):@Configuration、@Bean、@Autowired、@Component 系列。它们管的是「对象如何被创建和装配」。
  • Spring Boot 层(org.springframework.boot):@SpringBootApplication、@AutoConfiguration、@ConditionalOn*、@ConfigurationProperties。它们管的是「在什么条件下自动装配什么」。
  • 规范层(jakarta.*):@PostConstruct、@Valid、@Entity 等。它们由 Jakarta 规范定义,Spring 只是支持它们。

分清这三层,你就能在遇到问题时快速判断「该去查 Spring 的文档,还是查 Jakarta 的文档」,也能理解为什么有些注解换一个框架依然可用。

几个容易混淆的注解

容易混淆的一对区别
@Component 与 @Bean前者标在类上,靠组件扫描发现;后者标在方法上,由配置类显式声明
@Controller 与 @RestController前者返回值默认当作视图名;后者当作响应体直接写出
@Valid 与 @Validated前者是标准触发注解;后者是 Spring 扩展,支持分组校验
@RequestParam 与 @PathVariable前者取查询串中的参数;后者取路径模板中的占位符
@Configuration 与 @AutoConfiguration后者是 4.x 编写自动配置的推荐注解,额外携带加载元数据
@Transactional 与 @Modifying前者管事务边界;后者只标记某个查询是写操作

一个配置类示例

注解速查之外,一个常见的困惑是「配置类该怎么写」。下面这段示例把启动与配置类那一组注解放在一起:

@AutoConfiguration
@EnableConfigurationProperties(BookProperties.class)
public class BookAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public BookFormatter bookFormatter(BookProperties properties) {
        return new BookFormatter(properties.getPrefix());
    }
}

配合下面的属性类:

@ConfigurationProperties(prefix = "app.book")
public class BookProperties {

    private String prefix = "book";

    // getter / setter 省略
}

@AutoConfiguration 让这个类被识别为自动配置;@EnableConfigurationProperties 让属性类生效;@ConditionalOnMissingBean 保证用户自定义的 BookFormatter 能覆盖这个默认值。这三者组合起来,就是一个最小可用的「可被覆盖的自动配置」。更完整的自定义 starter 流程见 7.2 节。

按场景查注解

比起按分类逐个回忆,从「我要做的事」出发反查往往更快:

我想做的事会用到的注解
暴露一个 GET 接口@RestController + @GetMapping + @PathVariable / @RequestParam
接收 JSON 请求体@PostMapping + @RequestBody
校验入参@Valid(或 @Validated)+ jakarta.validation.constraints.*
统一返回错误格式@RestControllerAdvice + @ExceptionHandler
允许前端跨域@CrossOrigin,或全局 CORS 配置
映射一张表@Entity + @Table + @Id + @GeneratedValue
写一个自定义查询@Query,更新语句再加 @Modifying
保证一组操作原子@Transactional
绑定一组配置@ConfigurationProperties + @EnableConfigurationProperties
提供可被覆盖的默认 Bean@Bean + @ConditionalOnMissingBean
写一个只测 Controller 的测试@WebMvcTest + @AutoConfigureMockMvc + @MockitoBean

这张表里的每一项,都能在正文里找到对应的完整示例与解释。速查表的作用是让你「想起还有这么一个注解」,至于它怎么用、什么时候会失效,仍要回到正文。

小结

  • 速查表的价值在于「定位」而非「理解」:先用表找到注解属于哪一层、在哪个包,再回正文看它的完整行为。
  • 八类里最需要理解而非记忆的是条件装配:@ConditionalOnMissingBean 决定了「默认值可被覆盖」这一核心设计。
  • 校验里分清 @Valid(触发)与 @Validated(分组),Web 里分清 @Controller(视图)与 @RestController(响应体)。
  • 数据层要记住注解分属三套体系:jakarta.persistence 管映射,Spring Data 管查询,Spring 管事务。
  • 迁移到 4.x 时,先按末尾的变更对照表把 @MockBean / @SpyBean 等替换掉,再启动项目——@MockBean 与 @SpyBean 在 4.x 已被移除。
  • 需要查配置项而不是注解时,请看附录 B 的配置速查;需要查构建脚本时,看附录 C 的 Maven 与 Gradle 对照。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「java」更多文章

  1. 《Spring Boot 入门》18.3 打包与运行
  2. 《Spring Boot 入门》18.2 实现
  3. 《Spring Boot 入门》18.1 需求与设计