SpringBoot常用注解
入口
@SpringBootApplication: Spring Boot 应用的核心注解,通常用于标注主启动类。可以把@SpringBootApplication看作是下面三个注解的组合:@EnableAutoConfiguration:启用 Spring Boot 的自动配置机制。
@ComponentScan:扫描@Component、@Service、@Repository、@Controller等注解的类。@Configuration:允许注册额外的 Spring Bean 或导入其他配置类。
@MapperScan: 这是 MyBatis-Spring 提供的注解。它告诉框架去哪里查找 Mapper 接口。它会扫描指定的包,并将其中定义的接口注册为 Spring Bean。
Bean 注册
Spring 容器需要知道哪些类需要被管理为 Bean。除了使用 @Bean 方法显式声明(通常在 @Configuration 类中),更常见的方式是使用 Stereotype(构造型) 注解标记类,并配合组件扫描(Component Scanning)机制,让 Spring 自动发现并注册这些类作为 Bean。这些 Bean 后续可以通过 @Autowired 等方式注入到其他组件中。下面是常见的构造型注解:
@Component:通用的注解,可标注任意类为 Spring 的组件。如果一个 Bean 不知道属于哪个层,可以使用@Component注解标注。@Repository: 对应持久层即 Dao 层,主要用于数据库相关操作。@Service: 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao 层。@Controller: 对应 Spring MVC 控制层,主要用于接受用户请求并调用 Service 层返回数据给前端页面。主要用于传统的 Spring MVC 应用,方法返回值通常是逻辑视图名,需要视图解析器配合渲染页面。如果需要返回数据(如 JSON),则需要在方法上额外添加@ResponseBody注解。@RestController:一个组合注解,等效于@Controller+@ResponseBody。它专门用于构建 RESTful Web 服务的控制器。标注了@RestController的类,其所有处理器方法(handler methods)的返回值都会被自动序列化(通常为 JSON)并写入 HTTP 响应体,而不是被解析为视图名称。在现代前后端分离的应用中,@RestController是更常用的选择。@Configuration: 主要用于声明一个类是 Spring 的配置类。虽然也可以用@Component注解替代,但@Configuration能够更明确地表达该类的用途(定义 Bean)。@Bean: 通常用于标注在方法上,位于一个@Configuration类中。它告诉 Spring “这个方法会返回一个对象,请把这个对象作为 Bean 注册起来”。它适用依赖注入于你无法修改源代码的第三方库中的类,或需要进行复杂逻辑来创建 Bean(例如,根据条件创建、需要配置多个属性)等情况。
如果@Component或@Bean注解没有明确指定 Bean 的名字,Spring 会根据一定的默认规则来生成 Bean 的名字。对于前者, Bean 的名字将是该类的非限定类名(simple class name)的首字母小写;对于后者,Bean 的名字将是@Bean所注解的方法的方法名。
依赖注入
@Autowired用于自动注入依赖项(即其他 Spring Bean)。它可以标注在构造器、字段、Setter 方法或配置方法上,Spring 容器会自动查找匹配类型的 Bean 并将其注入。当存在多个相同类型的 Bean 时,@Autowired默认按类型注入可能产生歧义,此时,可以与@Qualifier结合使用,通过指定 Bean 的名称来精确选择需要注入的实例。@Resource(name="beanName")是 JSR-250 规范定义的注解,也用于依赖注入。它默认按名称 (by Name) 查找 Bean 进行注入。如果未指定name属性,它会尝试根据字段名或方法名查找,如果找不到,则回退到按类型查找(类似@Autowired)。@Resource只能标注在字段 和 Setter 方法上,不支持构造器注入。
注入配置
@Value("${app.name}")注入配置文件(如application.properties或application.yml)中的单个属性值给 Bean 对象的单个属性,可以以冒号的形式提供默认值,如@Value("${server.port:8080}")@ConfigurationProperties用于将一组相关的配置属性绑定到一个 Bean 对象上,它将配置文件的层次结构映射到 Bean 对象的属性结构。如@ConfigurationProperties(prefix = "mail")会绑定以“mail”为前缀的配置文件配置项到一个类上。之后无需在每一个属性上都使用@Value("${mail.name}")注解。
异常处理
Review:异常的层次结构
- Throwable:所有错误和异常的超类。
- Error:严重错误,通常是 JVM 自身的问题,如 OutOfMemoryError、StackOverflowError。程序通常无法处理和恢复,我们一般不捕获 Error。
- Exception:程序本身可以处理的异常。它又分为两类: - Checked Exceptions (受检异常):在编译时就必须处理的异常。编译器会强制你使用 try-catch 捕获或者使用 throws 声明抛出。例如 IOException、SQLException。它们通常是程序在与外部环境(如文件、网络、数据库)交互时可能发生的、可预见的问题。 - Unchecked Exceptions (非受检异常):也叫 RuntimeException。在编译时不会被检查,在运行时才可能抛出。例如 NullPointerException、ArrayIndexOutOfBoundsException。它们通常是由于程序逻辑错误(Bugs)导致的,是应该在编码阶段就避免的。

