Spring Boot 框架注解盘点

本文档面向已经具备 Java 基础和 Spring 基本概念的开发者,系统盘点 Spring Boot 框架自身提供的注解。讲解顺序遵循一个 Spring Boot 应用从启动到对外提供服务的真实调用链路:先从 main 方法入口的引导注解讲起,再进入自动配置类的加载与排序,然后是条件装配注解如何决定哪些 Bean 被注册,接着是外部化配置如何绑定到属性类,之后是 Actuator 端点注解如何暴露运维接口,最后是测试体系注解如何支撑分层测试。这样安排的目的是让读者在阅读每一组注解时,都能对应到 Spring Boot 启动流程中的某个具体阶段,形成循序渐进的认知链条。

需要特别说明的是,本文只盘点 Spring Boot 自身定义的注解,不涉及 Spring Framework 核心容器注解(如 @Configuration、@Component、@Bean、@Autowired、@Conditional 等),也不涉及 Spring MVC、Spring Data、Spring Security 等其他子项目的注解。当某个 Spring Boot 注解内部组合了 Spring Framework 注解时,会简要提及这种组合关系,但不会展开讲解被组合注解本身的语义。

启动入口注解

启动入口注解是 Spring Boot 应用启动流程的起点。当开发者调用 SpringApplication.run 方法时,框架首先需要识别哪个类是主配置类,然后基于这个类完成组件扫描、自动配置导入等一系列动作。这一组注解正是用来标记主配置类并触发后续流程的。

@SpringBootApplication

@SpringBootApplication 是 Spring Boot 最核心的入口注解,通常标注在含有 main 方法的引导类上。它本身是一个组合注解,内部使用 @SpringBootConfiguration、@EnableAutoConfiguration 和 @ComponentScan 三个注解来标注自己,因此一次标注就同时具备了配置类身份、自动配置开启能力和组件扫描能力。这种组合设计让开发者无需在引导类上堆叠多个注解,一个注解即可完成传统 Spring 应用中需要大量 XML 或多个注解才能完成的工作。

该注解提供了几个常用的属性用于精细控制行为。exclude 属性接受一个 Class 数组,用于排除特定的自动配置类,当某个自动配置类不符合当前项目需求时可以通过它关闭。excludeName 属性接受全限定类名字符串数组,作用与 exclude 相同,适用于类路径上不一定存在的场景。scanBasePackageClasses 和 scanBasePackages 属性用于显式指定组件扫描的根包,当引导类所在包结构无法覆盖所有业务组件时需要显式声明。proxyBeanMethods 属性用于控制配置类是否使用 CGLIB 代理,默认为 true,在 GraalVM 原生镜像场景下通常设置为 false 以减少运行时开销。

从启动流程角度看,当 SpringApplication.run 执行时,会通过 BeanDefinitionReader 读取主配置类上的注解元数据,识别出 @SpringBootApplication 后,其元注解 @EnableAutoConfiguration 会触发 AutoConfigurationImportSelector 的执行,进而从 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中加载所有候选自动配置类。这一步是 Spring Boot 自动装配机制的真正起点。

@SpringBootConfiguration

@SpringBootConfiguration 是 @SpringBootApplication 的元注解之一,用于标识一个类是 Spring Boot 应用的主配置类。它的语义与 Spring Framework 的 @Configuration 几乎一致,区别在于它通过 @Indexed 元注解标记,使得 Spring Boot 在启动时能够更高效地定位配置类,而不必依赖完整的组件扫描。在绝大多数项目中,开发者不需要直接使用 @SpringBootConfiguration,因为 @SpringBootApplication 已经包含了它。

该注解主要用于测试场景或需要显式声明配置类的场景。在集成测试中,如果不想使用 @SpringBootApplication 的全部能力,而只想加载部分配置,可以单独使用 @SpringBootConfiguration 标注一个测试专用的配置类,再配合 @EnableAutoConfiguration 或 @Import 完成定制化加载。proxyBeanMethods 属性与 @Configuration 中同名属性语义一致,控制 @Bean 方法是否被代理以支持 inter-bean references。

从调用链路看,@SpringBootConfiguration 的存在使得 Spring Boot 能够区分普通 @Configuration 类和应用主配置类。在 ApplicationContext 刷新阶段,主配置类会被作为 BeanDefinitionRegistry 的注册入口,其内部声明的 @Bean 方法以及通过 @Import 导入的配置都会被纳入容器管理。

@EnableAutoConfiguration

@EnableAutoConfiguration 是触发自动装配机制的核心注解,通常作为 @SpringBootApplication 的元注解出现,也可以单独使用。它的核心作用是通过 @Import 导入 AutoConfigurationImportSelector,后者在容器初始化阶段读取候选自动配置类列表,并根据条件过滤后注册到容器中。

该注解提供了 exclude 和 excludeName 两个属性,用于排除不需要的自动配置类。这种排除机制在解决自动配置冲突时非常有用,例如项目同时引入了 Web 和数据访问依赖,但只想启用其中一部分能力时,可以通过 exclude 精确关闭某些自动配置。从 Spring Boot 3.0 开始,候选自动配置类的来源从 spring.factories 文件迁移到了独立的 AutoConfiguration.imports 文件,这一变化使得自动配置类的加载更加清晰,也减少了 spring.factories 文件的膨胀问题。

在启动调用链中,AutoConfigurationImportSelector 实现了 DeferredImportSelector 接口,这意味着它的执行会被推迟到所有 @Configuration 类加载完成之后。这种延迟执行的设计保证了用户自定义的配置类优先于自动配置类被处理,从而使得 @ConditionalOnMissingBean 等条件注解能够正确判断容器中是否已经存在用户自定义的 Bean。

@AutoConfigurationPackage

@AutoConfigurationPackage 是 @EnableAutoConfiguration 内部通过 @Import 导入的注解,用于将主配置类所在包注册到 AutoConfigurationPackages 中。它的作用是记录应用的基础包路径,供后续 JPA Entity 扫描、Spring Data Repository 扫描等场景使用。当没有显式指定 basePackages 或 basePackageClasses 时,默认注册被注解类所在的包。

该注解通过 @Import 导入 AutoConfigurationPackages.Registrar,后者实现了 ImportBeanDefinitionRegistrar,在容器启动时向 BeanDefinitionRegistry 注册一个存储基础包路径的 Bean。这个 Bean 的类型是 BeanFactory 后续查询基础包的入口。basePackages 属性接受字符串数组,basePackageClasses 属性接受 Class 数组,两者都是类型安全的替代方案,推荐使用 basePackageClasses 以避免字符串硬编码带来的重构风险。

从调用链路看,@AutoConfigurationPackage 的执行时机早于 AutoConfigurationImportSelector 的自动配置类导入,因为它通过 ImportBeanDefinitionRegistrar 直接注册,而后者通过 DeferredImportSelector 延迟执行。这种时序保证了 JPA 等模块在扫描 Entity 时能够正确获取到基础包路径。

自动配置类注解

当 @EnableAutoConfiguration 触发自动配置类加载后,框架需要识别哪些类是自动配置类,并决定它们的加载顺序。这一组注解用于标注自动配置类本身,以及声明自动配置类之间的相对顺序。它们主要面向开发自定义 Starter 或扩展 Spring Boot 自动配置的场景。

@AutoConfiguration

@AutoConfiguration 用于标注一个类是自动配置类,是 Spring Boot 2.7 引入的注解,用于替代此前直接在 spring.factories 中通过 @Configuration 标注类的做法。它内部组合了 @Configuration(proxyBeanMethods = false)、@AutoConfigureBefore 和 @AutoConfigureAfter,因此一个注解即可声明自动配置类身份并指定与其他自动配置类的相对顺序。

proxyBeanMethods 被强制设置为 false 是自动配置类与普通配置类的重要区别。自动配置类通常不依赖 inter-bean references,关闭 CGLIB 代理可以减少启动时的字节码生成开销,提升启动速度,也更适合 GraalVM 原生镜像场景。该注解的 before、beforeName、after、afterName 属性分别用于指定当前自动配置类应在哪些类之前或之后加载,这些属性与独立的 @AutoConfigureBefore 和 @AutoConfigureAfter 注解语义一致,但通过组合方式提供了更紧凑的声明形式。

从加载机制看,标注了 @AutoConfiguration 的类需要被注册到 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中,框架通过 ImportCandidates 机制读取该文件并加载所有列出的自动配置类。AutoConfigurationImportSelector 在执行时会读取这个文件,将候选类交给 OnBeanCondition、OnClassCondition 等条件处理器进行过滤,最终只有满足条件的自动配置类才会被注册到容器中。

@AutoConfigureBefore

@AutoConfigureBefore 用于声明当前自动配置类应在指定的其他自动配置类之前加载。它接受 value 和 name 两个属性,value 是 Class 数组,name 是全限定类名字符串数组。当被引用的类可能不在类路径上时,应使用 name 属性以避免 ClassNotFoundException。

需要理解的是,这里的"之前加载"指的是 BeanDefinition 注册顺序,而非 Bean 实例化顺序。Bean 的实际创建顺序由依赖关系和 @DependsOn 决定,与自动配置类的加载顺序没有直接关系。这一注解主要用于解决自动配置类之间的声明顺序依赖,例如某个自动配置类需要在另一个自动配置类注册的 BeanDefinition 之上做后置处理时,需要保证加载顺序。

从执行机制看,@AutoConfigureBefore 的解析发生在 AutoConfigurationImportSelector 排序阶段。框架会读取所有候选自动配置类上的 @AutoConfigureBefore、@AutoConfigureAfter 和 @AutoConfigureOrder 注解,构建一个有向图,然后通过拓扑排序确定最终的加载顺序。如果出现循环依赖,框架会抛出异常并提示开发者修正。

@AutoConfigureAfter

@AutoConfigureAfter 与 @AutoConfigureBefore 语义对称,用于声明当前自动配置类应在指定的其他自动配置类之后加载。它同样接受 value 和 name 两个属性,使用方式与 @AutoConfigureBefore 完全一致。

该注解的典型应用场景是当某个自动配置类的条件判断依赖于另一个自动配置类注册的 Bean 是否存在时。例如,自动配置类 A 使用了 @ConditionalOnBean,判断容器中是否存在某个 Bean,而该 Bean 由自动配置类 B 注册,那么 A 必须在 B 之后加载,否则 @ConditionalOnBean 会因为 B 尚未加载而误判为不匹配。通过 @AutoConfigureAfter 显式声明这种依赖关系,可以避免条件判断的时序问题。

从排序算法看,@AutoConfigureAfter 与 @AutoConfigureBefore 共同参与有向图的构建。框架在解析这些注解时,会将每个 Before 关系转化为一条从当前类指向目标类的有向边,将每个 After 关系转化为一条从目标类指向当前类的有向边,然后通过拓扑排序得到全局顺序。这种设计使得复杂的顺序声明能够被统一处理。

@AutoConfigureOrder

@AutoConfigureOrder 是 Spring Boot 自动配置专用的顺序注解,语义类似于 Spring Framework 的 @Order,但作用范围限定在自动配置类之间。它接受一个 int 类型的 value 属性,默认值为 0,数值越小优先级越高,越早被加载。

