跳到主要内容 Spring Boot 常用注解速查表:30 个必会注解与实战案例 | 极客日志
Java java
Spring Boot 常用注解速查表:30 个必会注解与实战案例 本文总结了 Spring Boot 开发中常用的 30 个核心注解,涵盖核心、Web、Service、MyBatis-Plus、AOP 及 Lombok 六大类。内容包含各注解的作用说明、真实代码示例、使用场景及常见错误分析,旨在帮助开发者快速掌握依赖注入、请求映射、事务管理、数据持久化及切面编程等关键功能,提升开发效率并规范代码结构。
Spring Boot 常用注解速查表(30 个必会注解 + 实战案例)
一、前言
Spring Boot 开发中,注解无处不在。但注解太多,容易忘记怎么用?
本文整理了30 个最常用的注解 ,分为 7 大类,每个注解都配有:
二、核心注解(5 个)
2.1 @SpringBootApplication
@SpringBootApplication 是 Spring Boot 核心 ,整合 、 、 三大核心注解的功能,用于标注 Spring Boot 项目的 ,是开启 Spring Boot 自动配置、组件扫描的核心入口,简化项目配置,一键启动 Spring Boot 应用。
组合注解
@Configuration
@EnableAutoConfiguration
@ComponentScan
主启动类
含 @Configuration:将类标记为配置类,支持注解式配置;
含 @EnableAutoConfiguration:开启自动配置,自动加载适配的框架配置;
含 @ComponentScan:扫描主类所在包及子包的 @Component 系列注解(@Controller/@Service /@Mapper 等),将 Bean 纳入容器。
package com.liu;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.liu.mapper")
@SpringBootApplication
public class SimpleAccountingApplication {
public static void main (String[] args) {
SpringApplication.run(SimpleAccountingApplication.class, args);
}
}
使用场景: 每个 Spring Boot 项目有且仅有一个启动类
package com.liu.config;
@SpringBootApplication
public class Application {}
package com.liu;
@SpringBootApplication
public class Application {}
2.2 @Component 作用: @Component 是 Spring 框架的核心通用组件注解 ,用于标记普通 Java 类为Spring 容器可管理的 Bean ,标注后类会被 Spring 扫描并实例化,纳入 IoC 容器统一管理,实现对象的依赖注入与生命周期管控,解耦组件间依赖。
它是 @ComponentScan 扫描的基础注解,@Controller、@Service、@Repository 等注解均基于它扩展,分别适配控制层、业务层、数据层等场景,@Component 则适用于无明确分层的通用组件,是 Spring 组件化开发的基础。
@Component
public class JwtUtil {
@Value("${jwt.secret}")
private String secret;
public String generateToken (Long userId, Integer role, String username) {
}
}
@Controller:控制器
@Service:服务层
@Repository:数据访问层
@Configuration:配置类
2.3 @Autowired 作用: @Autowired 是 Spring 核心的自动依赖注入注解 ,用于实现 Spring IoC 容器中 Bean 的自动装配,简化组件间依赖管理,无需手动创建对象实例,直接注入所需依赖 Bean,大幅降低代码耦合度。
其默认按类型(byType) 匹配容器中的 Bean 完成注入,支持标注在类的构造方法、字段、setter 方法上;若同类型 Bean 存在多个,可结合 @Qualifier 按名称精准匹配,或用 @Primary 指定默认注入 Bean。
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Autowired
private JwtUtil jwtUtil;
public User login (String username, String password) {
return userMapper.selectByUsername(username);
}
}
使用场景: 注入 Service、Mapper、工具类等
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
private final JwtUtil jwtUtil;
}
不可变(final 修饰)
避免循环依赖
便于单元测试
2.4 @Value 作用:注入配置文件中的值 。@Value 是 Spring 框架的属性注入注解 ,核心用于将配置文件值、系统属性、常量值 注入到 Spring 容器管理的 Bean 的字段 / 方法参数中,实现配置与代码解耦,无需硬编码配置信息,简化配置读取与使用。
支持直接注入常量(如 @Value("hello")),更常用的是通过 ${key} 读取 application.properties/yaml 中的配置项(如 @Value("${server.port}")),可标注在 Bean 的字段、构造方法参数、setter 方法上,适配 Spring 管理的所有组件(@Component/@Service/@Controller 等)。
@Component
public class JwtUtil {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private Long expiration;
}
jwt:
secret: my-secret-key-12345
expiration: 7200000
使用场景: 注入配置参数(密钥、超时时间、文件路径等)
@Value("${jwt.secretKey}")
private String secret;
@Value("${jwt.secret:default-secret}")
private String secret;
2.5 @Configuration 作用: @Configuration 是 Spring 框架的核心配置类注解 ,用于标记 Java 类为Spring 配置类 ,替代传统 XML 配置文件,实现纯注解式配置开发。
标注该注解的类会被 Spring 解析,类中通过 @Bean 注解修饰的方法,其返回对象会被注册为 Spring IoC 容器中的 Bean,由容器统一管理实例化、依赖注入与生命周期,是 Spring 注解驱动开发的核心基础。
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private JwtInterceptor jwtInterceptor;
@Override
public void addInterceptors (InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor).addPathPatterns("/**" );
}
@Override
public void addCorsMappings (CorsRegistry registry) {
registry.addMapping("/**" ).allowedOriginPatterns("*" ).allowedMethods("GET" , "POST" , "DELETE" , "PUT" );
}
}
三、Web 层注解(8 个)
3.1 @RestController 作用: @RestController 是 Spring MVC 的组合注解 ,整合 @Controller和@ResponseBody 核心功能,专门用于标注RESTful 风格的控制器类 ,是 Spring Boot 开发接口的核心注解,无需额外配置即可实现 JSON/XML 等数据的返回。
继承 @Controller:将类标记为 Spring MVC 控制器,接收前端请求;
整合 @ResponseBody:默认对类中所有 @RequestMapping 系列注解的方法 生效,自动将方法返回值序列化为 JSON/XML 格式,直接写入响应体,替代传统视图跳转,适配前后端分离场景。
对比单独使用 @Controller+ 方法级 @ResponseBody,该注解简化了 REST 接口的开发,无需在每个接口方法上重复标注 @ResponseBody。
等价于: @Controller + @ResponseBody
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/login")
public Result<String> login (@RequestParam String username, @RequestParam String password) {
return Result.success("登录成功" , token);
}
}
注解 返回类型 使用场景 @Controller视图(HTML) 传统 MVC 项目 @RestControllerJSON 数据 前后端分离项目
3.2 @RequestMapping 作用: @RequestMapping 是 Spring MVC核心请求映射注解 ,用于将前端 HTTP 请求 与后端控制器方法 建立绑定关系,使 Spring 能精准匹配请求并调用对应方法处理,是开发 Web 接口 / 页面请求的基础注解,可标注在控制器类 或方法 上。
@RestController
@RequestMapping("/user")
public class UserController {
@RequestMapping(value = "/login", method = {RequestMethod.GET, RequestMethod.POST})
public Result<String> login () {
}
}
为简化 method 属性配置,Spring 提供了 @RequestMapping 的专用衍生注解 ,语义更清晰,开发中优先使用:
@GetMapping:等价于 @RequestMapping(method = RequestMethod.GET),处理 GET 查询请求;
@PostMapping:等价于 @RequestMapping(method = RequestMethod.POST),处理 POST 新增 / 提交请求;
@PutMapping:等价于 @RequestMapping(method = RequestMethod.PUT),处理 PUT 更新请求;
@DeleteMapping:等价于 @RequestMapping(method = RequestMethod.DELETE),处理 DELETE 删除请求。
@GetMapping("/list")
@PostMapping("/add")
@PutMapping("/update")
@DeleteMapping("/delete")
3.3 @RequestParam 作用: 获取 URL 参数(?key=value)
@PostMapping("/login")
public Result<String> login (@RequestParam String username, @RequestParam String password) {
}
@GetMapping("/list")
public Result<List<Bill>> list (
@RequestParam(required = false) String keyword, // 可选参数
@RequestParam(defaultValue = "1") Integer page // 默认值
) {
}
3.4 @RequestBody @RequestBody 是 Spring MVC 的核心请求体解析注解,专门用于接收前端通过 HTTP 请求体传递的非表单格式数据 (如 JSON、XML),并自动将请求体中的数据反序列化为指定的 Java 实体类 / Map / 字符串对象,绑定到控制器方法的参数上,是前后端分离场景中接收 JSON 请求 的必备注解。
@PostMapping("/register")
public Result<User> register (@RequestBody User user) {
}
使用场景: POST/PUT 请求,提交 JSON 数据
@GetMapping("/list")
public Result<List<Bill>> list (@RequestBody Map<String,Object> params) {
}
@GetMapping("/list")
public Result<List<Bill>> list (@RequestParam String keyword) {
}
3.5 @PathVariable @PathVariable 是 Spring MVC 的路径参数绑定注解 ,核心用于提取 URL 路径中的动态占位符参数 ,并自动将其转换为指定类型后绑定到控制器方法的入参上,是开发RESTful 风格动态接口 的核心注解(如 /user/123、/order/456/detail这类含动态 ID 的请求)。
@DeleteMapping("/delete/{id}")
public Result<Boolean> delete (@PathVariable Long id) {
billService.deleteById(id);
return Result.success("删除成功" );
}
@GetMapping("/user/{userId}/bill/{billId}")
public Result<Bill> getBill (@PathVariable Long userId, @PathVariable Long billId) {
}
3.6 @ResponseBody 作用: @ResponseBody 是 Spring MVC 的核心响应体处理注解,核心作用是将控制器方法的返回值,直接序列化为 JSON/XML 等格式的数据流,写入 HTTP 响应体(Response Body) ,替代传统的视图跳转(如跳转到 JSP/HTML 页面),是实现前后端分离接口 和RESTful 风格接口 的关键注解。
生效范围 :可标注在控制器方法上 (仅对当前方法生效),也可标注在控制器类上 (对类中所有 @RequestMapping 系列注解的方法生效);
自动序列化 :Spring 默认通过 Jackson 框架完成转换,将 Java 对象(实体类、Map、集合等)自动序列化为 JSON 字符串,无需手动处理;
返回值适配 :支持所有 Java 基础类型、自定义实体类、Map、List 等,均能被自动序列化;
与 @RestController 的关系 :@RestController是@Controller + @ResponseBody的组合注解,标注 @RestController 的类,底层已默认添加类级别的 @ResponseBody,无需重复标注。
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/toLogin")
public String toLogin () {
return "redirect:/login.html" ;
}
@ResponseBody
@PostMapping("/login")
public Result<String> login () {
return Result.success("登录成功" );
}
}
3.7 @Valid / @Validated 作用: @Valid 和 @Validated 均是 Spring 中用于开启参数校验 的核心注解,基于 JSR-380(Bean Validation 2.0)规范实现,配合 @NotNull/@NotBlank/@Min 等校验注解,可自动完成对实体类参数 的合法性校验,替代手动 if 判断,简化参数校验逻辑,是开发接口时的必备注解。
二者核心作用一致,但所属规范、功能特性、适用场景 存在明确区别,其中 @Validated 是 Spring 对 @Valid 的增强扩展版 ,开发中可根据需求选择。
@Data
public class User {
@NotBlank(message = "用户名不能为空")
@Size(min = 3, max = 20, message = "用户名长度必须在 3-20 个字符之间")
private String username;
@NotBlank(message = "密码不能为空")
@Size(min = 6, max = 10, message = "密码长度必须在 6-10 个字符之间")
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{6,10}$", message = "密码必须包含大小写字母和数字")
private String password;
@Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
private String phone;
}
@PostMapping("/register")
public Result<User> register (@RequestBody @Valid User user) {
return userService.register(user);
}
注解 作用 示例 @NotNull不能为 null @NotNull(message = "ID 不能为空")@NotBlank不能为空字符串 @NotBlank(message = "用户名不能为空")@Size长度限制 @Size(min = 3, max = 20)@Pattern正则验证 @Pattern(regexp = "^1[3-9]\\d{9}$")@Min / @Max数值范围 @Min(value = 0, message = "金额不能为负")@Email邮箱格式 @Email(message = "邮箱格式不正确")
3.8 @ExceptionHandler 作用: @ExceptionHandler 是 Spring MVC 提供的异常处理核心注解 ,核心作用是捕获并处理 Spring 容器中指定类型的异常 ,可标注在控制器(@Controller/@RestController)或全局异常处理器的方法上,实现异常的局部 / 全局统一处理 ,替代传统的 try-catch 代码块,简化异常处理逻辑,让接口返回统一、友好的错误响应。
精准捕获异常 :通过注解参数指定要处理的单个 / 多个异常类型 (如 @ExceptionHandler(NullPointerException.class)),仅捕获匹配的异常;
局部 / 全局生效:
标注在普通控制器类 中:仅处理当前控制器 中方法抛出的异常(局部生效);
标注在标注了 @RestControllerAdvice/@ControllerAdvice 的全局异常类 中:处理整个项目所有控制器 抛出的异常(全局生效,开发中最常用);
灵活返回结果 :方法返回值支持与普通控制器方法一致的类型(如 JSON 对象、视图名称),适配前后端分离(返回 JSON)和传统视图开发场景;
自动注入异常对象 :方法入参可直接接收捕获到的异常实例 ,便于获取异常信息(如错误消息、堆栈轨迹)。
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<String> handleValidException (MethodArgumentNotValidException e) {
String message = e.getBindingResult().getFieldError().getDefaultMessage();
return Result.fail(message);
}
@ExceptionHandler(RuntimeException.class)
public Result<String> handleRuntimeException (RuntimeException e) {
return Result.fail(e.getMessage());
}
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
public Result<String> handleSQLException (SQLIntegrityConstraintViolationException e) {
if (e.getMessage().contains("Duplicate entry" )) {
return Result.fail("数据已存在" );
}
return Result.fail("数据库操作失败" );
}
}
使用场景: 统一处理异常,避免在每个方法中 try-catch
类上标注的是全局异常处理注解 :@RestControllerAdvice 是 Spring MVC 提供的全局异常处理 + 数据绑定 + 返回值增强的核心组合注解 ,是 @ControllerAdvice + @ResponseBody 的整合版,专门适配前后端分离项目 ,核心作用是实现全局统一的异常处理、全局数据绑定、全局返回值封装 ,无需在每个控制器重复编写逻辑,让接口返回格式统一、异常处理更简洁。
四、Service 层注解(2 个)
4.1 @Service 作用: @Service 是 Spring 框架中业务层组件专用注解 ,属于 @Component 的分层扩展注解 ,核心作用是标记普通 Java 类为Spring IoC 容器可管理的业务层 Bean ,让类被 @ComponentScan 自动扫描并纳入容器统一管理,是 Spring 分层开发(控制层 / 业务层 / 数据层)的核心标识之一。
专属业务层标识 :语义上明确标注类的作用是业务逻辑处理 (如业务规则判断、数据层调用、事务处理等),替代通用的 @Component,让代码分层更清晰、可读性更强;
自动扫描注册 Bean :与 @Component 一致,Spring 启动时通过组件扫描,自动将标注该注解的类实例化并注册到 IoC 容器,无需手动配置 Bean;
支持依赖注入 :容器中的 @Service 组件,可通过 @Autowired/@Resource 等注解,自动注入依赖的其他 Bean(如 @Repository 数据层组件);
天然支持事务管理 :配合 Spring 声明式事务 @Transactional 注解,可直接在 @Service 方法上标注,实现业务层的事务控制(核心适用场景)。
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
@Override
public User login (String username, String password) {
User user = userMapper.selectByUsername(username);
if (user == null ) {
throw new RuntimeException ("用户不存在" );
}
if (!user.getPassword().equals(password)) {
throw new RuntimeException ("密码错误" );
}
return user;
}
}
4.2 @Transactional 作用: @Transactional 是 Spring 框架实现声明式事务管理 的核心注解,基于 AOP(面向切面编程)实现,无需手动编写 try-catch 事务提交 / 回滚代码,仅通过注解标注即可为方法 / 类开启事务控制,保证一组数据库操作的原子性 (要么全部成功提交,要么任意一步失败则整体回滚),是解决数据库事务问题的标准方案。
@Transactional 提供多个属性用于自定义事务行为,开发中可根据业务需求配置,核心常用属性如下:
属性名 作用 可选值示例、默认值 readOnly设置事务是否为只读 (适用于仅查询操作,提升数据库性能) true/false(默认)isolation设置事务隔离级别 (解决并发事务的脏读 / 不可重复读 / 幻读问题) READ_UNCOMMITTED/READ_COMMITTED/REPEATABLE_READ/SERIALIZABLE 数据库默认隔离级别(如 MySQL 为 REPEATABLE_READ)propagation设置事务传播行为 (解决方法嵌套调用时,事务的创建 / 复用规则) REQUIRED(最常用)/REQUIRES_NEW/SUPPORTS 等rollbackFor指定触发回滚的异常类型 (可包含 checked 异常) Exception.class/BusinessException.class 默认:RuntimeException.classnoRollbackFor指定不触发回滚的异常类型 IllegalArgumentException.class 默认:无timeout设置事务超时时间 (单位:秒),超时则自动回滚 3/5 默认:-1(无超时限制)
@Service
public class AnnouncementServiceImpl implements AnnouncementService {
@Transactional
public void publishAnnouncement (Announcement announcement) {
announcementMapper.insert(announcement);
logMapper.insert(new Log ("发布公告" , announcement.getId()));
}
}
@Transactional
private void saveUser (User user) {
}
@Transactional
public void saveUser (User user) {
}
五、MyBatis-Plus 注解(7 个)
5.1 @TableName 作用: @TableName 是 MyBatis-Plus(MP)框架的核心表映射注解 ,专门用于解决Java 实体类 与数据库表 之间的名称映射问题,通过注解直接指定实体类对应的数据库表名,替代传统 MyBatis 中手动编写 SQL 映射或 XML 配置表名的操作,简化 MP 的单表 CRUD 开发,是 MP 实现零 SQL 单表操作 的基础注解之一。
MyBatis-Plus 有默认表名映射规则 :实体类名(驼峰命名)自动转换为数据库表名(下划线命名) (如 Java 实体 UserInfo → 数据库表 user_info)。
当实体类名与数据库表名不一致 / 不满足驼峰转下划线规则 时(如实体 User 对应表 t_user、实体 Order 对应表 order_info),默认规则失效,需通过 @TableName 手动指定映射关系,否则 MP 执行 CRUD 时会因表名不存在抛出 SQL 异常。
@Data
@TableName("user")
public class User {
private Long userId;
private String username;
}
5.2 @TableId 作用: @TableId 是 MyBatis-Plus(MP)框架的专属主键映射注解 ,核心作用是将Java 实体类的属性 与数据库表的主键字段 建立绑定关系,同时指定主键的生成策略 (如自增、雪花算法、UUID 等),是 MP 实现单表 CRUD 时主键自动处理 的核心注解,替代传统 MyBatis 手动配置主键映射和生成逻辑的操作。
MyBatis-Plus 默认会将实体类中名为 id 的属性 映射为数据库表的主键字段,且默认使用雪花算法(IdType.ASSIGN_ID) 生成主键值。
当实体主键属性名与表主键字段名不一致 (如实体 userId 对应表 user_id)、需要自定义主键生成策略 (如数据库自增、UUID)时,默认规则失效,需通过 @TableId 显式配置,否则 MP 执行新增 / 查询等操作时会因主键映射错误 / 生成规则不符抛出异常。
@Data
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long userId;
}
策略 说明 IdType.AUTO数据库自增 IdType.ASSIGN_ID雪花算法生成 ID(默认) IdType.INPUT手动输入
5.3 @TableField 作用: @TableField 是 MyBatis-Plus(MP)框架的普通字段专属映射注解 ,核心作用是将Java 实体类的非主键属性 与数据库表的普通字段 建立绑定关系,同时支持配置字段是否参与 CRUD、是否为查询条件、字段填充规则等特性,是 MP 解决非主键字段映射不一致 、实现字段精细化控制的核心注解,替代传统 MyBatis 手动在 XML/SQL 中配置字段映射的操作。
MyBatis-Plus 有默认普通字段映射规则 :实体类属性名(驼峰命名)自动转换为数据库表字段名(下划线命名) (如实体 userName → 表 user_name)。
当实体属性名与表字段名不一致 / 不满足驼峰转下划线规则 、需要排除某些字段不参与 MP 的自动 CRUD 、需要配置字段自动填充 (如创建时间、更新时间)时,默认规则无法满足需求,需通过 @TableField 显式配置,否则 MP 执行操作时会因字段映射错误抛出 SQL 异常,或无法实现字段的精细化控制。
@Data
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long userId;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
}
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill (MetaObject metaObject) {
this .strictInsertFill(metaObject, "createTime" , LocalDateTime.class, LocalDateTime.now());
this .strictInsertFill(metaObject, "updateTime" , LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill (MetaObject metaObject) {
this .strictUpdateFill(metaObject, "updateTime" , LocalDateTime.class, LocalDateTime.now());
}
}
5.4 @Version 作用: @Version 是 MyBatis-Plus(MP)框架实现乐观锁机制 的专属核心注解,核心作用是将Java 实体类的属性 与数据库表的版本数字段 绑定,让 MP 自动基于该字段实现乐观锁的版本控制,解决多线程 / 多用户并发更新数据时的脏写问题 (避免多个请求同时修改同一条数据,导致数据覆盖、一致性丢失),是 MP 简化乐观锁开发的关键注解。
@Data
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long userId;
@Version
private Integer version;
}
UPDATE user SET username = ?, version = version + 1 WHERE user_id = ? AND version = ?
5.5 @TableLogic 作用: @TableLogic 是 MyBatis-Plus(MP)框架实现逻辑删除 的专属核心注解,核心作用是将 Java 实体类的属性与数据库表的逻辑删除标识字段 绑定,让 MP 自动将单表 CRUD 中的物理删除(DELETE)操作 替换为逻辑删除(UPDATE)操作 ,同时自动过滤查询 / 更新结果中已逻辑删除的数据,实现数据的「假删除、软删除」,避免真实删除数据导致的历史数据丢失、关联查询异常问题,是 MP 简化逻辑删除开发的关键注解。
@Data
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long userId;
@TableLogic
private Integer deleted;
}
UPDATE user SET deleted = 1 WHERE user_id = 1 AND deleted = 0
SELECT * FROM user WHERE deleted = 0
5.6 @MapperScan 作用: @MapperScan 是 MyBatis 及 MyBatis-Plus 框架的核心 Mapper 接口扫描注解 ,核心作用是指定项目中 Mapper 接口的扫描包路径 ,让框架自动扫描该包下所有的 Mapper 接口,并为每个接口动态生成代理实现类 ,最终将这些代理类注册到 Spring IoC 容器中,实现 Mapper 接口的依赖注入和数据库操作调用,是整合 MyBatis/MP 与 SpringBoot 的关键注解。
@MapperScan("com.liu.mapper")
@SpringBootApplication
public class SimpleAccountingApplication {
public static void main (String[] args) {
SpringApplication.run(SimpleAccountingApplication.class, args);
}
}
使用场景: 启动类上,扫描所有 Mapper 接口
5.7 @Select / @Insert / @Update / @Delete 作用: @Select、@Insert、@Update、@Delete 是 MyBatis/MyBatis-Plus(MP)框架的核心原生 SQL 注解 ,属于 MyBatis 基础注解(MP 完全兼容),核心作用是直接在 Mapper 接口的方法上标注对应的 SQL 语句 ,让框架将接口方法与 SQL 语句直接绑定 ,调用接口方法时自动执行标注的 SQL,实现数据库的查询、新增、更新、删除 操作。
这组注解替代了传统 MyBatis 中XML 映射文件 的编写(如 UserMapper.xml 中的 <select>/<insert>标签),实现「SQL 与 Mapper 接口方法一体化 」,简化单表 / 多表的 SQL 开发,是 MyBatis/MP 中除了 MP 自动 CRUD 外,自定义 SQL 的核心实现方式 。
@Mapper
public interface UserMapper extends BaseMapper <User> {
@Select("SELECT * FROM user WHERE username = #{username}")
User selectByUsername (String username) ;
@Update("UPDATE user SET status = #{status} WHERE user_id = #{userId}")
int updateStatus (@Param("userId") Long userId, @Param("status") Integer status) ;
}
优先使用 #{参数名}:实现预编译参数绑定 ,MyBatis 会自动处理参数类型转换,有效防止 SQL 注入 ,是开发中的标准用法;
慎用${参数名}:直接将参数拼接到 SQL 中,无预编译处理,有 SQL 注入风险,仅适用于表名、字段名动态拼接 (如 SELECT * FROM ${tableName});
多参数绑定:若方法有多个独立入参,可通过 @Param("参数名") 指定参数名,保证#{}中名称匹配:
@Select("SELECT * FROM t_user WHERE username = #{name} AND age = #{age}")
User selectByUsernameAndAge (@Param("name") String username, @Param("age") Integer age) ;
使用场景: 简单 SQL 可以用注解,复杂 SQL 建议用 XML
六、AOP 注解(3 个)
6.1 @Aspect 作用: @Aspect 是 Spring 框架实现 AOP(面向切面编程)的核心注解 ,核心作用是标记一个普通 Java 类为「切面类(Aspect)」 ,让 Spring 识别该类为 AOP 的核心载体 —— 用于封装切入点(Pointcut) 和通知(Advice) 逻辑,实现业务代码与非业务横切逻辑(如日志记录、事务控制、权限校验、性能监控)的解耦,是 Spring AOP 开发的基础注解。
@Aspect
@Component
@Slf4j
public class RoleCheckAspect {
@Before("@annotation(requireRole)")
public void checkRole (JoinPoint joinPoint, RequireRole requireRole) {
int [] allowedRoles = requireRole.value();
int userRole = TokenHelper.getRole(request);
boolean hasPermission = Arrays.stream(allowedRoles).anyMatch(role -> role == userRole);
if (!hasPermission) {
throw new RuntimeException ("无权限访问" );
}
}
}
@Aspect仅标记该类为切面,不会自动将其注册到 Spring IoC 容器 ,必须配合 @Component(或 @Service/@Repository),让 Spring 扫描并管理该 Bean,否则 AOP 逻辑完全失效。
@Around是唯一能控制目标方法执行的通知,必须遵守 3 个规则,否则会导致业务异常:
必须调用 joinPoint.proceed():执行目标业务方法,省略则目标方法不会执行;
必须返回 proceed() 的结果:否则目标方法的返回值会丢失(前端获取不到数据);
异常必须重新抛出:若捕获异常,需手动抛出,否则后续异常处理器(如 @RestControllerAdvice)无法感知。
避免写过于宽泛的表达式(如 execution(* *..*.*(..))),会匹配所有方法,导致性能损耗;
表达式中的包名、类名需与实际一致,否则无法匹配目标方法,切面逻辑不生效。
Spring AOP 默认基于动态代理 实现,存在 2 个核心限制,会导致切面逻辑不生效:
4.1 仅对 Spring 容器中的 Bean 生效
非 Spring 管理的类(未标注 @Component/@Service 等),其方法无法被切面增强,解决方案:将类注册为 Spring Bean。
private/protected/default 访问权限的方法,Spring AOP 不会生成代理,切面逻辑无法织入,解决方案:将方法改为 public(若需增强非公共方法,需使用 AspectJ 原生织入,而非 Spring AOP)。
同一类中,无切面增强的方法调用有切面增强的方法 ,因未经过 Spring 代理对象,切面逻辑无法织入,这是 Spring AOP 最常见的坑:
@Service
public class UserService {
public void test () {
this .saveUser();
}
public void saveUser () {
}
}
将方法拆分到不同的 Spring Bean 中,通过依赖注入调用;
注入自身的代理对象,通过代理对象调用(需开启暴露代理);
使用 AopContext.currentProxy() 获取代理对象调用。
6.2 @Before / @After / @Around 作用: @Before、@After、@Around 是 Spring AOP 中最核心的三大通知注解 ,与 @Aspect 切面类配合使用,核心作用是定义横切逻辑的织入时机 —— 将日志记录、性能监控、权限校验等通用非业务逻辑,精准织入到目标方法的执行前、执行后、执行前后全生命周期 ,实现业务代码与横切逻辑的解耦,是 Spring AOP 实现「无侵入式功能增强」的核心载体。
三者均标注在切面类(@Aspect + @Component 标注)的方法上,需绑定切入点(@Pointcut) 指定增强的目标方法,共同覆盖目标方法的核心执行节点,其中 @Around 功能最全面,可实现前两者的所有效果。
核心定义 :标注在切面类方法上,指定横切逻辑在目标方法执行前执行 ,是最基础的通知类型。
核心作用:用于实现目标方法执行前的预处理逻辑 ,无返回值,无法修改目标方法的入参,也无法控制目标方法是否执行。
核心适用场景 :权限校验、接口入参日志记录、资源初始化(如数据库连接准备)、请求参数预处理等。
核心定义 :标注在切面类方法上,指定横切逻辑在目标方法执行结束后执行(无论目标方法是否抛出异常) ,是「必执行」的通知类型。
核心作用 :用于实现目标方法执行后的收尾逻辑 ,无返回值,无法获取目标方法返回值或异常信息,仅做最终兜底处理。
核心适用场景 :资源统一释放(如关闭数据库连接、清空临时缓存、关闭文件流)、方法执行完成的通用日志标记等。
核心定义 :标注在切面类方法上,指定横切逻辑包裹目标方法的全执行生命周期(执行前 + 执行中 + 执行后 + 异常时) ,是功能最强大、最灵活的通知类型。
核心作用 :可实现目标方法的全流程控制 :能修改入参、手动控制目标方法是否执行、获取 / 修改返回值、捕获处理异常,完全覆盖 @Before 和 @After 的能力。
核心适用场景 :性能监控(统计方法执行耗时)、全流程日志记录(入参 + 执行结果 + 耗时)、核心接口的权限控制、方法返回值缓存等。
注解 织入时机 核心能力 方法入参 关键特性 核心限制 @Before 目标方法执行前 仅做前置预处理,无返回值 JoinPoint(获取方法信息) 执行时机固定,逻辑简单 无法修改入参、无法控制目标方法执行、无返回值 @After 目标方法执行结束后(必执行) 仅做最终收尾处理,无返回值 JoinPoint(获取方法信息) 无论异常与否都会执行 无法获取返回值、无法捕获异常、无返回值 @Around 目标方法执行前后全生命周期 修改入参、控制执行、获取 / 修改返回值、捕获异常,覆盖前两者所有能力 ProceedingJoinPoint(含执行方法) 功能最全面,灵活性最高 必须调用 proceed() 执行目标方法,必须返回结果
JoinPoint :基础入参,可获取目标方法的类名、方法名、入参数组等信息,@Before/@After 可直接使用;
ProceedingJoinPoint :继承自 JoinPoint,新增 proceed() 方法 ——手动执行目标业务方法 ,是 @Around 的专属入参,无此方法则无法触发目标方法执行。
以业务层方法(@Service) 为增强目标,实现「日志记录 + 性能监控」功能,分别演示三者的使用方式,统一绑定同一个切入点,便于对比差异。
引入 Spring AOP 起步依赖(Spring Boot 自动配置):
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-aop</artifactId >
</dependency >
import org.springframework.stereotype.Service;
@Service
public class UserService {
public String getUserById (Long id) throws InterruptedException {
Thread.sleep(80 );
return "查询到用户 ID:" + id;
}
public void deleteUserById (Long id) {
throw new RuntimeException ("模拟删除失败:用户不存在" );
}
}
切面类实现(@Aspect + @Component)
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.util.Arrays;
@Aspect
@Component
public class AopAdviceDemoAspect {
private static final Logger log = LoggerFactory.getLogger(AopAdviceDemoAspect.class);
@Pointcut("execution(public * com.example.demo.service.UserService.*(..))")
public void userServicePointcut () {
}
@Before("userServicePointcut()")
public void doBefore (JoinPoint joinPoint) {
String methodFullName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
log.info("【@Before 前置通知】方法{}开始执行,入参:{}" , methodFullName, Arrays.toString(args));
}
@After("userServicePointcut()")
public void doAfter (JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
log.info("【@After 最终通知】方法{}执行结束(必执行)" , methodName);
}
@Around("userServicePointcut()")
public Object doAround (ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
String methodFullName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
Object[] args = joinPoint.getArgs();
log.info("【@Around 执行前】方法{}入参:{}" , methodFullName, Arrays.toString(args));
Object result = null ;
try {
result = joinPoint.proceed();
long costTime = System.currentTimeMillis() - startTime;
log.info("【@Around 执行成功】方法{}返回值:{},耗时:{}ms" , methodFullName, result, costTime);
} catch (Throwable e) {
long costTime = System.currentTimeMillis() - startTime;
log.error("【@Around 执行异常】方法{}执行失败,耗时:{}ms,异常:{}" , methodFullName, costTime, e.getMessage());
throw e;
}
return result;
}
}
@Aspect
@Component
public class LogAspect {
@Before("execution(* com.liu.controller.*.*(..))")
public void before (JoinPoint joinPoint) {
log.info("方法执行前:{}" , joinPoint.getSignature().getName());
}
@After("execution(* com.liu.controller.*.*(..))")
public void after (JoinPoint joinPoint) {
log.info("方法执行后:{}" , joinPoint.getSignature().getName());
}
@Around("execution(* com.liu.controller.*.*(..))")
public Object around (ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long end = System.currentTimeMillis();
log.info("方法执行耗时:{}ms" , end - start);
return result;
}
}
6.3 自定义注解 作用:自定义注解是 Java 提供的元编程能力 ,允许开发者根据业务需求定义专属的注解类型,结合 Spring 框架的 AOP、反射等特性,可实现无侵入式的业务增强 (如自定义权限校验、操作日志、接口限流等),是企业级开发中实现通用逻辑复用、简化业务代码的核心手段。
自定义注解的核心价值是将通用逻辑与业务代码解耦 :通过注解标记需要增强的类 / 方法 / 属性,再通过注解解析器 (反射 / AOP)识别注解并执行对应的横切逻辑,无需修改业务代码即可实现功能增强。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequireRole {
int [] value() default {};
}
@RestController
@RequestMapping("/admin")
public class AdminController {
@RequireRole({Constants.ROLE_ADMIN})
@GetMapping("/users")
public Result<List<User>> getAllUsers () {
return Result.success(userService.list());
}
}
@Aspect
@Component
public class RoleCheckAspect {
@Before("@annotation(requireRole)")
public void checkRole (JoinPoint joinPoint, RequireRole requireRole) {
}
}
七、Lombok 注解(5 个)
<dependency >
<groupId > org.projectlombok</groupId >
<artifactId > lombok</artifactId >
<version > 1.18.30</version >
<scope > provided</scope >
</dependency >
7.1 @Data 作用: @Data 是 Lombok 框架的核心注解 ,核心作用是自动为 Java 类生成通用的模板代码 ,包括所有成员变量的 getter/setter 方法、toString()、equals()、hashCode() 方法,以及全参 / 无参构造器的核心部分,彻底消除实体类、POJO 类中大量重复的模板代码,大幅简化类的编写,提升开发效率并减少代码维护成本。
@Data
public class User {
private Long userId;
private String username;
private String password;
}
7.2 @NoArgsConstructor / @AllArgsConstructor 作用: @NoArgsConstructor 和 @AllArgsConstructor 是 Lombok 框架的核心基础注解 ,二者配合使用可分别为 Java 类自动生成无参构造器 和全参构造器 ,彻底消除手动编写构造器的模板代码,简化对象实例化操作,常与 @Data 组合成为实体类、POJO 类的标配注解。
构造器是 Java 类实例化对象的核心入口,手动编写多参构造器不仅繁琐,还会在新增 / 删除字段时需同步修改,而这两个注解通过编译期字节码增强 自动生成构造器,开发时仅需注解标注,编译后字节码中会包含对应构造器,与手动编写完全一致且运行时无性能损耗。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long userId;
private String username;
}
7.3 @RequiredArgsConstructor 作用: @RequiredArgsConstructor 是 Lombok 框架的核心构造器注解 ,核心作用是为 Java 类自动生成包含「必须初始化成员变量」的构造器 ,这里的「必须初始化变量」特指被 final 修饰的成员变量 和被 @NonNull 注解标注的成员变量 (这两类变量在 Java 语法中要求必须初始化,否则编译报错)。该注解精准解决了「仅为关键变量生成带参构造器」的需求,避免全参构造器参数冗余,常与 @Data、@NoArgsConstructor 等注解组合使用,是实体类、配置类、服务类开发中的常用注解。
@Service
@RequiredArgsConstructor
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
private final JwtUtil jwtUtil;
}
代码简洁
不可变(final)
Spring 自动注入
7.4 @Slf4j 作用: @Slf4j 是 Lombok 框架的核心日志注解 ,核心作用是为 Java 类自动生成基于 SLF4J 规范的日志对象 (private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(当前类.class);),彻底消除手动声明日志对象的模板代码,直接通过 log.info()/log.error() 等方法打印日志,是企业级 Java 开发中日志记录的标配注解,与 @Data、@Service、@RestController 等注解无缝配合使用。
@Service
@Slf4j
public class UserServiceImpl implements UserService {
public User login (String username, String password) {
log.info("用户登录:{}" , username);
log.error("登录失败:{}" , username);
log.debug("调试信息:{}" , username);
}
}
7.5 @Builder 作用: @Builder 是 Lombok 框架的核心创建型模式注解 ,核心作用是为 Java 类自动实现建造者(Builder)设计模式 ,通过链式调用 的方式灵活创建对象,替代传统的无参构造 + 多次 setter、多参构造器的对象实例化方式,解决多字段对象创建时代码繁琐、参数顺序易混淆、可选参数处理麻烦的问题,是企业级开发中创建复杂对象的标配注解,常与 @Data、@NoArgsConstructor、@AllArgsConstructor 组合使用。
@Data
@Builder
public class User {
private Long userId;
private String username;
private String password;
}
八、注解组合速查表
8.1 控制器常用组合 @RestController
@RequestMapping("/user")
@RequiredArgsConstructor
@Slf4j
public class UserController {
private final UserService userService;
@PostMapping("/login")
public Result<String> login (@RequestParam String username, @RequestParam String password) {
log.info("用户登录:{}" , username);
return userService.login(username, password);
}
}
8.2 实体类常用组合 @Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long userId;
@NotBlank(message = "用户名不能为空")
private String username;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@Version
private Integer version;
@TableLogic
private Integer deleted;
}
8.3 Service 层常用组合 @Service
@RequiredArgsConstructor
@Slf4j
public class UserServiceImpl implements UserService {
private final UserMapper userMapper;
@Transactional
public void saveUser (User user) {
log.info("保存用户:{}" , user.getUsername());
userMapper.insert(user);
}
}
九、常见错误汇总
错误 1:忘记加@Component 系列注解
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
}
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
}
错误 2:@Autowired 注入失败
public interface UserMapper {
User selectById (Long id) ;
}
@Mapper
public interface UserMapper {
User selectById (Long id) ;
}
错误 3:@Transactional 不生效
@Transactional
private void saveUser (User user) {
userMapper.insert(user);
}
@Transactional
public void saveUser (User user) {
userMapper.insert(user);
}
错误 4:@RequestBody 和@RequestParam 混用
@PostMapping("/add")
public Result<Boolean> add (@RequestBody Bill bill, @RequestParam Long userId) {
}
@PostMapping("/add")
public Result<Boolean> add (@RequestBody Map<String,Object> params) {
Long userId = (Long) params.get("userId" );
Bill bill = (Bill) params.get("bill" );
}
十、总结
10.1 必会注解(按使用频率排序) 排名 注解 使用频率 重要程度 1 @RestController⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 2 @RequestMapping⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 3 @Autowired⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 4 @Service⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ 5 @Data⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ 6 @RequestParam⭐⭐⭐⭐ ⭐⭐⭐⭐ 7 @RequestBody⭐⭐⭐⭐ ⭐⭐⭐⭐ 8 @PathVariable⭐⭐⭐ ⭐⭐⭐ 9 @Transactional⭐⭐⭐ ⭐⭐⭐⭐⭐ 10 @Valid⭐⭐⭐ ⭐⭐⭐⭐
10.2 快速查询表 需要返回 JSON? → @RestController
需要获取 URL 参数? → @RequestParam
需要获取 JSON 数据? → @RequestBody
需要获取路径参数? → @PathVariable
需要参数校验? → @Valid + 校验注解
需要依赖注入? → @Autowired 或 @RequiredArgsConstructor
需要事务? → @Transactional
需要日志? → @Slf4j
需要权限验证? → 自定义注解 + @Aspect
微信扫一扫,关注极客日志 微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online