Review:异常处理的五个关键字
- try:包裹可能会抛出异常的代码块。
- catch:用于捕获并处理 try 块中抛出的特定类型的异常。可以有多个 catch 块来处理不同类型的异常,捕获时遵循从小到大的原则(子类异常在前,父类异常在后)。
- finally:无论是否发生异常,finally 块中的代码总会执行(除非 JVM 退出,如 System.exit())。通常用于释放资源,如关闭文件流、数据库连接等。
- throw:在代码中手动抛出一个异常对象。通常用于在检测到错误条件时主动中断程序流程。
- throws:用在方法签名上,声明该方法可能会抛出某些受检异常。它将处理异常的责任转移给了方法的调用者。
- 注意:try-with-resources (Java 7+)是对 finally 块中资源释放代码的巨大简化。任何实现了 java.lang.AutoCloseable 或 java.io.Closeable 接口的资源都可以使用此语法,JVM 会自动为你调用 close() 方法,从而替代了繁琐的 finally 块:
// 传统方式 (繁琐且容易出错) |
使用 Spring 和第三方库进行全局异常处理
传统的 Java Web 开发(如 Servlet)中,每个方法都可能需要写大量的 try-catch 块来捕获异常,导致业务逻辑和异常处理逻辑耦合在一起,代码非常臃肿。Spring 框架通过 AOP (面向切面编程) 的思想,将异常捕获的逻辑从业务代码中分离出来,进行集中管理,完美地解决了这个问题。这主要通过以下注解实现:
@ControllerAdvice/@RestControllerAdvice:@ControllerAdvice作用于一个类上,表明这个类是一个“全局异常处理器”。它可以拦截并处理所有(或指定包下)@Controller中抛出的异常;@RestControllerAdvice是@ControllerAdvice和@ResponseBody的组合。它不仅具备@ControllerAdvice的功能,还会自动将处理方法的返回值序列化为 JSON 格式。这在构建 RESTful API 时非常常用。@ExceptionHandler: 这个注解作用于方法上,并且该方法必须位于一个被@ControllerAdvice或@RestControllerAdvice注解的类中。它指定了该方法专门负责处理哪种类型的异常。当控制器中抛出匹配类型的异常时,Spring 会自动调用这个被注解的方法,并将异常对象作为参数传入。@SneakyThrows: 当你的方法调用了一个可能会抛出受检异常的、在方法签名上使用了 throws 关键字的方法时,编译器会强制你要么使用 try-catch 来在这里捕获受检异常,要么你的这个方法的签名上也加上 throws 关键字继续抛出受检异常传递给上层处理。而采用了全局异常处理体系的在现代分层架构中,受检异常,比如一个底层的 IOException 可能需要穿透好几层(Repository -> Service -> Controller)才能最终被@RestControllerAdvice捕获。这意味着每一层的每个方法签名都得加上 throws IOException。这非常繁琐。Lombok 库的@SneakyThrows的作用是利用 Java 泛型和类型擦除的一个漏洞,欺骗编译器,让它相信这个受检异常已经被处理了,允许这个受检异常被看作是非受检异常,无 throws 关键字地被抛出,进而简化了代码。当你确定某个受检异常在当前上下文中几乎不可能发生,或者你希望将它交由上层的全局异常处理器来统一处理时,可以使用它来简化代码。- 注意:受检异常是编译器强制你必须处理(try-catch 或 throws)的异常;而非受检异常则由你自行决定是否处理,编译器完全忽略它们。出于这个原因,有程序员会倾向于将自定义的业务异常(比如 UserNotFoundException, OrderStateException)定义为非受检异常,以此避免 throws 污染各层接口。
控制层
@RequestMapping: 最通用的请求映射注解,用于将 HTTP 请求(URL、请求方法等)映射到控制器的方法上。可以用于类级别(定义基础路径)和方法级别。@GetMapping: 专门用于处理 HTTP GET 请求,@GetMapping("users")等价于@RequestMapping(value="/users",method=RequestMethod.GET)。方法级别。@PathVariable: 用于从 URL 的路径中提取值并绑定到方法参数上,用于参数绑定。例如,从 /users/{id} 中获取 id 的值。- 注意:URL 全称是 Uniform Resource Locator(统一资源定位符),一个 URL = 协议+主机名(ip 地址或域名)+端口(80 和 443 会省略)+路径(资源在服务器上的具体位置)+ 查询参数(client 给服务器提供的额外信息,以 ? 开始,用 & 分隔键值对)+片段(指向资源内部的特定部分,又称锚点,以 # 开始)。
@RequestParam: 用于从请求参数或表单数据中提取值并绑定到方法参数上,用于参数绑定。例如,从 /users?name=john 中获取 name 的值。@RequestBody: 用于将 HTTP 请求的 body 内容,即请求体(通常是 JSON 或 XML 数据)反序列化为一个 Java 对象,并绑定到方法参数上。用于参数绑定。@ResponseBody: 标记方法的返回值应该被直接写入 HTTP 响应体中,而不是被解析为视图。@RestController 已经默认包含了此功能。标记在方法上。@ResponseStatus: 用于指定方法成功执行后返回的 HTTP 状态码,例如@ResponseStatus(HttpStatus.CREATED)表示返回 201 Created。
第三方库
Lombok
@Data: 当你给一个类加上@Data注解后,Lombok 会在编译时自动为你生成该类所有字段的getter方法 (例如 getName());setter方法 (例如 setName(…));一个合适的toString()方法,用于打印对象内容;一个合适的equals()和hashCode()方法,用于比较对象是否相等;一个接收所有 final 字段的构造函数。可以把它看作包含了@Getter,@Setter,@ToString,@EqualsAndHashCode和@RequiredArgsConstructor@Getter: 当你给一个类加上@Getter注解后,Lombok 会在编译时,为该类中所有非静态的字段生成对应的 getXxx() 或 isXxx() 方法。@NoArgsConstructor: 生成一个无参构造函数。@AllArgsConstructor: 生成一个包含所有字段的构造函数。@RequiredArgsConstructor: 为 final 或标记为 @NonNull 的字段生成构造函数。@Builder: 实现建造者模式,可以链式调用来创建对象实例。@Slf4j: “Simple Logging Facade for Java” 的缩写。它是一个日志门面,可以与多种日志实现(如 Logback, Log4j2)配合使用。当你给一个类加上@Slf4j注解后,Lombok 会在编译时自动为你生成一个名为 log 的静态 final 日志记录器对象。
MyBatis-Plus
@TableName: 用于类上,将类映射到数据库中的表。@TableField: 用于字段上,用于当字段名与表的列名不一致时进行映射,或者配置自动填充策略。
Swagger
@Tag(name = "..."): 为控制器类提供一个分组标签,在 API 文档中进行分类。@Operation(summary = "..."): 为具体的 API 接口方法提供一个简短的摘要描述。@Schema(description = "..."): 为 DTO 的类或字段提供详细的描述和示例。
Jackson
@JsonFormat: 用于格式化日期时间字段,确保 Java 的日期对象能够按照一定的格式,如 yyyy-MM-dd HH:mm:ss,序列化为 JSON;同样也确保 JSON 可读字符串能够以一定的格式被转化为 Java 对象。
参考
- Java Guide
- 《Java 核心技术 卷 1 开发基础(原书第十二版)》