该注解与 @AutoConfigureBefore 和 @AutoConfigureAfter 的区别在于,前者是绝对顺序声明,后两者是相对顺序声明。当多个自动配置类之间没有明确的相对依赖关系,但需要控制整体加载顺序时,可以使用 @AutoConfigureOrder。例如,希望某个基础自动配置类在大多数其他类之前加载,可以给它一个较小的 order 值。

从排序优先级看,@AutoConfigureOrder 的优先级低于 @AutoConfigureBefore 和 @AutoConfigureAfter。框架在排序时,先处理 Before 和 After 关系构建有向图,再使用 @AutoConfigureOrder 的值作为同层节点的排序依据。这种设计保证了相对顺序声明的精确性,同时允许通过 order 值进行粗粒度的顺序调整。DEFAULT_ORDER 常量定义了默认顺序值,供框架内部使用。

条件装配注解

条件装配注解决定了哪些自动配置类和 Bean 会被真正注册到容器中。它们都基于 Spring Framework 的 @Conditional 机制,通过对应的 Condition 实现类在容器启动阶段进行条件判断。这一组注解是 Spring Boot 自动装配能够做到"约定优于配置"的关键,使得同一份代码在不同环境下能够呈现不同的行为。

@ConditionalOnClass

@ConditionalOnClass 用于判断指定的类是否存在于类路径上,只有当所有指定类都存在时,被标注的配置类或 Bean 才会被注册。它接受 value 和 name 两个属性,value 是 Class 数组,name 是全限定类名字符串数组。当被引用的类可能不在类路径上时,必须使用 name 属性,否则会触发 ClassNotFoundException。

该注解的判断通过 OnClassCondition 实现,框架使用 ASM 字节码读取注解元数据,而不是通过反射加载类,这一设计使得条件判断不会触发类的实际加载。这一点对于自动配置类尤为重要,因为自动配置类可能引用了项目并未引入的第三方类,如果通过反射判断会导致 ClassNotFoundException。从使用场景看,@ConditionalOnClass 通常用于声明某个自动配置类仅在某个第三方库被引入时才生效,例如 DataSourceAutoConfiguration 仅在 javax.sql.DataSource 类存在时才加载。

需要注意的是,在 @Bean 方法上使用 @ConditionalOnClass 时需要特别小心。因为 @Bean 方法的返回类型会被 JVM 加载,如果返回类型引用的类不存在,会在条件判断之前就抛出异常。解决方法是将这种 Bean 拆分到独立的内部 @Configuration 类中,让条件注解作用于配置类而非方法,从而利用 ASM 读取避免类加载。

@ConditionalOnMissingClass

@ConditionalOnMissingClass 与 @ConditionalOnClass 语义相反,用于判断指定的类是否不存在于类路径上,只有当所有指定类都不存在时,被标注的配置类或 Bean 才会被注册。它只接受 value 一个属性,类型为 String 数组,因为如果使用 Class 类型引用一个不存在的类会导致编译错误。

该注解同样通过 OnClassCondition 实现,使用 ASM 字节码读取避免类加载。典型应用场景是提供默认实现:当用户没有引入某个第三方库时,框架提供一个简化的默认实现;当用户引入了该库时,默认实现被跳过,转而加载与该库集成的实现。这种模式使得 Spring Boot 能够在不同依赖组合下提供合理的行为,而无需开发者手动配置。

从条件判断时序看,@ConditionalOnMissingClass 与 @ConditionalOnClass 在同一阶段执行,都发生在 ConfigurationClassParser 解析配置类阶段。框架会先读取所有候选配置类的条件注解,然后批量执行条件判断,避免重复扫描。这种批量处理机制提升了启动效率,特别是在自动配置类数量较多的场景下。

@ConditionalOnBean

@ConditionalOnBean 用于判断容器中是否存在指定类型或名称的 Bean,只有当所有指定 Bean 都存在时,被标注的配置类或 Bean 才会被注册。它提供了 value、type、annotation、name、search 等多个属性,value 和 type 用于指定 Bean 类型,annotation 用于指定 Bean 上必须存在的注解,name 用于指定 Bean 名称,search 用于控制搜索范围(当前容器、父容器或全部)。

该注解通过 OnBeanCondition 实现,条件判断发生在配置类处理阶段。需要注意的是,由于 Bean 的注册是渐进式的,@ConditionalOnBean 的判断结果会受到 Bean 注册顺序的影响。如果被依赖的 Bean 由一个尚未处理的配置类注册,那么 @ConditionalOnBean 可能会误判为不匹配。这也是为什么需要配合 @AutoConfigureAfter 等顺序注解使用,确保被依赖的自动配置类先加载。

从使用建议看,@ConditionalOnBean 应该谨慎使用,特别是在自动配置类之间。官方推荐优先使用 @ConditionalOnSingleCandidate 或 @ConditionalOnMissingBean,因为它们的语义更明确,受顺序影响更小。@ConditionalOnBean 更适合用于用户自定义配置类中,判断框架提供的某些 Bean 是否存在,从而决定是否注册补充 Bean。

@ConditionalOnMissingBean

@ConditionalOnMissingBean 用于判断容器中是否不存在指定类型或名称的 Bean,只有当所有指定 Bean 都不存在时,被标注的配置类或 Bean 才会被注册。它是 Spring Boot 自动配置中最常用的条件注解之一,用于实现"用户优先"的装配策略:框架提供默认实现,但当用户自定义了同类型 Bean 时,默认实现被跳过。

该注解的属性与 @ConditionalOnBean 类似,包括 value、type、annotation、name、ignored、ignoredType、parameterizedContainer 等。ignored 和 ignoredType 用于排除某些特定 Bean 不参与判断,parameterizedContainer 用于处理泛型 Bean 的匹配。从执行机制看,OnBeanCondition 在判断时会扫描已注册的所有 BeanDefinition,包括通过组件扫描、@Bean 方法、自动配置等途径注册的 Bean。

@ConditionalOnMissingBean 的有效性依赖于自动配置类的加载顺序晚于用户配置类。这正是 @EnableAutoConfiguration 通过 DeferredImportSelector 延迟执行的设计目的:用户配置类先被处理,用户自定义的 Bean 先注册到容器,然后自动配置类加载时 @ConditionalOnMissingBean 才能正确判断。如果顺序颠倒,自动配置类的默认 Bean 会先注册,用户的自定义 Bean 反而会被跳过,导致行为与预期不符。

@ConditionalOnSingleCandidate

@ConditionalOnSingleCandidate 用于判断容器中是否存在指定类型的 Bean,并且该类型的 Bean 在容器中只有一个(或虽然有多个但有一个 @Primary 标注的主候选)。只有满足这一条件时,被标注的配置类或 Bean 才会被注册。它接受 value 和 type 两个属性,用于指定 Bean 类型,以及 search 属性控制搜索范围。

该注解通过 OnBeanCondition 实现,是 @ConditionalOnBean 的增强版本。它的典型应用场景是当某个 Bean 需要注入一个特定类型的依赖,但希望避免歧义性问题时。例如,某个自动配置类需要注入一个 DataSource,但容器中可能存在多个 DataSource,此时使用 @ConditionalOnSingleCandidate 可以保证只有当存在唯一主候选 DataSource 时才加载该配置类,避免歧义注入导致的启动失败。

从语义上看,@ConditionalOnSingleCandidate 比 @ConditionalOnBean 更严格,它不仅要求 Bean 存在,还要求唯一性。这种严格性使得它在处理可选依赖场景时更加安全,特别是在自动配置类之间,能够避免因多个候选导致的装配歧义。当容器中有多个同类型 Bean 但其中一个标注了 @Primary 时,该注解仍然会匹配,因为 @Primary 解决了歧义问题。

@ConditionalOnProperty

@ConditionalOnProperty 用于判断是否满足指定的属性条件,只有当配置属性满足要求时,被标注的配置类或 Bean 才会被注册。它提供了 prefix、name、value、havingValue、matchIfMissing 等属性。prefix 用于指定属性名前缀,name 和 value 用于指定属性名(两者互为别名),havingValue 用于指定属性必须等于的值,matchIfMissing 用于指定当属性不存在时是否匹配,默认为 false。

该注解通过 OnPropertyCondition 实现,条件判断读取 Environment 中的属性值。属性名通过 prefix + name 拼接而成,例如 prefix 为 "spring.datasource" 且 name 为 "enabled" 时,实际读取的属性名为 "spring.datasource.enabled"。havingValue 用于精确匹配属性值,如果未指定 havingValue,则只要属性存在且不等于 false 即视为匹配。matchIfMissing 控制属性缺失时的行为,设置为 true 时表示属性未配置也视为匹配。

从使用场景看,@ConditionalOnProperty 是实现"开关式"自动配置的常用手段。例如,某个监控功能可以通过 spring.management.metrics.enabled=false 关闭,对应的自动配置类使用 @ConditionalOnProperty(prefix = "spring.management.metrics", name = "enabled", havingValue = "true", matchIfMissing = true) 标注,这样默认开启但允许通过配置关闭。这种模式使得框架行为高度可配置,同时保持了合理的默认值。

@ConditionalOnResource

@ConditionalOnResource 用于判断指定的资源是否存在于类路径上,只有当所有指定资源都存在时,被标注的配置类或 Bean 才会被注册。它只接受 resources 一个属性,类型为 String 数组,资源路径遵循 Spring 的资源约定,例如 "classpath:logback.xml" 或 "file:/etc/app/config.properties"。

该注解通过 OnResourceCondition 实现,条件判断通过 ResourceLoader 加载指定资源,如果资源能够被解析则视为存在。典型应用场景是当某个配置类依赖特定的配置文件或资源存在时才加载,例如只有当 classpath 下存在 ehcache.xml 时才注册 EhCache 相关的 Bean,否则跳过。

从执行机制看,@ConditionalOnResource 的判断发生在配置类处理阶段,与 @ConditionalOnClass 类似,都是基于类路径或资源存在性的静态判断,不依赖容器状态。这种静态判断的特性使得它的执行时序非常早,不会受到 Bean 注册顺序的影响。需要注意的是,资源路径的解析依赖于 ResourceLoader 的实现,在 Web 应用中默认使用 ServletContextResourceLoader,能够识别 WEB-INF 目录下的资源。

@ConditionalOnWebApplication

@ConditionalOnWebApplication 用于判断当前应用是否为 Web 应用,只有当应用类型为 SERVLET 或 REACTIVE 时才匹配。它接受 type 属性,类型为 ConditionalOnWebApplication.Type 枚举,可选值为 SERVLET、REACTIVE、ANY,默认为 ANY,表示任意 Web 应用类型都匹配。

该注解通过 OnWebApplicationCondition 实现,条件判断基于 SpringApplication 在启动时确定的 WebApplicationType。WebApplicationType 的判定通过检查类路径上是否存在相关类来完成:如果存在 org.springframework.web.context.support.GenericWebApplicationContext 则认为是 SERVLET 类型,如果存在 org.springframework.web.reactive.DispatcherHandler 则认为是 REACTIVE 类型,如果两者都不存在则是 NONE 类型。

从使用场景看,@ConditionalOnWebApplication 用于区分 Web 和非 Web 环境。例如,WebMvcAutoConfiguration 仅在 SERVLET 类型应用中加载,WebFluxAutoConfiguration 仅在 REACTIVE 类型应用中加载,而某些通用的 Web 相关配置可以使用 type = ANY 在两种 Web 类型下都加载。这种区分使得同一份 Spring Boot 代码能够同时支持 Servlet 栈和 Reactive 栈,开发者可以根据需要选择技术栈。

@ConditionalOnNotWebApplication

@ConditionalOnNotWebApplication 与 @ConditionalOnWebApplication 语义相反,用于判断当前应用是否为非 Web 应用,只有当应用类型为 NONE 时才匹配。它不接受任何属性,是一个纯粹的开关式条件注解。

该注解同样通过 OnWebApplicationCondition 实现,判断逻辑与 @ConditionalOnWebApplication 一致,只是匹配条件取反。典型应用场景是当某些配置类仅适用于非 Web 环境(例如命令行工具、批处理任务)时,使用该注解确保它们不会在 Web 应用中被加载,避免引入不必要的 Web 依赖或行为。

从设计角度看,@ConditionalOnNotWebApplication 与 @ConditionalOnWebApplication 共同构成了对应用类型的完整覆盖,使得自动配置类能够根据应用类型精确地选择加载策略。这种基于应用类型的条件装配是 Spring Boot 实现"一份代码多种部署形态"的重要基础。

@ConditionalOnExpression

@ConditionalOnExpression 用于判断指定的 SpEL 表达式是否为 true,只有当表达式求值结果为 true 时,被标注的配置类或 Bean 才会被注册。它接受 value 一个属性,类型为 String,即 SpEL 表达式。

该注解通过 OnExpressionCondition 实现,条件判断通过 StandardEnvironment 和 BeanExpressionResolver 对 SpEL 表达式求值。表达式可以引用 Environment 中的属性,例如 "${spring.datasource.url:default}" 表示读取 spring.datasource.url 属性,如果不存在则使用 default。表达式也可以使用 SpEL 的完整语法,包括方法调用、运算符、正则匹配等。

从使用场景看,@ConditionalOnExpression 适用于需要复合条件判断的场景,当 @ConditionalOnProperty 等单一条件注解无法表达复杂逻辑时使用。例如,只有当 spring.datasource.url 属性存在且 spring.datasource.driver-class-name 属性等于某个值时才加载某个配置类,可以使用 @ConditionalOnExpression("${spring.datasource.url:#{null}} != null and '${spring.datasource.driver-class-name}' == 'com.mysql.cj.jdbc.Driver'")。需要注意的是,复杂的 SpEL 表达式可读性较差,应优先考虑使用多个简单条件注解的组合。

@ConditionalOnJava

@ConditionalOnJava 用于判断当前 JVM 的 Java 版本是否满足要求,只有当 Java 版本符合条件时,被标注的配置类或 Bean 才会被注册。它接受 value 和 range 两个属性,value 类型为 ConditionalOnJava.Range 枚举,可选值为 EQUAL_OR_NEWER、OLDER_THAN,range 类型为 JavaVersion 枚举,表示目标 Java 版本。

该注解通过 OnJavaCondition 实现,条件判断通过读取 java.version 系统属性确定当前 JVM 版本,然后与 range 指定的版本进行比较。Range.EQUAL_OR_NEWER 表示当前版本等于或更新于指定版本时匹配,Range.OLDER_THAN 表示当前版本早于指定版本时匹配。

从使用场景看,@ConditionalOnJava 用于处理不同 Java 版本之间的 API 差异。例如,某个自动配置类使用了 Java 11 才有的 API,可以通过 @ConditionalOnJava(value = ConditionalOnJava.Range.EQUAL_OR_NEWER, range = JavaVersion.ELEVEN) 标注,确保它只在 Java 11 及以上版本中加载,避免在低版本上因 API 不存在而启动失败。这种基于版本的条件装配使得 Spring Boot 能够同时支持多个 Java 版本,同时利用新版本的特性。

@ConditionalOnCloudPlatform

@ConditionalOnCloudPlatform 用于判断当前应用是否运行在指定的云平台上,只有当运行在指定平台上时才匹配。它接受 value 一个属性,类型为 CloudPlatform 枚举,可选值包括 CLOUD_FOUNDRY、HEROKU、SAP、KUBERNETES、AZURE_APP_SERVICE 等。

该注解通过 OnCloudPlatformCondition 实现,条件判断通过检测特定的环境变量或系统属性来确定当前运行的云平台。例如,KUBERNETES 平台通过检测是否存在 KUBERNETES_SERVICE_HOST 和 KUBERNETES_SERVICE_PORT 环境变量来判定,CLOUD_FOUNDRY 通过检测是否存在 VCAP_APPLICATION 和 VCAP_SERVICES 环境变量来判定。

从使用场景看,@ConditionalOnCloudPlatform 用于在云原生部署场景下提供平台特定的配置。例如,当应用部署在 Kubernetes 上时,可能需要使用不同的服务发现机制或配置加载策略,通过该注解可以精确识别平台并加载对应的配置类。这种基于平台的条件装配使得同一份代码能够在不同云平台上以最优方式运行,而无需修改代码或配置。

@ConditionalOnJndi

@ConditionalOnJndi 用于判断指定的 JNDI 资源是否存在,只有当所有指定 JNDI 资源都存在时才匹配。它接受 value 一个属性,类型为 String 数组,表示 JNDI 名称,例如 "java:comp/env/jdbc/myDataSource"。

该注解通过 OnJndiCondition 实现,条件判断通过 JndiLocatorDelegate 查找指定的 JNDI 资源。需要注意的是,JNDI 查找依赖于运行环境是否提供了 JNDI 上下文,在嵌入式容器或独立应用中通常不可用,只有在部署到外部容器(如 Tomcat、WebSphere)时才有效。

从使用场景看,@ConditionalOnJndi 主要用于传统的 JEE 部署场景,当应用需要使用容器提供的数据源、JMS 连接工厂等资源时,通过该注解判断 JNDI 资源是否存在,从而决定是否加载相关配置。在现代 Spring Boot 应用中,由于更倾向于使用嵌入式容器和自动配置的数据源,该注解的使用频率较低,但在需要与外部容器集成的场景下仍然有用。

@ConditionalOnWarDeployment

@ConditionalOnWarDeployment 用于判断当前应用是否以 WAR 包形式部署到外部 Servlet 容器,只有当应用是 WAR 部署时才匹配。它不接受任何属性,是一个纯粹的部署形态判断注解。

该注解通过 OnWarDeploymentCondition 实现,条件判断通过检测是否存在特定的 ServletContext 属性来确定。当应用打包为 WAR 并部署到外部容器时,SpringBootApplicationInitializer 会设置一个标记属性,OnWarDeploymentCondition 通过检测该属性来判断部署形态。

从使用场景看,@ConditionalOnWarDeployment 用于区分嵌入式部署和 WAR 部署两种形态。某些配置在嵌入式部署下有意义(例如嵌入式容器的端口配置),但在 WAR 部署下应该由外部容器管理,此时可以通过该注解跳过这些配置。这种区分使得 Spring Boot 应用能够灵活选择部署形态,同时保持配置的合理性。

@ConditionalOnThreading

@ConditionalOnThreading 用于判断当前应用的线程模型是否满足要求,只有当线程模型匹配时才注册对应的配置类或 Bean。它接受 value 一个属性,类型为 Threading 枚举,可选值为 PLATFORM、VIRTUAL,分别表示平台线程和虚拟线程。

该注解通过 OnThreadingCondition 实现,条件判断基于是否启用了虚拟线程。当 spring.threads.virtual.enabled 属性设置为 true 且 JVM 支持虚拟线程时,Threading 为 VIRTUAL,否则为 PLATFORM。这是 Spring Boot 3.2 引入的注解,用于适配 Java 21 的虚拟线程特性。

从使用场景看,@ConditionalOnThreading 用于根据线程模型选择不同的实现。例如,某些组件在虚拟线程环境下可以使用更简单的同步实现(因为虚拟线程不会阻塞平台线程),而在平台线程环境下需要使用异步实现以避免阻塞,通过该注解可以自动选择合适的实现。这种基于线程模型的条件装配使得 Spring Boot 能够充分利用虚拟线程带来的简化编程模型。

@ConditionalOnRepositoryType

@ConditionalOnRepositoryType 用于判断指定类型的 Spring Data Repository 是否被启用,只有当对应类型的 Repository 存在时才匹配。它接受 repository 和 value 两个属性,repository 类型为 Class>,表示 Repository 接口类型,value 类型为 RepositoryType 枚举,可选值为 IMPERATIVE、REACTIVE。

该注解通过 OnRepositoryTypeCondition 实现,条件判断基于类路径上是否存在对应 Spring Data 模块的特定类,以及是否启用了响应式 Repository 支持。例如,当 repository 为 Repository.class 且 value 为 IMPERATIVE 时,判断类路径上是否存在 Spring Data Commons 的命令式 Repository 支持;当 value 为 REACTIVE 时,判断是否存在 Reactive Repository 支持。

从使用场景看,@ConditionalOnRepositoryType 用于在 Spring Data 多模块共存场景下精确选择配置。例如,当项目同时引入了 Spring Data JPA 和 Spring Data MongoDB Reactive 时,通过该注解可以分别加载命令式和响应式的 Repository 配置,避免冲突。这种基于 Repository 类型的条件装配使得 Spring Boot 能够支持复杂的数据访问组合。

配置属性绑定注解

配置属性绑定注解用于将外部化配置(application.properties、环境变量、命令行参数等)绑定到类型安全的 Java 对象。这一组注解是 Spring Boot 外部化配置体系的核心,使得开发者可以用强类型方式访问配置,避免在代码中散落字符串键值。

@ConfigurationProperties

@ConfigurationProperties 用于将指定前缀下的配置属性绑定到标注类的字段上。它接受 prefix 或 value 属性(两者互为别名)指定属性前缀,ignoreUnknownFields 属性控制是否忽略未知字段(默认为 true),ignoreInvalidFields 属性控制是否忽略类型不匹配的字段(默认为 false)。

该注解通常标注在标注了 @Component 或 @ConfigurationPropertiesScan 的类上,或者通过 @EnableConfigurationProperties 显式启用。绑定过程通过 ConfigurationPropertiesBinder 完成,它从 Environment 中读取属性,通过 JavaBean 的 setter 方法或构造器注入到目标对象。绑定支持嵌套对象、集合、Map、Duration、Period 等复杂数据类型,并且支持 JSR-303 校验注解(当类路径上存在校验实现时)。

从使用场景看,@ConfigurationProperties 是替代 @Value 的推荐方案,特别是当配置项较多或需要分组管理时。例如,数据源配置可以定义一个 DataSourceProperties 类,标注 @ConfigurationProperties(prefix = "spring.datasource"),然后在代码中通过依赖注入 DataSourceProperties 来访问配置,而不是在每个使用处写 @Value("${spring.datasource.url}")。这种强类型方式提升了代码可读性和可维护性,也便于 IDE 重构。

@ConfigurationPropertiesScan

@ConfigurationPropertiesScan 用于自动扫描并注册 @ConfigurationProperties 标注的类。它接受 basePackages 或 basePackageClasses 属性指定扫描包,默认扫描被注解类所在包及其子包。该注解是 @ConfigurationProperties 的便捷启用方式,无需在每个属性类上额外标注 @Component,也无需使用 @EnableConfigurationProperties 逐个声明。

该注解通过 @Import 导入 ConfigurationPropertiesScanRegistrar,后者实现 ImportBeanDefinitionRegistrar,在容器启动时扫描指定包下的 @ConfigurationProperties 类并注册为 Bean。扫描过程使用 ClassPathScanningCandidateComponentProvider,结合 @ConfigurationProperties 注解的元数据进行过滤。

从使用场景看,@ConfigurationPropertiesScan 适合属性类较多的项目,可以一次性启用所有属性类的自动注册,避免逐个声明。通常标注在主配置类上,与 @SpringBootApplication 一起使用。需要注意的是,扫描会注册所有匹配的类,如果某些属性类不希望被自动注册,应避免放在扫描包下或使用 @EnableConfigurationProperties 显式声明。

@EnableConfigurationProperties

@EnableConfigurationProperties 用于显式启用指定的 @ConfigurationProperties 类,将它们注册为 Spring Bean。它接受 value 一个属性,类型为 Class 数组,列出要启用的属性类。这是 @ConfigurationPropertiesScan 之外的另一种启用方式,更加显式和精确。

该注解通过 @Import 导入 EnableConfigurationPropertiesRegistrar,后者实现 ImportBeanDefinitionRegistrar,在容器启动时为每个指定的属性类注册一个 BeanDefinition。注册的 Bean 名称默认为属性类的全限定类名,类型为属性类本身。同时,框架会注册一个 ConfigurationPropertiesBindingPostProcessor Bean,用于在 Bean 初始化阶段完成属性绑定。

从使用场景看,@EnableConfigurationProperties 适合需要精确控制哪些属性类被注册的场景,特别是在自动配置类中。例如,DataSourceAutoConfiguration 使用 @EnableConfigurationProperties(DataSourceProperties.class) 显式启用数据源属性类,确保只有该属性类被注册,而不会扫描整个包。这种显式声明方式使得自动配置类的依赖关系清晰,也避免了不必要的扫描开销。

@ConfigurationPropertiesBinding

@ConfigurationPropertiesBinding 用于标注一个 Converter,使其被注册为配置属性绑定的转换器,用于将字符串配置值转换为目标类型。它是一个标记注解,不接受任何属性,标注在实现 org.springframework.core.convert.converter.Converter 接口的类上。

该注解的作用是扩展配置属性绑定的类型转换能力。默认情况下,ConfigurationPropertiesBinder 使用 ConversionService 完成类型转换,支持基本类型、枚举、集合等常见转换。当需要绑定自定义类型时,可以通过实现 Converter 并标注 @ConfigurationPropertiesBinding 来扩展转换能力。例如,定义一个 StringToDurationConverter,将字符串 "5s" 转换为 Duration.ofSeconds(5),使得属性类可以使用 Duration 类型字段。

从执行机制看,标注了 @ConfigurationPropertiesBinding 的 Converter 会被 ConfigurationPropertiesBeanDefinitionRegistrar 检测到,并注册到 ConfigurationPropertiesBinder 使用的 ConversionService 中。绑定过程中,当遇到需要从字符串转换为目标类型的场景时,会调用注册的 Converter 完成转换。这种扩展机制使得 @ConfigurationProperties 能够支持任意复杂的自定义类型。

@NestedConfigurationProperty

@NestedConfigurationProperty 用于标注一个字段,表示它是一个嵌套的配置属性对象,应当被配置元数据工具识别为独立的属性组。它是一个标记注解,不接受任何属性,通常标注在 @ConfigurationProperties 类的嵌套对象字段上。

该注解的主要作用是辅助配置元数据的生成。Spring Boot 提供了 configuration-processor 工具,用于在编译期生成配置元数据文件(META-INF/spring-configuration-metadata.json),供 IDE 提供配置补全和文档提示。当属性类中包含嵌套对象时,configuration-processor 默认可能无法正确识别嵌套属性,通过 @NestedConfigurationProperty 显式标注可以确保嵌套属性被正确记录到元数据中。

从使用场景看,@NestedConfigurationProperty 主要用于提升开发体验,而非运行时行为。它不影响属性绑定的实际过程,只影响配置元数据的生成。当属性类结构复杂、嵌套层次较深时,使用该注解可以确保 IDE 能够正确提示嵌套属性,提升配置编写效率。在现代 Spring Boot 版本中,configuration-processor 的识别能力已经较强,该注解的使用频率有所下降,但在某些复杂场景下仍然必要。

@ConstructorBinding

@ConstructorBinding 用于标注一个构造器,表示配置属性绑定应通过该构造器完成,而非通过 setter 方法。它是一个标记注解,可以标注在类上(表示使用主构造器)或具体构造器上(当类有多个构造器时)。这是 Spring Boot 2.0 引入的注解,用于支持不可变的属性类。

该注解的作用是改变属性绑定的策略。默认情况下,ConfigurationPropertiesBinder 通过 setter 方法注入属性,这要求属性类提供无参构造器和 setter,使得属性类是可变的。使用 @ConstructorBinding 后,绑定过程通过构造器参数完成,属性类可以是不可变的 final 字段,提升了线程安全性和可维护性。绑定过程会根据构造器参数名与属性名的匹配关系,从 Environment 中读取对应属性值并传入构造器。

从 Spring Boot 3.0 开始,@ConstructorBinding 不再需要显式标注在单构造器的类上,框架会自动识别单构造器并使用构造器绑定。只有当类有多个构造器时,才需要使用 @ConstructorBinding 显式指定使用哪一个。这种简化使得不可变属性类的编写更加自然,符合现代 Java 编程的偏好。

@DefaultValue

@DefaultValue 用于为配置属性指定默认值,当属性在 Environment 中不存在时使用该默认值。它接受 value 一个属性,类型为 String,表示默认值的字符串形式,绑定过程中会通过 ConversionService 转换为目标类型。

该注解通常标注在 @ConfigurationProperties 类的字段或构造器参数上,用于补充 @ConfigurationProperties 的默认值机制。需要注意的是,@ConfigurationProperties 类的字段可以直接赋值默认值(如 private int port = 8080;),但当使用构造器绑定时,字段是 final 的无法直接赋值,此时需要使用 @DefaultValue 为构造器参数指定默认值。

从使用场景看,@DefaultValue 主要用于构造器绑定场景下的默认值声明。例如,一个 ServerProperties 属性类使用构造器绑定,其中 maxConnections 参数希望默认值为 100,可以声明为 public ServerProperties(@DefaultValue("100") int maxConnections)。当配置文件中未指定 spring.server.max-connections 时,绑定过程会使用 "100" 作为默认值,并通过 ConversionService 转换为 int 类型的 100。

@Name

@Name 用于标注构造器参数,指定该参数对应的配置属性名。它接受 value 一个属性,类型为 String,表示属性名。该注解主要用于构造器绑定场景下,当构造器参数名与属性名不一致时,通过该注解显式指定映射关系。

该注解解决的问题是 Java 编译时参数名保留的问题。默认情况下,Java 编译器会保留参数名(需要 -parameters 编译选项),Spring Boot 可以直接通过参数名匹配属性。但当编译时未启用 -parameters,或参数名与属性名需要解耦时,使用 @Name 显式指定属性名可以确保绑定正确。

从使用场景看,@Name 主要用于需要精确控制构造器参数与属性名映射的场景。例如,某个属性名为 "max-connections",但构造器参数希望命名为 "maxConnections"(虽然 Spring Boot 默认会进行 kebab-case 到 camelCase 的转换,但在某些复杂场景下可能需要显式指定)。该注解提供了对绑定过程的精细控制,是构造器绑定体系的重要补充。

Actuator 端点注解

Actuator 端点注解用于定义和暴露运维管理端点,使得应用运行时的健康状态、指标、配置等信息可以通过 HTTP 或 JMX 访问。这一组注解是 Spring Boot Actuator 模块的核心,使得运维人员能够通过标准化的接口管理应用。

@Endpoint

@Endpoint 用于标注一个类,表示它是一个 Actuator 端点。它接受 id 属性指定端点标识(如 "health"、"info"),enableByDefault 属性控制是否默认启用(默认为 true)。标注了 @Endpoint 的类可以通过 @ReadOperation、@WriteOperation、@DeleteOperation 等注解定义操作方法,这些方法会被框架识别并暴露为 HTTP 或 JMX 操作。

该注解通过 EndpointDiscoverer 机制工作,框架在启动时扫描所有 @Endpoint 标注的类,通过反射读取操作方法注解,构建 Endpoint 描述对象,然后注册到对应的暴露通道(Web 或 JMX)。端点的暴露方式由 @WebEndpoint 和 @JmxEndpoint 等技术特定注解控制,@Endpoint 本身表示同时支持 Web 和 JMX 暴露。

从使用场景看,@Endpoint 用于自定义运维端点。例如,应用希望暴露一个 "feature" 端点,返回当前启用的功能列表,可以定义一个 @Endpoint(id = "feature") 类,其中标注 @ReadOperation 的方法返回功能列表。框架会自动将该端点暴露为 HTTP GET /actuator/feature 和 JMX MBean 操作,无需开发者处理具体的传输细节。

@WebEndpoint

@WebEndpoint 用于标注一个类,表示它是一个仅通过 Web 暴露的端点。它接受 id 和 enableByDefault 属性,语义与 @Endpoint 一致,区别在于 @WebEndpoint 标注的端点只会通过 HTTP 暴露,不会通过 JMX 暴露。

该注解通过 WebEndpointDiscoverer 工作,框架在扫描端点时,会根据注解类型决定暴露通道。@WebEndpoint 标注的端点只会被 WebEndpointDiscoverer 识别,不会被 JmxEndpointDiscoverer 识别。这种区分使得开发者可以精确控制端点的暴露范围,避免敏感操作通过 JMX 暴露。

从使用场景看,@WebEndpoint 适用于只适合通过 HTTP 访问的端点。例如,某个端点返回的数据量较大,通过 JMX 传输效率低,或者某个端点的操作只适合通过 HTTP 请求触发,此时使用 @WebEndpoint 可以限制其只通过 Web 暴露。这种精确控制提升了端点管理的灵活性和安全性。

@JmxEndpoint

@JmxEndpoint 用于标注一个类,表示它是一个仅通过 JMX 暴露的端点。它接受 id、enableByDefault 等属性,语义与 @Endpoint 一致,区别在于 @JmxEndpoint 标注的端点只会通过 JMX 暴露,不会通过 HTTP 暴露。

该注解通过 JmxEndpointDiscoverer 工作,框架在扫描端点时,@JmxEndpoint 标注的端点只会被 JmxEndpointDiscoverer 识别,不会被 WebEndpointDiscoverer 识别。这种设计适用于传统的 JMX 管理场景,当运维工具主要基于 JMX 时,可以将端点限定为 JMX 暴露。

从使用场景看,@JmxEndpoint 适用于需要与传统 JMX 管理工具集成的端点。例如,某些遗留的运维系统通过 JMX 访问应用指标,使用 @JmxEndpoint 可以确保端点通过 JMX 暴露,同时避免通过 HTTP 暴露可能带来的安全风险。这种基于暴露通道的精确控制是 Actuator 端点体系的重要特性。

@RestControllerEndpoint

@RestControllerEndpoint 用于标注一个类,表示它是一个通过 Spring MVC 暴露的端点,可以使用 @RestController 的全部能力。它接受 id 属性指定端点标识,被标注的类需要同时使用 @RestController 和 @RequestMapping 等标准 MVC 注解定义端点路径和方法。

该注解与 @WebEndpoint 的区别在于,@WebEndpoint 通过框架内置的 Web 暴露机制工作,操作方法使用 @ReadOperation 等注解,路径由框架自动生成;而 @RestControllerEndpoint 通过标准 Spring MVC 工作,开发者可以完全控制路径、HTTP 方法、参数绑定等,灵活性更高但需要更多手动配置。

从使用场景看,@RestControllerEndpoint 适用于需要复杂 HTTP 交互的端点。例如,某个端点需要支持复杂的查询参数、路径变量、请求体绑定,使用 @WebEndpoint 的简单操作注解难以满足,此时可以使用 @RestControllerEndpoint 结合标准 MVC 注解实现。这种端点会被框架识别并纳入 Actuator 的端点管理(如安全控制、暴露配置),但具体的 HTTP 处理由 Spring MVC 完成。

@ServletEndpoint

@ServletEndpoint 用于标注一个类,表示它是一个通过 Servlet 暴露的端点。它接受 id 属性指定端点标识,被标注的类需要实现 org.springframework.boot.actuate.endpoint.web.EndpointServlet 接口,提供要暴露的 Servlet 实例。

该注解适用于需要直接使用 Servlet API 的端点场景。当某个端点的实现依赖于 Servlet API 的底层能力(如异步处理、WebSocket 升级等),无法通过 @WebEndpoint 的操作注解表达时,可以使用 @ServletEndpoint 直接暴露一个 Servlet。框架会将该 Servlet 注册到 Servlet 容器,路径前缀为 /actuator/{id}。

从使用场景看,@ServletEndpoint 主要用于兼容遗留的 Servlet 实现或需要底层 Servlet 能力的场景。在现代 Spring Boot 应用中,更推荐使用 @WebEndpoint 或 @RestControllerEndpoint,它们提供了更高层的抽象和更好的集成。@ServletEndpoint 作为一种底层扩展机制,为特殊需求提供了支持。

@ReadOperation

@ReadOperation 用于标注一个方法,表示它是一个读取操作,对应 HTTP GET 请求。它不接受任何属性,标注在 @Endpoint 类的方法上。方法的返回值会被序列化为 JSON 并作为 HTTP 响应体返回。

该注解定义了端点的读取语义。框架通过反射识别标注了 @ReadOperation 的方法,将其注册为端点的 read 操作。当 HTTP GET 请求到达 /actuator/{endpointId} 时,框架调用对应方法,将返回值通过 Jackson 序列化为 JSON 返回。方法可以接受 @Selector 标注的参数,用于从路径中提取变量。

从使用场景看,@ReadOperation 用于实现幂等的查询操作。例如,健康检查端点的 health 方法标注 @ReadOperation,返回应用的健康状态;指标端点的 metrics 方法标注 @ReadOperation,返回所有指标。这种基于注解的操作定义使得端点的实现简洁,开发者只需关注业务逻辑,无需处理 HTTP 细节。

@WriteOperation

@WriteOperation 用于标注一个方法,表示它是一个写入操作,对应 HTTP POST 请求。它不接受任何属性,标注在 @Endpoint 类的方法上。方法的参数会从 HTTP 请求体中绑定,返回值会被序列化为 JSON 响应。

该注解定义了端点的写入语义。框架通过反射识别标注了 @WriteOperation 的方法,将其注册为端点的 write 操作。当 HTTP POST 请求到达 /actuator/{endpointId} 时,框架从请求体中提取参数,调用对应方法。参数绑定通过 Jackson 反序列化完成,支持复杂对象类型。

从使用场景看,@WriteOperation 用于实现会改变应用状态的操作。例如,日志级别端点的 loggers 方法标注 @WriteOperation,接受一个包含 logger 名称和级别的对象,动态修改日志级别;缓存端点的 evict 方法标注 @WriteOperation,清空指定缓存。这种基于注解的操作定义使得写入操作的实现简洁,同时框架会自动处理参数绑定和错误响应。

@DeleteOperation

@DeleteOperation 用于标注一个方法,表示它是一个删除操作,对应 HTTP DELETE 请求。它不接受任何属性,标注在 @Endpoint 类的方法上。方法通常接受 @Selector 标注的参数,用于指定要删除的资源。

该注解定义了端点的删除语义。框架通过反射识别标注了 @DeleteOperation 的方法,将其注册为端点的 delete 操作。当 HTTP DELETE 请求到达 /actuator/{endpointId}/{selector} 时,框架从路径中提取 selector 参数,调用对应方法执行删除操作。

从使用场景看,@DeleteOperation 用于实现删除资源的操作。例如,缓存端点的 delete 方法标注 @DeleteOperation,接受 @Selector 标注的缓存名称参数,删除指定缓存;定时任务端点的 delete 方法标注 @DeleteOperation,取消指定任务。这种基于注解的操作定义使得删除操作的实现简洁,同时框架会自动处理路径参数提取和错误响应。

@Selector

@Selector 用于标注一个方法参数,表示它是一个路径选择器,从 HTTP 请求路径中提取变量。它接受 value 一个属性,类型为 String,表示路径变量名,默认使用参数名。该注解通常与 @ReadOperation、@WriteOperation、@DeleteOperation 配合使用。

该注解的作用是支持端点的路径参数化。当端点需要操作特定资源时(如查看某个 logger 的级别、清空某个缓存),可以通过 @Selector 标注的参数从路径中提取资源标识。例如,方法 @ReadOperation public Object getLogger(@Selector String name) 会被映射为 GET /actuator/loggers/{name},框架从路径中提取 name 参数传入方法。

从使用场景看,@Selector 用于实现针对特定资源的操作。它支持 String、long、int 等基本类型,框架会自动完成类型转换。当需要多个路径变量时,可以使用多个 @Selector 标注的参数,它们会按顺序映射到路径段。这种路径参数化机制使得端点能够精确操作单个资源,提升了端点的实用性。

@EndpointWebExtension

@EndpointWebExtension 用于标注一个类,表示它是某个端点的 Web 扩展。它接受 endpoint 属性指定要扩展的端点 id,被标注的类可以提供特定于 Web 暴露的额外操作或覆盖现有操作的行为。

该注解的作用是扩展端点的 Web 行为。某些端点在 Web 暴露时可能需要额外的操作或不同的行为,例如健康检查端点在 Web 暴露时支持按路径访问特定健康指标,这些扩展操作可以通过 @EndpointWebExtension 标注的类提供。框架在扫描端点时会同时扫描扩展,将扩展的操作合并到端点的 Web 暴露中。

从使用场景看,@EndpointWebExtension 主要用于框架内置端点的扩展,开发者自定义端点较少使用。例如,HealthEndpointWebExtension 扩展了健康检查端点的 Web 行为,支持按路径访问特定健康指标。这种扩展机制使得端点的核心逻辑与暴露特定逻辑分离,提升了代码的模块化程度。

@EndpointJmxExtension

@EndpointJmxExtension 用于标注一个类,表示它是某个端点的 JMX 扩展。它接受 endpoint 属性指定要扩展的端点 id,被标注的类可以提供特定于 JMX 暴露的额外操作或覆盖现有操作的行为。

该注解与 @EndpointWebExtension 语义对称,区别在于它扩展的是 JMX 暴露而非 Web 暴露。框架在扫描端点时会同时扫描 JMX 扩展,将扩展的操作合并到端点的 JMX 暴露中。这种设计使得同一个端点可以在不同暴露通道下有不同的扩展行为,而核心逻辑保持一致。

从使用场景看,@EndpointJmxExtension 主要用于框架内置端点的 JMX 扩展,开发者自定义端点较少使用。例如,LoggersEndpointJmxExtension 扩展了日志端点的 JMX 行为,提供适合 JMX 操作的额外接口。这种扩展机制与 @EndpointWebExtension 共同构成了端点的多通道扩展体系。

@FilteredEndpoint

@FilteredEndpoint 用于标注一个端点类,表示它需要通过特定的 EndpointFilter 进行过滤。它接受 value 一个属性,类型为 Class<? extends EndpointFilter>,指定过滤器类型。该注解主要用于框架内部,控制端点在不同场景下的可见性。

该注解的作用是支持端点的条件性暴露。某些端点可能只在特定条件下应该被暴露(如只在开发环境、只在特定云平台),通过 @FilteredEndpoint 可以声明端点需要通过的过滤器,框架在扫描端点时会应用过滤器决定是否暴露该端点。

从使用场景看,@FilteredEndpoint 主要用于框架内部实现,开发者自定义端点较少直接使用。它提供了一种声明式的端点过滤机制,使得端点的暴露策略可以通过注解配置而非代码逻辑控制。这种设计提升了端点管理的灵活性和可配置性。

@Accessor

@Accessor 用于标注端点操作方法的参数,表示它是一个访问器参数,用于指定操作的访问上下文。它接受 value 一个属性,类型为 AccessorType 枚举,可选值为 READ、WRITE、DELETE,表示访问类型。

该注解主要用于框架内部,帮助端点操作方法正确处理参数绑定。在某些复杂的端点操作中,参数可能需要根据操作类型(读、写、删除)进行不同的绑定处理,@Accessor 通过声明访问类型指导框架的参数绑定行为。

从使用场景看,@Accessor 主要用于框架内部实现,开发者自定义端点较少直接使用。它提供了一种精细的参数绑定控制机制,是端点操作方法参数处理体系的一部分。在大多数自定义端点场景中,使用 @Selector 即可满足需求,@Accessor 用于更复杂的参数处理场景。

测试注解

测试注解用于支持 Spring Boot 应用的集成测试和切片测试。这一组注解提供了从完整应用上下文加载到特定层切片测试的多种能力,使得开发者能够根据测试目标选择合适的测试策略,在测试覆盖率和测试速度之间取得平衡。

@SpringBootTest

@SpringBootTest 用于标注一个集成测试类,表示需要加载完整的 Spring Boot 应用上下文。它接受多个属性,classes 指定主配置类(默认使用 @SpringBootConfiguration 标注的类),webEnvironment 指定 Web 环境类型(MOCK、RANDOM_PORT、DEFINED_PORT、NONE),properties 指定测试专有属性,value 和 properties 互为别名。

该注解是 Spring Boot 测试体系的核心,通过 SpringBootTestContextBootstrapper 加载应用上下文。webEnvironment 为 MOCK 时,使用 MockServletContext 加载 Web 上下文但不启动真实服务器,适合 Controller 测试;为 RANDOM_PORT 时,启动真实服务器并监听随机端口,适合端到端测试;为 DEFINED_PORT 时,使用配置文件指定的端口;为 NONE 时,不创建 Web 上下文。

从使用场景看,@SpringBootTest 适用于需要完整应用上下文的集成测试。例如,测试 Service 层与数据库的交互、测试多个组件的协作行为。由于加载完整上下文,测试速度较慢,因此对于只需要测试某一层的场景,应优先使用切片测试注解(如 @WebMvcTest、@DataJpaTest)以提升测试速度。

@TestConfiguration

@TestConfiguration 用于标注一个测试专用的配置类,表示它提供额外的 Bean 定义用于测试场景。它的语义与 @Configuration 类似,区别在于 @TestConfiguration 标注的类不会被组件扫描自动拾取,需要通过 @Import 显式导入或放在测试类的内部静态类中。

该注解的设计目的是支持测试场景下的配置补充。在集成测试中,可能需要覆盖某些 Bean 的定义或添加测试专有的 Bean,但又不想修改主配置。通过 @TestConfiguration 标注的类可以提供这些补充配置,测试结束后不会影响生产配置。当 @TestConfiguration 标注的类作为测试类的内部静态类时,会自动被拾取,无需显式 @Import。

从使用场景看,@TestConfiguration 用于测试场景的 Bean 覆盖和补充。例如,测试需要 Mock 某个外部服务客户端,可以定义一个 @TestConfiguration 类,其中声明 @Bean 方法返回 Mock 实例,覆盖生产配置中的真实客户端。这种机制使得测试配置与生产配置分离,提升了测试的独立性和可维护性。

@AutoConfigureMockMvc

@AutoConfigureMockMvc 用于标注一个测试类,表示自动配置 MockMvc 用于测试 Spring MVC Controller。它接受 print 属性控制是否打印请求响应详情(NEVER、SYSTEM_OUT、SYSTEM_ERR、LOGGING),addFilters 属性控制是否添加过滤器,properties 和 value 属性指定测试专有属性。

该注解通常与 @SpringBootTest(webEnvironment = WebEnvironment.MOCK) 配合使用,自动配置一个 MockMvc 实例并注入到测试类中。MockMvc 模拟 Spring MVC 的请求处理流程,无需启动真实 Servlet 容器即可测试 Controller 的路由、参数绑定、响应序列化等行为。测试类通过 @Autowired 注入 MockMvc,然后使用其流式 API 编写测试。

从使用场景看,@AutoConfigureMockMvc 适用于需要测试 Controller 层但不需要真实 Servlet 容器的场景。例如,测试 Controller 的路由是否正确、参数绑定是否成功、异常处理是否生效。与 @WebMvcTest 的区别在于,@AutoConfigureMockMvc 加载完整应用上下文(与 @SpringBootTest 配合),而 @WebMvcTest 只加载 Controller 层切片,后者速度更快但覆盖范围更窄。

@AutoConfigureTestDatabase

@AutoConfigureTestDatabase 用于标注一个测试类,表示自动配置测试数据库,替代生产数据库。它接受 replace 属性控制替换策略(ANY、AUTO_CONFIGURED、NONE),connection 属性指定数据库连接类型(H2、HSQLDB、DERBY)。

该注解通过 TestDatabaseAutoConfiguration 工作,自动配置一个嵌入式内存数据库(如 H2)替代生产数据库。replace 为 ANY 时,替换任何 DataSource;为 AUTO_CONFIGURED 时,只替换通过自动配置创建的 DataSource;为 NONE 时,不替换,使用生产数据库。这种机制使得数据库相关测试不依赖外部数据库实例,提升了测试的可移植性和执行速度。

从使用场景看,@AutoConfigureTestDatabase 适用于数据访问层测试。例如,与 @DataJpaTest 配合使用,自动配置 H2 数据库替代生产数据库,Repository 测试在内存数据库上执行,速度快且不污染生产数据。需要注意的是,嵌入式数据库与生产数据库的 SQL 方言可能不同,某些 SQL 特性在嵌入式数据库上可能行为不一致,测试结果需要谨慎解读。

@AutoConfigureMockRestServiceServer

@AutoConfigureMockRestServiceServer 用于标注一个测试类,表示自动配置 MockRestServiceServer 用于测试 RestTemplate 或 RestClient 的外部调用。它接受 enabled 属性控制是否启用,value 和 properties 属性指定测试专有属性。

该注解自动配置一个 MockRestServiceServer 实例,并绑定到容器中的 RestTemplateBuilder 或 RestClientBuilder。MockRestServiceServer 模拟外部 HTTP 服务的响应,使得测试不需要真实的外部服务即可验证客户端的请求构造和响应处理逻辑。测试类通过 @Autowired 注入 MockRestServiceServer,使用其 API 设置期望请求和响应,然后调用业务代码触发请求。

从使用场景看,@AutoConfigureMockRestServiceServer 适用于测试调用外部 HTTP 服务的代码。例如,Service 层通过 RestTemplate 调用第三方 API,使用该注解配置 MockRestServiceServer,设置期望的请求 URL、HTTP 方法和响应体,然后验证 Service 是否正确构造请求和处理响应。这种机制使得外部依赖测试不依赖真实服务,提升了测试的稳定性和速度。

@AutoConfigureJson

@AutoConfigureJson 用于标注一个测试类,表示自动配置 JSON 序列化反序列化组件用于测试。它接受 converters 属性指定要导入的 HttpMessageConverter,value 和 properties 属性指定测试专有属性。

该注解通过 JsonTestersAutoConfiguration 和 JacksonAutoConfiguration 工作,自动配置 ObjectMapper、JsonParser、JsonGenerator 等 JSON 处理组件,以及 BasicJsonTester、JacksonJsonTester、GsonJsonTester 等测试辅助工具。测试类可以通过 @Autowired 注入这些组件,验证 JSON 序列化反序列化的正确性。

从使用场景看,@AutoConfigureJson 通常与 @JsonTest 配合使用,用于测试 JSON 序列化反序列化逻辑。例如,测试某个 DTO 的 JSON 序列化结果是否符合预期、测试 ObjectMapper 的自定义配置是否生效。该注解也可以单独使用,在需要 JSON 处理能力的非切片测试中提供 JSON 组件。

@AutoConfigureJsonTesters

@AutoConfigureJsonTesters 用于标注一个测试类,表示自动配置 JSON 测试器(JsonTester)用于测试。它接受 enabled 属性控制是否启用,value 和 properties 属性指定测试专有属性。

该注解与 @AutoConfigureJson 的区别在于,它专注于配置 JsonTester 实例,而非 ObjectMapper 等底层组件。JsonTester 是 assertj 风格的 JSON 断言工具,提供了流式的 JSON 验证 API。该注解自动配置 BasicJsonTester、JacksonJsonTester、GsonJsonTester 等,测试类通过 @Autowired 注入并使用。

从使用场景看,@AutoConfigureJsonTesters 通常与 @JsonTest 配合使用,用于测试 JSON 序列化反序列化逻辑。例如,测试某个 DTO 序列化为 JSON 后,使用 JacksonJsonTester 验证 JSON 路径的值是否符合预期。这种基于 JsonTester 的断言方式比直接比较 JSON 字符串更加灵活和可读。

@AutoConfigureRestDocs

@AutoConfigureRestDocs 用于标注一个测试类,表示自动配置 Spring REST Docs 用于生成 API 文档。它接受 outputDir 属性指定文档输出目录(默认为 target/generated-snippets),uriScheme、uriHost、uriPort 属性指定文档中记录的 URI 信息,value 和 properties 属性指定测试专有属性。

该注解通过 RestDocsAutoConfiguration 工作,自动配置 REST Docs 的 MockMvc 集成或 WebTestClient 集成。Spring REST Docs 是一种从测试生成 API 文档的工具,通过在测试中调用 document 方法记录请求响应,生成 asciidoc 或 markdown 片段,最终组装为 API 文档。该注解确保 REST Docs 的相关组件被正确配置到测试上下文中。

从使用场景看,@AutoConfigureRestDocs 通常与 @WebMvcTest 或 @SpringBootTest 配合使用,用于在测试 Controller 的同时生成 API 文档。例如,测试某个 Controller 的 GET 请求,在测试中调用 .andDo(document("get-resource")) 记录请求响应,生成文档片段。这种从测试生成文档的方式确保了文档与代码的一致性,避免了文档与实际 API 脱节。

@AutoConfigureTestEntityManager

@AutoConfigureTestEntityManager 用于标注一个测试类,表示自动配置 TestEntityManager 用于 JPA 测试。它接受 enabled 属性控制是否启用,value 和 properties 属性指定测试专有属性。

该注解通过 TestEntityManagerAutoConfiguration 工作,自动配置一个 TestEntityManager 实例。TestEntityManager 是 JPA 测试的辅助工具,提供了 persist、find、flush、clear 等方法,方便在测试中操作实体。它内部使用 EntityManagerFactory 创建 EntityManager,与测试事务配合使用。

从使用场景看,@AutoConfigureTestEntityManager 通常与 @DataJpaTest 配合使用,用于 JPA Repository 测试。例如,测试某个 Repository 的自定义查询方法,使用 TestEntityManager 准备测试数据(persist 实体),然后调用 Repository 方法验证查询结果。TestEntityManager 提供了比直接使用 EntityManager 更简洁的 API,提升了测试代码的可读性。

@AutoConfigureWebTestClient

@AutoConfigureWebTestClient 用于标注一个测试类,表示自动配置 WebTestClient 用于测试 Spring WebFlux Controller。它接受 controller 属性指定要测试的 Controller 类,value 和 properties 属性指定测试专有属性。

该注解自动配置一个 WebTestClient 实例,用于测试响应式 Web 应用。WebTestClient 是 Spring WebFlux 的测试工具,类似于 MockMvc 但针对响应式栈。它可以绑定到真实服务器或模拟服务器,测试 Controller 的路由、参数绑定、响应式处理等行为。测试类通过 @Autowired 注入 WebTestClient,使用其流式 API 编写测试。

从使用场景看,@AutoConfigureWebTestClient 适用于测试 Spring WebFlux 应用。例如,测试响应式 Controller 的路由是否正确、响应式数据流是否正确处理。与 @WebFluxTest 的区别在于,@AutoConfigureWebTestClient 加载完整应用上下文(与 @SpringBootTest 配合),而 @WebFluxTest 只加载 Controller 层切片,后者速度更快但覆盖范围更窄。

@AutoConfigureWebServer

@AutoConfigureWebServer 用于标注一个测试类,表示自动配置嵌入式 Web 服务器用于测试。它接受 enabled 属性控制是否启用,port 属性指定端口(-1 表示随机端口),value 和 properties 属性指定测试专有属性。

该注解通过 WebServerAutoConfiguration 工作,自动配置嵌入式 Web 服务器(Tomcat、Jetty 或 Undertow,取决于类路径)。当 @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) 或 DEFINED_PORT 时,框架会自动配置 Web 服务器,该注解提供了额外的配置控制能力。

从使用场景看,@AutoConfigureWebServer 主要用于需要精细控制 Web 服务器的测试场景。例如,测试需要指定特定端口、或需要禁用 Web 服务器但保留其他自动配置的场景。在大多数情况下,@SpringBootTest 的 webEnvironment 属性已经足够控制 Web 服务器行为,该注解用于更精细的配置需求。

@DataJpaTest

@DataJpaTest 用于标注一个测试类,表示这是一个 JPA 切片测试,只加载 JPA 相关组件。它接受 properties、value 属性指定测试专有属性,useDefaultFilters 属性控制是否使用默认过滤器,includeFilters 和 excludeFilters 属性控制组件扫描过滤器。

该注解通过 @AutoConfigureMockMvc、@ImportAutoConfiguration 等组合实现,加载 JPA 切片所需的组件:EntityManagerFactory、DataSource(默认为嵌入式 H2)、Repository(通过 @EntityScan 扫描)、TestEntityManager 等。它不会加载完整的应用上下文,因此测试速度快。默认情况下,每个测试方法结束后会回滚事务,保证测试数据隔离。

从使用场景看,@DataJpaTest 适用于 JPA Repository 的单元测试。例如,测试某个 Repository 的自定义查询方法是否正确、测试实体的关联映射是否正确。由于只加载 JPA 切片,Service、Controller 等组件不会被加载,如果 Repository 依赖 Service,需要通过 @MockBean 或 @Import 提供 Mock 实现。这种切片测试机制在保证测试覆盖的同时,显著提升了测试速度。

@DataRedisTest

@DataRedisTest 用于标注一个测试类,表示这是一个 Redis 切片测试,只加载 Redis 相关组件。它接受 properties、value 属性指定测试专有属性,useDefaultFilters、includeFilters、excludeFilters 属性控制组件扫描。

该注解加载 Redis 切片所需的组件:RedisTemplate、RedisConnectionFactory(默认为嵌入式 Redis 或 Mock)、Repository(通过 @RedisRepositoryScan 扫描)等。它不会加载完整的应用上下文,测试速度快。嵌入式 Redis 的可用性取决于类路径上是否有相关依赖,如果没有,会使用 Mock 实现。

从使用场景看,@DataRedisTest 适用于 Redis Repository 的单元测试。例如,测试某个 Redis Repository 的读写操作是否正确、测试 RedisTemplate 的自定义操作是否正确。与 @DataJpaTest 类似,它只加载 Redis 切片,其他组件需要通过 Mock 提供。这种切片测试机制使得 Redis 相关测试不依赖真实 Redis 实例,提升了测试的可移植性。

@JdbcTest

@JdbcTest 用于标注一个测试类,表示这是一个 JDBC 切片测试,只加载 JDBC 相关组件。它接受 properties、value 属性指定测试专有属性,useDefaultFilters、includeFilters、excludeFilters 属性控制组件扫描,autoConfigureTestDatabase 属性控制是否自动配置测试数据库。

该注解加载 JDBC 切片所需的组件:DataSource(默认为嵌入式 H2)、JdbcTemplate、NamedParameterJdbcTemplate 等。它不会加载完整的应用上下文,测试速度快。默认情况下,每个测试方法结束后会回滚事务,保证测试数据隔离。同时,该注解会自动应用 @AutoConfigureTestDatabase,使用嵌入式数据库替代生产数据库。

从使用场景看,@JdbcTest 适用于直接使用 JdbcTemplate 的数据访问测试。例如,测试某个 DAO 类的 SQL 查询是否正确、测试 JdbcTemplate 的自定义 RowMapper 是否正确。与 @DataJpaTest 的区别在于,@JdbcTest 不加载 JPA 相关组件,适用于不使用 JPA 而直接使用 JDBC 的场景。这种切片测试机制使得 JDBC 测试不依赖 JPA 实体管理器,加载范围更小,速度更快。

@JsonTest

@JsonTest 用于标注一个测试类,表示这是一个 JSON 切片测试,只加载 JSON 序列化反序列化组件。它接受 properties、value 属性指定测试专有属性,useDefaultFilters、includeFilters、excludeFilters 属性控制组件扫描。

该注解通过 @ImportAutoConfiguration 加载 JSON 切片所需的组件:ObjectMapper(或 Gson)、HttpMessageConverter、JsonTester 等。它不会加载完整的应用上下文,测试速度非常快。同时,该注解会自动应用 @AutoConfigureJson 和 @AutoConfigureJsonTesters,提供 JSON 测试工具。

从使用场景看,@JsonTest 适用于 JSON 序列化反序列化的单元测试。例如,测试某个 DTO 的 JSON 序列化结果是否符合预期、测试 ObjectMapper 的自定义配置(如日期格式、字段命名策略)是否生效。这种切片测试机制使得 JSON 测试不加载其他组件,速度极快,适合频繁执行的单元测试。

@RestClientTest

@RestClientTest 用于标注一个测试类,表示这是一个 REST 客户端切片测试,只加载 REST 客户端相关组件。它接受 properties、value 属性指定测试专有属性,useDefaultFilters、includeFilters、excludeFilters 属性控制组件扫描,client 属性指定要测试的 REST 客户端类。

该注解加载 REST 客户端切片所需的组件:RestTemplateBuilder、RestClientBuilder、MockRestServiceServer 等。它不会加载完整的应用上下文,测试速度快。同时,该注解会自动应用 @AutoConfigureMockRestServiceServer,提供 MockRestServiceServer 用于模拟外部 HTTP 服务。

从使用场景看,@RestClientTest 适用于 REST 客户端的单元测试。例如,测试某个 Service 通过 RestTemplate 调用外部 API 的逻辑是否正确、测试请求构造和响应处理是否正确。通过 client 属性指定要测试的 REST 客户端类,框架只加载该类及其依赖,其他组件通过 Mock 提供。这种切片测试机制使得 REST 客户端测试不依赖真实外部服务,提升了测试的稳定性和速度。

@WebMvcTest

@WebMvcTest 用于标注一个测试类,表示这是一个 Spring MVC Controller 切片测试,只加载 MVC 相关组件。它接受 controllers 属性指定要测试的 Controller 类,properties、value 属性指定测试专有属性,useDefaultFilters、includeFilters、excludeFilters 属性控制组件扫描。

该注解加载 MVC 切片所需的组件:Spring MVC 基础设施(DispatcherServlet、HandlerMapping、HandlerAdapter等)、MockMvc、HttpMessageConverter 等。它不会加载完整的应用上下文,特别是不会加载 Service、Repository 等组件,这些需要通过 @MockBean 提供。同时,该注解会自动应用 @AutoConfigureMockMvc,提供 MockMvc 用于测试。

从使用场景看,@WebMvcTest 适用于 Controller 层的单元测试。例如,测试 Controller 的路由是否正确、参数绑定是否成功、异常处理是否生效、响应序列化是否正确。通过 controllers 属性指定要测试的 Controller 类,框架只加载该 Controller 及其依赖的 MVC 基础设施,其他 Controller 不会被加载,Service 等依赖通过 @MockBean 提供。这种切片测试机制使得 Controller 测试不加载完整应用上下文,速度较快,同时聚焦于 Web 层逻辑。

@WebFluxTest

@WebFluxTest 用于标注一个测试类,表示这是一个 Spring WebFlux Controller 切片测试,只加载 WebFlux 相关组件。它接受 controllers 属性指定要测试的 Controller 类,properties、value 属性指定测试专有属性,useDefaultFilters、includeFilters、excludeFilters 属性控制组件扫描。

该注解加载 WebFlux 切片所需的组件:Spring WebFlux 基础设施(DispatcherHandler、HandlerMapping、HandlerAdapter等)、WebTestClient、HttpMessageConverter 等。它不会加载完整的应用上下文,特别是不会加载 Service、Repository 等组件,这些需要通过 @MockBean 提供。同时,该注解会自动应用 @AutoConfigureWebTestClient,提供 WebTestClient 用于测试。

从使用场景看,@WebFluxTest 适用于响应式 Controller 层的单元测试。例如,测试响应式 Controller 的路由是否正确、响应式数据流是否正确处理、Server-Sent Events 是否正确生成。与 @WebMvcTest 的区别在于,@WebFluxTest 针对响应式栈,使用 WebTestClient 而非 MockMvc。这种切片测试机制使得响应式 Controller 测试不加载完整应用上下文,速度较快,同时聚焦于 Web 层逻辑。

@DataLdapTest

@DataLdapTest 用于标注一个测试类,表示这是一个 LDAP 切片测试,只加载 LDAP 相关组件。它接受 properties、value 属性指定测试专有属性,useDefaultFilters、includeFilters、excludeFilters 属性控制组件扫描。

该注解加载 LDAP 切片所需的组件:LdapTemplate、ContextSource(默认为嵌入式 LDAP 或 Mock)、LdapRepository 等。它不会加载完整的应用上下文,测试速度快。嵌入式 LDAP 的可用性取决于类路径上是否有相关依赖(如 unboundid-ldapsdk),如果没有,会使用 Mock 实现。

从使用场景看,@DataLdapTest 适用于 LDAP Repository 的单元测试。例如,测试某个 LdapRepository 的查询操作是否正确、测试 LdapTemplate 的自定义操作是否正确。与 @DataJpaTest 类似,它只加载 LDAP 切片,其他组件需要通过 Mock 提供。这种切片测试机制使得 LDAP 相关测试不依赖真实 LDAP 服务器,提升了测试的可移植性和速度。

@DataNeo4jTest

@DataNeo4jTest 用于标注一个测试类,表示这是一个 Neo4j 切片测试,只加载 Neo4j 相关组件。它接受 properties、value 属性指定测试专有属性,useDefaultFilters、includeFilters、excludeFilters 属性控制组件扫描。

该注解加载 Neo4j 切片所需的组件:Neo4jTemplate、Neo4jClient、Neo4jRepository 等。它不会加载完整的应用上下文,测试速度快。默认情况下,会使用嵌入式 Neo4j 或 Testcontainers 提供的 Neo4j 实例,具体取决于配置和类路径依赖。

从使用场景看,@DataNeo4jTest 适用于 Neo4j Repository 的单元测试。例如,测试某个 Neo4j Repository 的查询操作是否正确、测试 Neo4jTemplate 的自定义操作是否正确。与 @DataJpaTest 类似,它只加载 Neo4j 切片,其他组件需要通过 Mock 提供。这种切片测试机制使得 Neo4j 相关测试不依赖真实 Neo4j 服务器,提升了测试的可移植性和速度。

@JooqTest

@JooqTest 用于标注一个测试类,表示这是一个 jOOQ 切片测试,只加载 jOOQ 相关组件。它接受 properties、value 属性指定测试专有属性,useDefaultFilters、includeFilters、excludeFilters 属性控制组件扫描。

该注解加载 jOOQ 切片所需的组件:DSLContext、DataSource(默认为嵌入式 H2)等。它不会加载完整的应用上下文,测试速度快。同时,该注解会自动应用 @AutoConfigureTestDatabase,使用嵌入式数据库替代生产数据库。

从使用场景看,@JooqTest 适用于 jOOQ 数据访问的单元测试。例如,测试某个 DAO 类的 jOOQ 查询是否正确、测试 DSLContext 的自定义操作是否正确。与 @JdbcTest 的区别在于,@JooqTest 专注于 jOOQ 相关组件,适用于使用 jOOQ 而非原生 JDBC 的场景。这种切片测试机制使得 jOOQ 测试不加载其他组件,速度较快。

@WebServiceClientTest

@WebServiceClientTest 用于标注一个测试类,表示这是一个 Web Service 客户端切片测试,只加载 Web Service 客户端相关组件。它接受 properties、value 属性指定测试专有属性,useDefaultFilters、includeFilters、excludeFilters 属性控制组件扫描,client 属性指定要测试的 Web Service 客户端类。

该注解加载 Web Service 客户端切片所需的组件:WebServiceGatewaySupport、MockWebServiceServer 等。它不会加载完整的应用上下文,测试速度快。MockWebServiceServer 模拟 SOAP 服务的响应,使得测试不需要真实 SOAP 服务即可验证客户端的请求构造和响应处理逻辑。

从使用场景看,@WebServiceClientTest 适用于 SOAP Web Service 客户端的单元测试。例如,测试某个 Service 通过 WebServiceTemplate 调用外部 SOAP 服务的逻辑是否正确、测试请求构造和响应处理是否正确。通过 client 属性指定要测试的客户端类,框架只加载该类及其依赖,其他组件通过 Mock 提供。这种切片测试机制使得 Web Service 客户端测试不依赖真实 SOAP 服务,提升了测试的稳定性和速度。

@OutputCaptureExtension

@OutputCaptureExtension 用于标注一个测试类或测试方法参数,表示使用输出捕获扩展,捕获 System.out 和 System.err 的输出用于断言。它是一个 JUnit 5 的 ExtendWith 实现,标注在测试类上时,所有测试方法都可以通过 CapturedOutput 类型的参数访问捕获的输出。

该注解通过 OutputCaptureExtension 类实现,它实现了 JUnit 5 的 BeforeTestExecutionCallback 和 AfterTestExecutionCallback 接口,在测试方法执行前后安装和卸载输出捕获器。捕获器替换 System.out 和 System.err 为自定义的 PrintStream,将输出重定向到内存缓冲区,测试方法可以通过 CapturedOutput 参数访问缓冲区内容。

从使用场景看,@OutputCaptureExtension 适用于需要验证控制台输出的测试。例如,测试某个组件是否输出了正确的日志信息、测试某个方法是否输出了特定的提示信息。通过捕获输出,测试可以断言输出内容是否包含特定字符串,避免直接比较完整输出。这种机制使得输出相关测试更加可靠和可维护。

@DisabledInAotMode

@DisabledInAotMode 用于标注一个测试类或测试方法,表示在 AOT(Ahead-Of-Time)处理模式下禁用该测试。它是一个标记注解,不接受任何属性。当应用通过 GraalVM 原生镜像方式运行时,某些测试可能因为依赖反射或运行时类生成而不适用,此时可以使用该注解禁用。

该注解通过 AotDetector 检测当前是否处于 AOT 处理模式。当 Spring AOT 处理器在编译期处理应用时,会设置特定的标记,@DisabledInAotMode 标注的测试在 AOT 模式下会被 JUnit 跳过。这种机制使得同一份测试代码在 JIT 模式和 AOT 模式下可以有不同的行为,避免因 AOT 限制导致的测试失败。

从使用场景看,@DisabledInAotMode 适用于依赖运行时反射或动态代理的测试。例如,某些测试使用 Mockito 的 inline mock maker,依赖运行时类生成,在 GraalVM 原生镜像下可能不工作,此时可以使用该注解在 AOT 模式下禁用这些测试。这种机制使得 Spring Boot 应用在向 GraalVM 原生镜像迁移时,测试体系能够平滑过渡。

@EnabledInAotMode

@EnabledInAotMode 用于标注一个测试类或测试方法,表示只在 AOT 处理模式下启用该测试。它是一个标记注解,不接受任何属性。与 @DisabledInAotMode 语义相反,该注解标注的测试只在 AOT 模式下执行,在 JIT 模式下被跳过。

该注解同样通过 AotDetector 检测当前是否处于 AOT 处理模式。当处于 AOT 模式时,标注了 @EnabledInAotMode 的测试会执行;否则,测试被跳过。这种机制使得开发者可以为 AOT 模式编写专门的测试,验证 AOT 处理后的应用行为是否符合预期。

从使用场景看,@EnabledInAotMode 适用于专门验证 AOT 处理结果的测试。例如,测试 AOT 处理后 Bean 的初始化是否正确、测试 GraalVM 原生镜像下的特定行为是否正常。这种机制使得 AOT 相关测试与常规测试分离,避免在常规开发流程中执行不必要的 AOT 测试,提升开发效率。

@MockitoBean

@MockitoBean 用于标注一个测试类的字段,表示为该字段类型创建一个 Mockito Mock 并注入到 Spring 容器中。它接受 name 属性指定 Bean 名称,value 和 classes 属性指定要 Mock 的类型,extraInterfaces 属性指定额外实现的接口,answer 属性指定默认行为。

该注解是 Spring Boot 3.4 引入的注解,用于替代此前 Spring Boot Test 中的 @MockBean 注解。它通过 MockitoBeanRegistrar 工作,在容器启动时为标注字段类型创建一个 Mockito Mock,注册到容器中替换原有 Bean 定义,并将 Mock 实例注入到测试字段中。测试方法可以通过该字段验证 Mock 的调用情况或设置 Mock 的行为。

从使用场景看,@MockitoBean 适用于在集成测试中 Mock 某些依赖。例如,测试 Service 层时,Repository 层可能依赖外部数据库,通过 @MockitoBean 标注 Repository 字段,创建 Mock 实例,设置其返回值,从而测试 Service 的业务逻辑而不依赖真实数据库。这种机制使得集成测试可以聚焦于被测组件,同时保持其他依赖可控。

@MockitoBeans

@MockitoBeans 用于在一个测试类上声明多个 @MockitoBean,是 @MockitoBean 的容器注解。它接受 value 一个属性,类型为 @MockitoBean 数组,列出要创建的多个 Mock。当需要在一个测试类中创建多个 Mock 时,可以使用该注解避免在类上堆叠多个 @MockitoBean。

该注解的设计目的是支持 Java 注解不支持重复标注同一注解类型的限制。当测试类需要多个 @MockitoBean 时,可以使用 @MockitoBeans 容器注解一次性声明所有 Mock。每个 @MockitoBean 的语义与单独使用时一致,会创建对应的 Mock 并注入到容器和测试字段中。

从使用场景看,@MockitoBeans 适用于需要多个 Mock 的复杂测试场景。例如,测试某个 Service 依赖多个外部服务,需要为每个外部服务创建 Mock,此时可以使用 @MockitoBeans 一次性声明所有 Mock,代码更加清晰。这种容器注解机制使得多个 Mock 的声明更加紧凑,提升了测试代码的可读性。

@MockitoSpyBean

@MockitoSpyBean 用于标注一个测试类的字段,表示为该字段类型创建一个 Mockito Spy 并注入到 Spring 容器中。它接受 name 属性指定 Bean 名称,value 和 classes 属性指定要 Spy 的类型,proxyTargetAware 属性控制是否感知目标代理。

该注解是 Spring Boot 3.4 引入的注解,用于替代此前 Spring Boot Test 中的 @SpyBean 注解。它与 @MockitoBean 的区别在于,Spy 是对真实对象的部分 Mock,默认调用真实方法,只在需要时覆盖特定方法的行为;而 Mock 是完全 Mock,默认不调用真实方法。Spy 通过 MockitoBeanRegistrar 工作,在容器启动时为标注字段类型创建一个 Mockito Spy,包装真实 Bean 实例。

从使用场景看,@MockitoSpyBean 适用于需要部分 Mock 的测试场景。例如,测试某个 Service 时,希望大部分方法调用真实实现,但 Mock 某个特定方法(如发送邮件的方法),此时可以使用 @MockitoSpyBean 创建 Spy,只覆盖特定方法的行为。这种机制使得测试可以保留真实业务逻辑的同时,控制特定行为,适合需要部分真实、部分 Mock的复杂测试场景。

@MockitoSpyBeans

@MockitoSpyBeans 用于在一个测试类上声明多个 @MockitoSpyBean,是 @MockitoSpyBean 的容器注解。它接受 value 一个属性,类型为 @MockitoSpyBean 数组,列出要创建的多个 Spy。当需要在一个测试类中创建多个 Spy 时,可以使用该注解避免在类上堆叠多个 @MockitoSpyBean。

该注解的设计目的与 @MockitoBeans 类似,是为了支持 Java 注解不支持重复标注同一注解类型的限制。当测试类需要多个 @MockitoSpyBean 时,可以使用 @MockitoSpyBeans 容器注解一次性声明所有 Spy。每个 @MockitoSpyBean 的语义与单独使用时一致,会创建对应的 Spy 并注入到容器和测试字段中。

从使用场景看,@MockitoSpyBeans 适用于需要多个 Spy 的复杂测试场景。例如,测试某个 Service 依赖多个外部服务,需要为每个外部服务创建 Spy(保留真实行为但 Mock 特定方法),此时可以使用 @MockitoSpyBeans 一次性声明所有 Spy,代码更加清晰。这种容器注解机制使得多个 Spy 的声明更加紧凑,提升了测试代码的可读性。

注解协作关系总结

理解 Spring Boot 注解的最佳方式是把握它们在启动流程中的协作关系。当一个 Spring Boot 应用启动时,注解的执行遵循明确的时序:首先 @SpringBootApplication 触发启动流程,其元注解 @SpringBootConfiguration 标识主配置类,@EnableAutoConfiguration 触发自动配置加载,@AutoConfigurationPackage 注册基础包路径。然后 AutoConfigurationImportSelector 延迟执行,读取 AutoConfiguration.imports 文件,加载所有标注 @AutoConfiguration 的候选类,根据 @AutoConfigureBefore、@AutoConfigureAfter、@AutoConfigureOrder 排序。

排序完成后,框架对每个候选自动配置类应用条件注解判断。@ConditionalOnClass 和 @ConditionalOnMissingClass 通过 ASM 读取字节码判断类存在性,@ConditionalOnBean 和 @ConditionalOnMissingBean 通过扫描已注册 BeanDefinition 判断 Bean 存在性,@ConditionalOnProperty 通过读取 Environment 判断属性条件,@ConditionalOnWebApplication 通过检测类路径判断应用类型。只有所有条件都满足的自动配置类才会被注册到容器,其内部的 @Bean 方法才会被处理。

在 Bean 注册和初始化阶段,@ConfigurationProperties 标注的属性类通过 @EnableConfigurationProperties 或 @ConfigurationPropertiesScan 被注册,ConfigurationPropertiesBindingPostProcessor 在 Bean 初始化时从 Environment 读取属性并绑定,@ConstructorBinding 指示使用构造器绑定,@DefaultValue 提供默认值,@ConfigurationPropertiesBinding 标注的 Converter 提供类型转换支持。绑定完成后,属性类的实例可以被其他 Bean 注入使用。

在应用运行阶段,@Endpoint 标注的端点类通过 EndpointDiscoverer 被扫描,@ReadOperation、@WriteOperation、@DeleteOperation 标注的方法被识别为端点操作,@Selector 标注的参数从请求路径提取,端点通过 @WebEndpoint 或 @JmxEndpoint 限定暴露通道,@EndpointWebExtension 和 @EndpointJmxExtension 提供通道特定的扩展。这些端点通过 /actuator 路径暴露,供运维工具访问。

在测试阶段,@SpringBootTest 加载完整应用上下文进行集成测试,@WebMvcTest、@DataJpaTest 等切片测试注解只加载特定层组件进行单元测试,@AutoConfigureMockMvc、@AutoConfigureTestDatabase 等自动配置注解提供测试辅助工具,@MockitoBean 和 @MockitoSpyBean 提供 Mock 和 Spy 能力,@DisabledInAotMode 和 @EnabledInAotMode 控制 AOT 模式下的测试行为。这些测试注解共同构成了从单元测试到集成测试的完整体系。

掌握这些注解的语义和协作关系,是深入理解 Spring Boot 自动装配机制的关键。在实际开发中,应根据场景选择合适的注解:开发自定义 Starter 时重点使用 @AutoConfiguration 和条件注解,开发业务功能时重点使用 @ConfigurationProperties 和 @SpringBootApplication,开发运维端点时重点使用 @Endpoint 和操作注解,编写测试时根据测试目标选择切片测试或集成测试注解。通过合理运用这些注解,可以充分发挥 Spring Boot 框架的能力,构建高质量的应用。

posted @ 2026-07-24 00:05  减瓦~  阅读(4)  评论(0)    收藏  举报