最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Boot常用注解速查表(30個(gè)必會(huì)注解+實(shí)戰(zhàn)案例)

 更新時(shí)間:2026年03月20日 10:57:59   作者:識(shí)君啊  
這篇文章主要介紹了Spring Boot常用注解速查表(30個(gè)必會(huì)注解+實(shí)戰(zhàn)案例),本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧

一、前言

Spring Boot開發(fā)中,注解無處不在。但注解太多,容易忘記怎么用?

本文整理了30個(gè)最常用的注解,分為7大類,每個(gè)注解都配有:

  • 作用說明
  • 真實(shí)代碼示例(來自我的記賬系統(tǒng)項(xiàng)目)
  • 使用場景
  • 常見錯(cuò)誤

二、核心注解(5個(gè))

2.1 @SpringBootApplication

@SpringBootApplication 是 Spring Boot 核心組合注解,整合@Configuration、@EnableAutoConfiguration@ComponentScan三大核心注解的功能,用于標(biāo)注 Spring Boot 項(xiàng)目的主啟動(dòng)類,是開啟 Spring Boot 自動(dòng)配置、組件掃描的核心入口,簡化項(xiàng)目配置,一鍵啟動(dòng) Spring Boot 應(yīng)用。

  1. @Configuration:將類標(biāo)記為配置類,支持注解式配置;
  2. @EnableAutoConfiguration:開啟自動(dòng)配置,自動(dòng)加載適配的框架配置;
  3. @ComponentScan:掃描主類所在包及子包的 @Component 系列注解(@Controller/@Service /@Mapper等),將 Bean 納入容器。

實(shí)戰(zhàn)代碼:

package com.liu;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.liu.mapper")  // 掃描Mapper接口
@SpringBootApplication         // 核心注解
public class SimpleAccountingApplication {
    public static void main(String[] args) {
        SpringApplication.run(SimpleAccountingApplication.class, args);
    }
}

使用場景: 每個(gè)Spring Boot項(xiàng)目有且僅有一個(gè)啟動(dòng)類

常見錯(cuò)誤:

// 錯(cuò)誤:啟動(dòng)類放在子包里,掃描不到其他組件
package com.liu.config;  // 錯(cuò)誤位置
@SpringBootApplication
public class Application { }
// 正確:啟動(dòng)類放在根包
package com.liu;  // 正確位置
@SpringBootApplication
public class Application { }

2.2 @Component

作用: @Component 是 Spring 框架的核心通用組件注解,用于標(biāo)記普通 Java 類為Spring 容器可管理的 Bean,標(biāo)注后類會(huì)被 Spring 掃描并實(shí)例化,納入 IoC 容器統(tǒng)一管理,實(shí)現(xiàn)對象的依賴注入與生命周期管控,解耦組件間依賴。

它是 @ComponentScan 掃描的基礎(chǔ)注解,@Controller、@Service、@Repository 等注解均基于它擴(kuò)展,分別適配控制層、業(yè)務(wù)層、數(shù)據(jù)層等場景,@Component 則適用于無明確分層的通用組件,是 Spring 組件化開發(fā)的基礎(chǔ)。

實(shí)戰(zhàn)代碼:

@Component
public class JwtUtil {
    @Value("${jwt.secret}")
    private String secret;
    public String generateToken(Long userId, Integer role, String username) {
        // 生成JWT Token
    }
}

使用場景: 工具類、攔截器、切面等

衍生注解:

  • @Controller:控制器
  • @Service:服務(wù)層
  • @Repository:數(shù)據(jù)訪問層
  • @Configuration:配置類

2.3 @Autowired

作用: @Autowired 是 Spring 核心的自動(dòng)依賴注入注解,用于實(shí)現(xiàn) Spring IoC 容器中 Bean 的自動(dòng)裝配,簡化組件間依賴管理,無需手動(dòng)創(chuàng)建對象實(shí)例,直接注入所需依賴 Bean,大幅降低代碼耦合度。

其默認(rèn)按類型(byType) 匹配容器中的 Bean 完成注入,支持標(biāo)注在類的構(gòu)造方法、字段、setter 方法上;若同類型 Bean 存在多個(gè),可結(jié)合 @Qualifier 按名稱精準(zhǔn)匹配,或用 @Primary 指定默認(rèn)注入 Bean。

實(shí)戰(zhàn)代碼:

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;  // 自動(dòng)注入Mapper
    @Autowired
    private JwtUtil jwtUtil;  // 自動(dòng)注入工具類
    public User login(String username, String password) {
        return userMapper.selectByUsername(username);
    }
}

使用場景: 注入Service、Mapper、工具類等

推薦寫法(構(gòu)造器注入):

@Service
@RequiredArgsConstructor  // Lombok注解,自動(dòng)生成構(gòu)造器
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;  // final修飾
    private final JwtUtil jwtUtil;
    // Lombok自動(dòng)生成構(gòu)造器,Spring自動(dòng)注入
}

為什么推薦構(gòu)造器注入?

  • 不可變(final修飾)
  • 避免循環(huán)依賴
  • 便于單元測試

2.4 @Value

作用: 注入配置文件中的值。@Value 是 Spring 框架的屬性注入注解,核心用于將配置文件值、系統(tǒng)屬性、常量值注入到 Spring 容器管理的 Bean 的字段 / 方法參數(shù)中,實(shí)現(xiàn)配置與代碼解耦,無需硬編碼配置信息,簡化配置讀取與使用。

支持直接注入常量(如@Value("hello")),更常用的是通過${key}讀取 application.properties/yaml 中的配置項(xiàng)(如@Value("${server.port}")),可標(biāo)注在 Bean 的字段、構(gòu)造方法參數(shù)、setter 方法上,適配 Spring 管理的所有組件(@Component/@Service/@Controller 等)。

實(shí)戰(zhàn)代碼:

@Component
public class JwtUtil {
    @Value("${jwt.secret}")
    private String secret;  // 注入配置:jwt.secret
    @Value("${jwt.expiration}")
    private Long expiration;  // 注入配置:jwt.expiration
}

配置文件(application.yml):

jwt:
  secret: my-secret-key-12345
  expiration: 7200000  # 2小時(shí)

使用場景: 注入配置參數(shù)(密鑰、超時(shí)時(shí)間、文件路徑等)

常見錯(cuò)誤:

// 錯(cuò)誤:配置文件中沒有這個(gè)key
@Value("${jwt.secretKey}")  // 配置文件是jwt.secret,不是jwt.secretKey
private String secret;
// 正確:設(shè)置默認(rèn)值
@Value("${jwt.secret:default-secret}")  // 如果沒有配置,使用default-secret
private String secret;

2.5 @Configuration

作用: @Configuration 是 Spring 框架的核心配置類注解,用于標(biāo)記 Java 類為Spring 配置類,替代傳統(tǒng) XML 配置文件,實(shí)現(xiàn)純注解式配置開發(fā)。

標(biāo)注該注解的類會(huì)被 Spring 解析,類中通過@Bean注解修飾的方法,其返回對象會(huì)被注冊為 Spring IoC 容器中的 Bean,由容器統(tǒng)一管理實(shí)例化、依賴注入與生命周期,是 Spring 注解驅(qū)動(dòng)開發(fā)的核心基礎(chǔ)。

實(shí)戰(zhàn)代碼:

@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");
    }
}

使用場景: 配置攔截器、跨域、數(shù)據(jù)源、線程池等

三、Web層注解(8個(gè))

3.1 @RestController

作用: @RestController 是 Spring MVC 的組合注解,整合@Controller@ResponseBody核心功能,專門用于標(biāo)注RESTful 風(fēng)格的控制器類,是 Spring Boot 開發(fā)接口的核心注解,無需額外配置即可實(shí)現(xiàn) JSON/XML 等數(shù)據(jù)的返回。

  1. 繼承@Controller:將類標(biāo)記為 Spring MVC 控制器,接收前端請求;
  2. 整合@ResponseBody:默認(rèn)對類中所有 @RequestMapping 系列注解的方法生效,自動(dòng)將方法返回值序列化為 JSON/XML 格式,直接寫入響應(yīng)體,替代傳統(tǒng)視圖跳轉(zhuǎn),適配前后端分離場景。

對比單獨(dú)使用@Controller+ 方法級(jí)@ResponseBody,該注解簡化了 REST 接口的開發(fā),無需在每個(gè)接口方法上重復(fù)標(biāo)注@ResponseBody。

等價(jià)于: @Controller + @ResponseBody

實(shí)戰(zhàn)代碼:

@RestController
@RequestMapping("/user")
public class UserController {
    @PostMapping("/login")
    public Result<String> login(@RequestParam String username, 
                                @RequestParam String password) {
        // 返回JSON:{"code":200,"msg":"登錄成功","data":"token"}
        return Result.success("登錄成功", token);
    }
}

使用場景: 前后端分離項(xiàng)目,返回JSON數(shù)據(jù)

對比:

注解返回類型使用場景
@Controller視圖(HTML)傳統(tǒng)MVC項(xiàng)目
@RestControllerJSON數(shù)據(jù)前后端分離項(xiàng)目

3.2 @RequestMapping

作用: @RequestMapping 是 Spring MVC核心請求映射注解,用于將前端 HTTP 請求后端控制器方法建立綁定關(guān)系,使 Spring 能精準(zhǔn)匹配請求并調(diào)用對應(yīng)方法處理,是開發(fā) Web 接口 / 頁面請求的基礎(chǔ)注解,可標(biāo)注在控制器類方法上。

實(shí)戰(zhàn)代碼:

@RestController
@RequestMapping("/user")  // 類級(jí)別:所有方法的URL前綴
public class UserController {
    // 方法級(jí)別:完整URL = /user/login
    @RequestMapping(value = "/login", method = {RequestMethod.GET, RequestMethod.POST})
    public Result<String> login() {
        // 支持GET和POST請求
    }
}

簡化衍生注解(Spring MVC 推薦)

為簡化method屬性配置,Spring 提供了 @RequestMapping 的專用衍生注解,語義更清晰,開發(fā)中優(yōu)先使用:

  • @GetMapping:等價(jià)于@RequestMapping(method = RequestMethod.GET),處理 GET 查詢請求;
  • @PostMapping:等價(jià)于@RequestMapping(method = RequestMethod.POST),處理 POST 新增 / 提交請求;
  • @PutMapping:等價(jià)于 @RequestMapping(method = RequestMethod.PUT),處理 PUT 更新請求;
  • @DeleteMapping:等價(jià)于 @RequestMapping(method = RequestMethod.DELETE),處理 DELETE 刪除請求。
@GetMapping("/list")     // 等價(jià)于 @RequestMapping(method = RequestMethod.GET)
@PostMapping("/add")     // 等價(jià)于 @RequestMapping(method = RequestMethod.POST)
@PutMapping("/update")   // 等價(jià)于 @RequestMapping(method = RequestMethod.PUT)
@DeleteMapping("/delete")// 等價(jià)于 @RequestMapping(method = RequestMethod.DELETE)

3.3 @RequestParam

作用: 獲取URL參數(shù)(?key=value)

實(shí)戰(zhàn)代碼:

@PostMapping("/login")
public Result<String> login(@RequestParam String username, 
                            @RequestParam String password) {
    // 請求:POST /user/login?username=admin&password=123456
    // username = "admin"
    // password = "123456"
}

可選參數(shù):

@GetMapping("/list")
public Result<List<Bill>> list(
    @RequestParam(required = false) String keyword,  // 可選參數(shù)
    @RequestParam(defaultValue = "1") Integer page   // 默認(rèn)值
) {
    // 請求:GET /bill/list
    // keyword = null
    // page = 1
}

3.4 @RequestBody

作用:

@RequestBody 是 Spring MVC 的核心請求體解析注解,專門用于接收前端通過 HTTP 請求體傳遞的非表單格式數(shù)據(jù)(如 JSON、XML),并自動(dòng)將請求體中的數(shù)據(jù)反序列化為指定的 Java 實(shí)體類 / Map / 字符串對象,綁定到控制器方法的參數(shù)上,是前后端分離場景中接收 JSON 請求的必備注解。

實(shí)戰(zhàn)代碼:

@PostMapping("/register")
public Result<User> register(@RequestBody User user) {
    // 請求體:{"username":"admin","password":"123456"}
    // 自動(dòng)轉(zhuǎn)換為User對象
    // user.getUsername() = "admin"
    // user.getPassword() = "123456"
}

使用場景: POST/PUT請求,提交JSON數(shù)據(jù)

常見錯(cuò)誤:

// 錯(cuò)誤:GET請求不能用@RequestBody
@GetMapping("/list")
public Result<List<Bill>> list(@RequestBody Map<String, Object> params) {
    // GET請求沒有請求體,會(huì)報(bào)錯(cuò)
}
// 正確:GET請求用@RequestParam
@GetMapping("/list")
public Result<List<Bill>> list(@RequestParam String keyword) {
    // 正確
}

3.5 @PathVariable

作用:

@PathVariable 是 Spring MVC 的路徑參數(shù)綁定注解,核心用于提取 URL 路徑中的動(dòng)態(tài)占位符參數(shù),并自動(dòng)將其轉(zhuǎn)換為指定類型后綁定到控制器方法的入?yún)⑸希情_發(fā)RESTful 風(fēng)格動(dòng)態(tài)接口的核心注解(如/user/123、/order/456/detail這類含動(dòng)態(tài) ID 的請求)。

實(shí)戰(zhàn)代碼:

@DeleteMapping("/delete/{id}")
public Result<Boolean> delete(@PathVariable Long id) {
    // 請求:DELETE /bill/delete/123
    // id = 123
    billService.deleteById(id);
    return Result.success("刪除成功");
}
@GetMapping("/user/{userId}/bill/{billId}")
public Result<Bill> getBill(@PathVariable Long userId, 
                            @PathVariable Long billId) {
    // 請求:GET /user/10/bill/20
    // userId = 10
    // billId = 20
}

使用場景: RESTful風(fēng)格的URL

3.6 @ResponseBody

作用: @ResponseBody 是 Spring MVC 的核心響應(yīng)體處理注解,核心作用是將控制器方法的返回值,直接序列化為 JSON/XML 等格式的數(shù)據(jù)流,寫入 HTTP 響應(yīng)體(Response Body),替代傳統(tǒng)的視圖跳轉(zhuǎn)(如跳轉(zhuǎn)到 JSP/HTML 頁面),是實(shí)現(xiàn)前后端分離接口RESTful 風(fēng)格接口的關(guān)鍵注解。

核心使用特性

  1. 生效范圍:可標(biāo)注在控制器方法上(僅對當(dāng)前方法生效),也可標(biāo)注在控制器類上(對類中所有 @RequestMapping 系列注解的方法生效);
  2. 自動(dòng)序列化:Spring 默認(rèn)通過 Jackson 框架完成轉(zhuǎn)換,將 Java 對象(實(shí)體類、Map、集合等)自動(dòng)序列化為 JSON 字符串,無需手動(dòng)處理;
  3. 返回值適配:支持所有 Java 基礎(chǔ)類型、自定義實(shí)體類、Map、List 等,均能被自動(dòng)序列化;
  4. 與 @RestController 的關(guān)系@RestController@Controller + @ResponseBody的組合注解,標(biāo)注 @RestController 的類,底層已默認(rèn)添加類級(jí)別的 @ResponseBody,無需重復(fù)標(biāo)注。

實(shí)戰(zhàn)代碼:

@Controller  // 注意:不是@RestController
@RequestMapping("/user")
public class UserController {
    @GetMapping("/toLogin")
    public String toLogin() {
        return "redirect:/login.html";  // 返回視圖
    }
    @ResponseBody  // 單獨(dú)使用,返回JSON
    @PostMapping("/login")
    public Result<String> login() {
        return Result.success("登錄成功");  // 返回JSON
    }
}

使用場景: 混合使用視圖和JSON返回時(shí)

3.7 @Valid / @Validated

作用: @Valid 和 @Validated 均是 Spring 中用于開啟參數(shù)校驗(yàn)的核心注解,基于 JSR-380(Bean Validation 2.0)規(guī)范實(shí)現(xiàn),配合 @NotNull/@NotBlank/@Min 等校驗(yàn)注解,可自動(dòng)完成對實(shí)體類參數(shù)的合法性校驗(yàn),替代手動(dòng) if 判斷,簡化參數(shù)校驗(yàn)邏輯,是開發(fā)接口時(shí)的必備注解。

二者核心作用一致,但所屬規(guī)范、功能特性、適用場景存在明確區(qū)別,其中 @Validated 是 Spring 對 @Valid增強(qiáng)擴(kuò)展版,開發(fā)中可根據(jù)需求選擇。

實(shí)戰(zhàn)代碼:

// 實(shí)體類(User.java)
@Data
public class User {
    @NotBlank(message = "用戶名不能為空")
    @Size(min = 3, max = 20, message = "用戶名長度必須在3-20個(gè)字符之間")
    private String username;
    @NotBlank(message = "密碼不能為空")
    @Size(min = 6, max = 10, message = "密碼長度必須在6-10個(gè)字符之間")
    @Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[a-zA-Z\\d]{6,10}$", 
             message = "密碼必須包含大小寫字母和數(shù)字")
    private String password;
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手機(jī)號(hào)格式不正確")
    private String phone;
}
// 控制器
@PostMapping("/register")
public Result<User> register(@RequestBody @Valid User user) {
    // 如果校驗(yàn)失敗,自動(dòng)返回400錯(cuò)誤,不會(huì)執(zhí)行方法體
    // 如果校驗(yàn)成功,繼續(xù)執(zhí)行
    return userService.register(user);
}

常用校驗(yàn)注解:

在博主以前的文章里面有詳細(xì)的JSR303校驗(yàn)講解: JSR303 Bean Validation 詳解(權(quán)威版).md

注解作用示例
@NotNull不能為null@NotNull(message = "ID不能為空")
@NotBlank不能為空字符串@NotBlank(message = "用戶名不能為空")
@Size長度限制@Size(min = 3, max = 20)
@Pattern正則驗(yàn)證@Pattern(regexp = "^1[3-9]\\d{9}$")
@Min / @Max數(shù)值范圍@Min(value = 0, message = "金額不能為負(fù)")
@Email郵箱格式@Email(message = "郵箱格式不正確")

3.8 @ExceptionHandler

作用: @ExceptionHandler 是 Spring MVC 提供的異常處理核心注解,核心作用是捕獲并處理 Spring 容器中指定類型的異常,可標(biāo)注在控制器(@Controller/@RestController)或全局異常處理器的方法上,實(shí)現(xiàn)異常的局部 / 全局統(tǒng)一處理,替代傳統(tǒng)的 try-catch 代碼塊,簡化異常處理邏輯,讓接口返回統(tǒng)一、友好的錯(cuò)誤響應(yīng)。

核心核心特性

  1. 精準(zhǔn)捕獲異常:通過注解參數(shù)指定要處理的單個(gè) / 多個(gè)異常類型(如 @ExceptionHandler(NullPointerException.class)),僅捕獲匹配的異常;
  2. 局部 / 全局生效:
    • 標(biāo)注在普通控制器類中:僅處理當(dāng)前控制器中方法拋出的異常(局部生效);
    • 標(biāo)注在標(biāo)注了 @RestControllerAdvice/@ControllerAdvice 的全局異常類中:處理整個(gè)項(xiàng)目所有控制器拋出的異常(全局生效,開發(fā)中最常用);
  3. 靈活返回結(jié)果:方法返回值支持與普通控制器方法一致的類型(如 JSON 對象、視圖名稱),適配前后端分離(返回 JSON)和傳統(tǒng)視圖開發(fā)場景;
  4. 自動(dòng)注入異常對象:方法入?yún)⒖芍苯咏邮?strong>捕獲到的異常實(shí)例,便于獲取異常信息(如錯(cuò)誤消息、堆棧軌跡)。

實(shí)戰(zhàn)代碼:

@RestControllerAdvice  // 全局異常處理
public class GlobalExceptionHandler {
    // 處理參數(shù)校驗(yàn)異常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<String> handleValidException(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        return Result.fail(message);  // 返回:{"code":400,"msg":"用戶名不能為空"}
    }
    // 處理業(yè)務(wù)異常
    @ExceptionHandler(RuntimeException.class)
    public Result<String> handleRuntimeException(RuntimeException e) {
        return Result.fail(e.getMessage());
    }
    // 處理數(shù)據(jù)庫唯一約束異常
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public Result<String> handleSQLException(SQLIntegrityConstraintViolationException e) {
        if (e.getMessage().contains("Duplicate entry")) {
            return Result.fail("數(shù)據(jù)已存在");
        }
        return Result.fail("數(shù)據(jù)庫操作失敗");
    }
}

使用場景: 統(tǒng)一處理異常,避免在每個(gè)方法中try-catch

類上標(biāo)注的是全局異常處理注解@RestControllerAdvice 是 Spring MVC 提供的全局異常處理 + 數(shù)據(jù)綁定 + 返回值增強(qiáng)的核心組合注解,是 @ControllerAdvice + @ResponseBody 的整合版,專門適配前后端分離項(xiàng)目,核心作用是實(shí)現(xiàn)全局統(tǒng)一的異常處理、全局?jǐn)?shù)據(jù)綁定、全局返回值封裝,無需在每個(gè)控制器重復(fù)編寫邏輯,讓接口返回格式統(tǒng)一、異常處理更簡潔。

四、Service層注解(2個(gè))

4.1 @Service

作用: @Service 是 Spring 框架中業(yè)務(wù)層組件專用注解,屬于 @Component分層擴(kuò)展注解,核心作用是標(biāo)記普通 Java 類為Spring IoC 容器可管理的業(yè)務(wù)層 Bean,讓類被 @ComponentScan 自動(dòng)掃描并納入容器統(tǒng)一管理,是 Spring 分層開發(fā)(控制層 / 業(yè)務(wù)層 / 數(shù)據(jù)層)的核心標(biāo)識(shí)之一。

核心核心特性:

  1. 專屬業(yè)務(wù)層標(biāo)識(shí):語義上明確標(biāo)注類的作用是業(yè)務(wù)邏輯處理(如業(yè)務(wù)規(guī)則判斷、數(shù)據(jù)層調(diào)用、事務(wù)處理等),替代通用的 @Component,讓代碼分層更清晰、可讀性更強(qiáng);
  2. 自動(dòng)掃描注冊 Bean:與 @Component 一致,Spring 啟動(dòng)時(shí)通過組件掃描,自動(dòng)將標(biāo)注該注解的類實(shí)例化并注冊到 IoC 容器,無需手動(dòng)配置 Bean;
  3. 支持依賴注入:容器中的 @Service 組件,可通過 @Autowired/@Resource 等注解,自動(dòng)注入依賴的其他 Bean(如 @Repository 數(shù)據(jù)層組件);
  4. 天然支持事務(wù)管理:配合 Spring 聲明式事務(wù) @Transactional 注解,可直接在 @Service 方法上標(biāo)注,實(shí)現(xiàn)業(yè)務(wù)層的事務(wù)控制(核心適用場景)。

實(shí)戰(zhàn)代碼:

@Service
@RequiredArgsConstructor//Lombok注解,自動(dòng)生成構(gòu)造器,構(gòu)造器注入,避免字段注入
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;
    @Override
    public User login(String username, String password) {
        // 業(yè)務(wù)邏輯
        User user = userMapper.selectByUsername(username);
        if (user == null) {
            throw new RuntimeException("用戶不存在");
        }
        if (!user.getPassword().equals(password)) {
            throw new RuntimeException("密碼錯(cuò)誤");
        }
        return user;
    }
}

使用場景: 業(yè)務(wù)邏輯層

4.2 @Transactional

作用: @Transactional 是 Spring 框架實(shí)現(xiàn)聲明式事務(wù)管理的核心注解,基于 AOP(面向切面編程)實(shí)現(xiàn),無需手動(dòng)編寫 try-catch 事務(wù)提交 / 回滾代碼,僅通過注解標(biāo)注即可為方法 / 類開啟事務(wù)控制,保證一組數(shù)據(jù)庫操作的原子性(要么全部成功提交,要么任意一步失敗則整體回滾),是解決數(shù)據(jù)庫事務(wù)問題的標(biāo)準(zhǔn)方案。

核心注解屬性(常用配置)

@Transactional 提供多個(gè)屬性用于自定義事務(wù)行為,開發(fā)中可根據(jù)業(yè)務(wù)需求配置,核心常用屬性如下:

屬性名作用可選值示例、默認(rèn)值
readOnly設(shè)置事務(wù)是否為只讀(適用于僅查詢操作,提升數(shù)據(jù)庫性能)true/false(默認(rèn))
isolation設(shè)置事務(wù)隔離級(jí)別(解決并發(fā)事務(wù)的臟讀 / 不可重復(fù)讀 / 幻讀問題)READ_UNCOMMITTED/READ_COMMITTED/REPEATABLE_READ/SERIALIZABLE 數(shù)據(jù)庫默認(rèn)隔離級(jí)別(如 MySQL 為 REPEATABLE_READ)
propagation設(shè)置事務(wù)傳播行為(解決方法嵌套調(diào)用時(shí),事務(wù)的創(chuàng)建 / 復(fù)用規(guī)則)REQUIRED(最常用)/REQUIRES_NEW/SUPPORTS
rollbackFor指定觸發(fā)回滾的異常類型(可包含 checked 異常)Exception.class/BusinessException.class 默認(rèn):RuntimeException.class
noRollbackFor指定不觸發(fā)回滾的異常類型IllegalArgumentException.class 默認(rèn):無
timeout設(shè)置事務(wù)超時(shí)時(shí)間(單位:秒),超時(shí)則自動(dòng)回滾3/5 默認(rèn):-1(無超時(shí)限制)

實(shí)戰(zhàn)代碼:

@Service
public class AnnouncementServiceImpl implements AnnouncementService {
    @Transactional  // 開啟事務(wù)
    public void publishAnnouncement(Announcement announcement) {
        // 1. 保存公告
        announcementMapper.insert(announcement);
        // 2. 記錄操作日志
        logMapper.insert(new Log("發(fā)布公告", announcement.getId()));
        // 如果第2步失敗,第1步會(huì)自動(dòng)回滾
    }
}

使用場景: 多個(gè)數(shù)據(jù)庫操作需要保證原子性

常見錯(cuò)誤:

// 錯(cuò)誤:@Transactional只對public方法有效
@Transactional
private void saveUser(User user) {
    // 事務(wù)不生效
}

// 正確:必須是public方法
@Transactional
public void saveUser(User user) {
    // 事務(wù)生效
}

五、MyBatis-Plus注解(7個(gè))

5.1 @TableName

作用:@TableNameMyBatis-Plus(MP)框架的核心表映射注解,專門用于解決Java 實(shí)體類數(shù)據(jù)庫表之間的名稱映射問題,通過注解直接指定實(shí)體類對應(yīng)的數(shù)據(jù)庫表名,替代傳統(tǒng) MyBatis 中手動(dòng)編寫 SQL 映射或 XML 配置表名的操作,簡化 MP 的單表 CRUD 開發(fā),是 MP 實(shí)現(xiàn)零 SQL 單表操作的基礎(chǔ)注解之一。

核心設(shè)計(jì)背景

MyBatis-Plus 有默認(rèn)表名映射規(guī)則實(shí)體類名(駝峰命名)自動(dòng)轉(zhuǎn)換為數(shù)據(jù)庫表名(下劃線命名)(如 Java 實(shí)體UserInfo → 數(shù)據(jù)庫表user_info)。

當(dāng)實(shí)體類名與數(shù)據(jù)庫表名不一致 / 不滿足駝峰轉(zhuǎn)下劃線規(guī)則時(shí)(如實(shí)體User對應(yīng)表t_user、實(shí)體Order對應(yīng)表order_info),默認(rèn)規(guī)則失效,需通過@TableName手動(dòng)指定映射關(guān)系,否則 MP 執(zhí)行 CRUD 時(shí)會(huì)因表名不存在拋出 SQL 異常。

實(shí)戰(zhàn)代碼:

@Data
@TableName("user")  // 對應(yīng)數(shù)據(jù)庫的user表
public class User {
    private Long userId;
    private String username;
}

使用場景: 實(shí)體類名和表名不一致時(shí)

5.2 @TableId

作用: @TableIdMyBatis-Plus(MP)框架的專屬主鍵映射注解,核心作用是將Java 實(shí)體類的屬性數(shù)據(jù)庫表的主鍵字段建立綁定關(guān)系,同時(shí)指定主鍵的生成策略(如自增、雪花算法、UUID 等),是 MP 實(shí)現(xiàn)單表 CRUD 時(shí)主鍵自動(dòng)處理的核心注解,替代傳統(tǒng) MyBatis 手動(dòng)配置主鍵映射和生成邏輯的操作。

核心設(shè)計(jì)背景

MyBatis-Plus 默認(rèn)會(huì)將實(shí)體類中名為id的屬性映射為數(shù)據(jù)庫表的主鍵字段,且默認(rèn)使用雪花算法(IdType.ASSIGN_ID) 生成主鍵值。

當(dāng)實(shí)體主鍵屬性名與表主鍵字段名不一致(如實(shí)體userId對應(yīng)表user_id)、需要自定義主鍵生成策略(如數(shù)據(jù)庫自增、UUID)時(shí),默認(rèn)規(guī)則失效,需通過@TableId顯式配置,否則 MP 執(zhí)行新增 / 查詢等操作時(shí)會(huì)因主鍵映射錯(cuò)誤 / 生成規(guī)則不符拋出異常。

實(shí)戰(zhàn)代碼:

@Data
@TableName("user")
public class User {
    @TableId(type = IdType.AUTO)  // 主鍵自增
    private Long userId;
}

主鍵策略:

策略說明
IdType.AUTO數(shù)據(jù)庫自增
IdType.ASSIGN_ID雪花算法生成ID(默認(rèn))
IdType.INPUT手動(dòng)輸入

5.3 @TableField

作用: @TableField 是 MyBatis-Plus(MP)框架的普通字段專屬映射注解,核心作用是將Java 實(shí)體類的非主鍵屬性數(shù)據(jù)庫表的普通字段建立綁定關(guān)系,同時(shí)支持配置字段是否參與 CRUD、是否為查詢條件、字段填充規(guī)則等特性,是 MP 解決非主鍵字段映射不一致、實(shí)現(xiàn)字段精細(xì)化控制的核心注解,替代傳統(tǒng) MyBatis 手動(dòng)在 XML/SQL 中配置字段映射的操作。

核心設(shè)計(jì)背景

MyBatis-Plus 有默認(rèn)普通字段映射規(guī)則實(shí)體類屬性名(駝峰命名)自動(dòng)轉(zhuǎn)換為數(shù)據(jù)庫表字段名(下劃線命名)(如實(shí)體userName → 表user_name)。

當(dāng)實(shí)體屬性名與表字段名不一致 / 不滿足駝峰轉(zhuǎn)下劃線規(guī)則、需要排除某些字段不參與 MP 的自動(dòng) CRUD需要配置字段自動(dòng)填充(如創(chuàng)建時(shí)間、更新時(shí)間)時(shí),默認(rèn)規(guī)則無法滿足需求,需通過@TableField顯式配置,否則 MP 執(zhí)行操作時(shí)會(huì)因字段映射錯(cuò)誤拋出 SQL 異常,或無法實(shí)現(xiàn)字段的精細(xì)化控制。

實(shí)戰(zhàn)代碼:

@Data
@TableName("user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long userId;
    // 自動(dòng)填充:插入時(shí)填充
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    // 自動(dòng)填充:插入和更新時(shí)都填充
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
}

自動(dòng)填充處理器:

@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)框架實(shí)現(xiàn)樂觀鎖機(jī)制的專屬核心注解,核心作用是將Java 實(shí)體類的屬性數(shù)據(jù)庫表的版本數(shù)字段綁定,讓 MP 自動(dòng)基于該字段實(shí)現(xiàn)樂觀鎖的版本控制,解決多線程 / 多用戶并發(fā)更新數(shù)據(jù)時(shí)的臟寫問題(避免多個(gè)請求同時(shí)修改同一條數(shù)據(jù),導(dǎo)致數(shù)據(jù)覆蓋、一致性丟失),是 MP 簡化樂觀鎖開發(fā)的關(guān)鍵注解。

實(shí)戰(zhàn)代碼:

@Data
@TableName("user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long userId;
    @Version  // 樂觀鎖
    private Integer version;
}

工作原理:

-- 更新時(shí)自動(dòng)加上version條件
UPDATE user SET username = ?, version = version + 1 
WHERE user_id = ? AND version = ?
-- 如果version不匹配(被其他線程修改了),更新失敗

使用場景: 防止并發(fā)修改沖突

5.5 @TableLogic

作用: @TableLogic 是 MyBatis-Plus(MP)框架實(shí)現(xiàn)邏輯刪除的專屬核心注解,核心作用是將 Java 實(shí)體類的屬性與數(shù)據(jù)庫表的邏輯刪除標(biāo)識(shí)字段綁定,讓 MP 自動(dòng)將單表 CRUD 中的物理刪除(DELETE)操作替換為邏輯刪除(UPDATE)操作,同時(shí)自動(dòng)過濾查詢 / 更新結(jié)果中已邏輯刪除的數(shù)據(jù),實(shí)現(xiàn)數(shù)據(jù)的「假刪除、軟刪除」,避免真實(shí)刪除數(shù)據(jù)導(dǎo)致的歷史數(shù)據(jù)丟失、關(guān)聯(lián)查詢異常問題,是 MP 簡化邏輯刪除開發(fā)的關(guān)鍵注解。

實(shí)戰(zhàn)代碼:

@Data
@TableName("user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long userId;
    @TableLogic  // 邏輯刪除:0=正常,1=已刪除
    private Integer deleted;
}

效果:

// 調(diào)用刪除方法
userMapper.deleteById(1);
// 實(shí)際執(zhí)行的SQL(不是真刪除)
UPDATE user SET deleted = 1 WHERE user_id = 1 AND deleted = 0
// 查詢時(shí)自動(dòng)過濾已刪除的數(shù)據(jù)
SELECT * FROM user WHERE deleted = 0

5.6 @MapperScan

作用: @MapperScan 是 MyBatis 及 MyBatis-Plus 框架的核心 Mapper 接口掃描注解,核心作用是指定項(xiàng)目中 Mapper 接口的掃描包路徑,讓框架自動(dòng)掃描該包下所有的 Mapper 接口,并為每個(gè)接口動(dòng)態(tài)生成代理實(shí)現(xiàn)類,最終將這些代理類注冊到 Spring IoC 容器中,實(shí)現(xiàn) Mapper 接口的依賴注入和數(shù)據(jù)庫操作調(diào)用,是整合 MyBatis/MP 與 SpringBoot 的關(guān)鍵注解。

實(shí)戰(zhàn)代碼:

@MapperScan("com.liu.mapper")  // 掃描mapper包下的所有接口
@SpringBootApplication
public class SimpleAccountingApplication {
    public static void main(String[] args) {
        SpringApplication.run(SimpleAccountingApplication.class, args);
    }
}

使用場景: 啟動(dòng)類上,掃描所有Mapper接口

5.7 @Select / @Insert / @Update / @Delete

作用: @Select、@Insert、@Update@DeleteMyBatis/MyBatis-Plus(MP)框架的核心原生 SQL 注解,屬于 MyBatis 基礎(chǔ)注解(MP 完全兼容),核心作用是直接在 Mapper 接口的方法上標(biāo)注對應(yīng)的 SQL 語句,讓框架將接口方法與 SQL 語句直接綁定,調(diào)用接口方法時(shí)自動(dòng)執(zhí)行標(biāo)注的 SQL,實(shí)現(xiàn)數(shù)據(jù)庫的查詢、新增、更新、刪除操作。

這組注解替代了傳統(tǒng) MyBatis 中XML 映射文件的編寫(如UserMapper.xml中的<select>/<insert>標(biāo)簽),實(shí)現(xiàn)「SQL 與 Mapper 接口方法一體化」,簡化單表 / 多表的 SQL 開發(fā),是 MyBatis/MP 中除了 MP 自動(dòng) CRUD 外,自定義 SQL 的核心實(shí)現(xiàn)方式。

實(shí)戰(zhàn)代碼:

@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);
}

1. 參數(shù)綁定規(guī)范

  • 優(yōu)先使用#{參數(shù)名}:實(shí)現(xiàn)預(yù)編譯參數(shù)綁定,MyBatis 會(huì)自動(dòng)處理參數(shù)類型轉(zhuǎn)換,有效防止 SQL 注入,是開發(fā)中的標(biāo)準(zhǔn)用法;
  • 慎用${參數(shù)名}:直接將參數(shù)拼接到 SQL 中,無預(yù)編譯處理,有 SQL 注入風(fēng)險(xiǎn),僅適用于表名、字段名動(dòng)態(tài)拼接(如SELECT * FROM ${tableName});
  • 多參數(shù)綁定:若方法有多個(gè)獨(dú)立入?yún)?,可通過**@Param(“參數(shù)名”)**指定參數(shù)名,保證#{}中名稱匹配:
// 多參數(shù)需標(biāo)注@Param
@Select("SELECT * FROM t_user WHERE username = #{name} AND age = #{age}")
User selectByUsernameAndAge(@Param("name") String username, @Param("age") Integer age);

使用場景: 簡單SQL可以用注解,復(fù)雜SQL建議用XML

六、AOP注解(3個(gè))

6.1 @Aspect

作用:@AspectSpring 框架實(shí)現(xiàn) AOP(面向切面編程)的核心注解,核心作用是標(biāo)記一個(gè)普通 Java 類為「切面類(Aspect)」,讓 Spring 識(shí)別該類為 AOP 的核心載體 —— 用于封裝切入點(diǎn)(Pointcut)通知(Advice) 邏輯,實(shí)現(xiàn)業(yè)務(wù)代碼與非業(yè)務(wù)橫切邏輯(如日志記錄、事務(wù)控制、權(quán)限校驗(yàn)、性能監(jiān)控)的解耦,是 Spring AOP 開發(fā)的基礎(chǔ)注解。

實(shí)戰(zhàn)代碼:

@Aspect
@Component
@Slf4j
public class RoleCheckAspect {
    @Before("@annotation(requireRole)")//在切點(diǎn)之前運(yùn)行的代碼
    public void checkRole(JoinPoint joinPoint, RequireRole requireRole) {
        // 權(quán)限驗(yàn)證邏輯
        int[] allowedRoles = requireRole.value();
        int userRole = TokenHelper.getRole(request);
        boolean hasPermission = Arrays.stream(allowedRoles)
                .anyMatch(role -> role == userRole);
        if (!hasPermission) {
            throw new RuntimeException("無權(quán)限訪問");
        }
    }
}

@Aspect 關(guān)鍵使用注意事項(xiàng)(避坑重點(diǎn))

  1. 切面類必須標(biāo)注 @Component

@Aspect僅標(biāo)記該類為切面,不會(huì)自動(dòng)將其注冊到 Spring IoC 容器,必須配合@Component(或 @Service/@Repository),讓 Spring 掃描并管理該 Bean,否則 AOP 邏輯完全失效。

  1. @Around 通知的核心要求

@Around是唯一能控制目標(biāo)方法執(zhí)行的通知,必須遵守 3 個(gè)規(guī)則,否則會(huì)導(dǎo)致業(yè)務(wù)異常:

  • 必須調(diào)用joinPoint.proceed():執(zhí)行目標(biāo)業(yè)務(wù)方法,省略則目標(biāo)方法不會(huì)執(zhí)行;
  • 必須返回proceed()的結(jié)果:否則目標(biāo)方法的返回值會(huì)丟失(前端獲取不到數(shù)據(jù));
  • 異常必須重新拋出:若捕獲異常,需手動(dòng)拋出,否則后續(xù)異常處理器(如 @RestControllerAdvice)無法感知。
  1. 切入點(diǎn)表達(dá)式需精準(zhǔn)
  • 避免寫過于寬泛的表達(dá)式(如execution(* *..*.*(..))),會(huì)匹配所有方法,導(dǎo)致性能損耗;
  • 表達(dá)式中的包名、類名需與實(shí)際一致,否則無法匹配目標(biāo)方法,切面邏輯不生效。
  1. Spring AOP 的代理限制

Spring AOP 默認(rèn)基于動(dòng)態(tài)代理實(shí)現(xiàn),存在 2 個(gè)核心限制,會(huì)導(dǎo)致切面邏輯不生效:

? 4.1 僅對 Spring 容器中的 Bean 生效

非 Spring 管理的類(未標(biāo)注 @Component/@Service 等),其方法無法被切面增強(qiáng),解決方案:將類注冊為 Spring Bean。

? 4.2 僅對公共(public)方法生效

private/protected/default 訪問權(quán)限的方法,Spring AOP 不會(huì)生成代理,切面邏輯無法織入,解決方案:將方法改為 public(若需增強(qiáng)非公共方法,需使用 AspectJ 原生織入,而非 Spring AOP)。

  1. 內(nèi)部方法自調(diào)用會(huì)導(dǎo)致切面失效

同一類中,無切面增強(qiáng)的方法調(diào)用有切面增強(qiáng)的方法,因未經(jīng)過 Spring 代理對象,切面邏輯無法織入,這是 Spring AOP 最常見的坑:

@Service
public class UserService {
    // 無切面增強(qiáng)的方法
    public void test() {
        this.saveUser(); // 內(nèi)部自調(diào)用,saveUser的切面邏輯失效
    }
    // 有切面增強(qiáng)的方法(如@Transactional/@Around)
    public void saveUser() {
        // 業(yè)務(wù)邏輯
    }
}

解決方案

  1. 將方法拆分到不同的 Spring Bean 中,通過依賴注入調(diào)用;
  2. 注入自身的代理對象,通過代理對象調(diào)用(需開啟暴露代理);
  3. 使用AopContext.currentProxy()獲取代理對象調(diào)用。

使用場景: 權(quán)限驗(yàn)證、日志記錄、性能監(jiān)控

6.2 @Before / @After / @Around

作用: @Before、@After、@Around 是 Spring AOP 中最核心的三大通知注解,與 @Aspect 切面類配合使用,核心作用是定義橫切邏輯的織入時(shí)機(jī)—— 將日志記錄、性能監(jiān)控、權(quán)限校驗(yàn)等通用非業(yè)務(wù)邏輯,精準(zhǔn)織入到目標(biāo)方法的執(zhí)行前、執(zhí)行后、執(zhí)行前后全生命周期,實(shí)現(xiàn)業(yè)務(wù)代碼與橫切邏輯的解耦,是 Spring AOP 實(shí)現(xiàn)「無侵入式功能增強(qiáng)」的核心載體。

三者均標(biāo)注在切面類(@Aspect + @Component 標(biāo)注)的方法上,需綁定切入點(diǎn)(@Pointcut) 指定增強(qiáng)的目標(biāo)方法,共同覆蓋目標(biāo)方法的核心執(zhí)行節(jié)點(diǎn),其中 @Around 功能最全面,可實(shí)現(xiàn)前兩者的所有效果。

三大注解核心定義與核心作用:

1. @Before:前置通知注解

核心定義:標(biāo)注在切面類方法上,指定橫切邏輯在目標(biāo)方法執(zhí)行前執(zhí)行,是最基礎(chǔ)的通知類型。

核心作用:用于實(shí)現(xiàn)目標(biāo)方法執(zhí)行前的預(yù)處理邏輯,無返回值,無法修改目標(biāo)方法的入?yún)?,也無法控制目標(biāo)方法是否執(zhí)行。

核心適用場景:權(quán)限校驗(yàn)、接口入?yún)⑷罩居涗洝①Y源初始化(如數(shù)據(jù)庫連接準(zhǔn)備)、請求參數(shù)預(yù)處理等。

2. @After:最終通知注解

核心定義:標(biāo)注在切面類方法上,指定橫切邏輯在目標(biāo)方法執(zhí)行結(jié)束后執(zhí)行(無論目標(biāo)方法是否拋出異常),是「必執(zhí)行」的通知類型。

核心作用:用于實(shí)現(xiàn)目標(biāo)方法執(zhí)行后的收尾邏輯,無返回值,無法獲取目標(biāo)方法返回值或異常信息,僅做最終兜底處理。

核心適用場景:資源統(tǒng)一釋放(如關(guān)閉數(shù)據(jù)庫連接、清空臨時(shí)緩存、關(guān)閉文件流)、方法執(zhí)行完成的通用日志標(biāo)記等。

3. @Around:環(huán)繞通知注解

核心定義:標(biāo)注在切面類方法上,指定橫切邏輯包裹目標(biāo)方法的全執(zhí)行生命周期(執(zhí)行前 + 執(zhí)行中 + 執(zhí)行后 + 異常時(shí)),是功能最強(qiáng)大、最靈活的通知類型。

核心作用:可實(shí)現(xiàn)目標(biāo)方法的全流程控制:能修改入?yún)ⅰ⑹謩?dòng)控制目標(biāo)方法是否執(zhí)行、獲取 / 修改返回值、捕獲處理異常,完全覆蓋 @Before@After 的能力。

核心適用場景:性能監(jiān)控(統(tǒng)計(jì)方法執(zhí)行耗時(shí))、全流程日志記錄(入?yún)?+ 執(zhí)行結(jié)果 + 耗時(shí))、核心接口的權(quán)限控制、方法返回值緩存等。

核心使用差異

注解織入時(shí)機(jī)核心能力方法入?yún)?/th>關(guān)鍵特性核心限制
@Before目標(biāo)方法執(zhí)行前僅做前置預(yù)處理,無返回值JoinPoint(獲取方法信息)執(zhí)行時(shí)機(jī)固定,邏輯簡單無法修改入?yún)?、無法控制目標(biāo)方法執(zhí)行、無返回值
@After目標(biāo)方法執(zhí)行結(jié)束后(必執(zhí)行)僅做最終收尾處理,無返回值JoinPoint(獲取方法信息)無論異常與否都會(huì)執(zhí)行無法獲取返回值、無法捕獲異常、無返回值
@Around目標(biāo)方法執(zhí)行前后全生命周期修改入?yún)?、控制?zhí)行、獲取 / 修改返回值、捕獲異常,覆蓋前兩者所有能力ProceedingJoinPoint(含執(zhí)行方法)功能最全面,靈活性最高必須調(diào)用 proceed() 執(zhí)行目標(biāo)方法,必須返回結(jié)果

關(guān)鍵入?yún)⒄f明

  • JoinPoint:基礎(chǔ)入?yún)?,可獲取目標(biāo)方法的類名、方法名、入?yún)?shù)組等信息,@Before/@After 可直接使用;
  • ProceedingJoinPoint:繼承自 JoinPoint,新增 proceed() 方法 ——手動(dòng)執(zhí)行目標(biāo)業(yè)務(wù)方法,是 @Around 的專屬入?yún)?,無此方法則無法觸發(fā)目標(biāo)方法執(zhí)行。

完整使用示例(同一切面,對比實(shí)現(xiàn))

業(yè)務(wù)層方法(@Service) 為增強(qiáng)目標(biāo),實(shí)現(xiàn)「日志記錄 + 性能監(jiān)控」功能,分別演示三者的使用方式,統(tǒng)一綁定同一個(gè)切入點(diǎn),便于對比差異。

環(huán)境前提

  1. 引入 Spring AOP 起步依賴(Spring Boot 自動(dòng)配置):
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>
  1. 目標(biāo)業(yè)務(wù)類(被增強(qiáng)的方法,無任何侵入式修改):
import org.springframework.stereotype.Service;
@Service
public class UserService {
    // 正常方法:返回結(jié)果
    public String getUserById(Long id) throws InterruptedException {
        Thread.sleep(80); // 模擬業(yè)務(wù)執(zhí)行耗時(shí)
        return "查詢到用戶ID:" + id;
    }
    // 異常方法:拋出運(yùn)行時(shí)異常
    public void deleteUserById(Long id) {
        throw new RuntimeException("模擬刪除失?。河脩舨淮嬖?);
    }
}

切面類實(shí)現(xiàn)(@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;
// 1. 標(biāo)記為切面類  2. 注冊為Spring Bean(必須,否則AOP失效)
@Aspect
@Component
public class AopAdviceDemoAspect {
    private static final Logger log = LoggerFactory.getLogger(AopAdviceDemoAspect.class);
    // 定義公共切入點(diǎn):匹配UserService類的所有公共方法(精準(zhǔn)增強(qiáng)目標(biāo))
    @Pointcut("execution(public * com.example.demo.service.UserService.*(..))")
    public void userServicePointcut() {
        // 切入點(diǎn)方法:僅做標(biāo)識(shí),無需編寫任何邏輯
    }
    // ==================== 1. @Before 前置通知 ====================
    @Before("userServicePointcut()")
    public void doBefore(JoinPoint joinPoint) {
        // 獲取方法信息:類名.方法名
        String methodFullName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        // 獲取方法入?yún)?
        Object[] args = joinPoint.getArgs();
        // 前置邏輯:記錄方法開始執(zhí)行 + 入?yún)?
        log.info("【@Before 前置通知】方法{}開始執(zhí)行,入?yún)ⅲ簕}", methodFullName, Arrays.toString(args));
    }
    // ==================== 2. @After 最終通知 ====================
    @After("userServicePointcut()")
    public void doAfter(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        // 最終邏輯:標(biāo)記方法執(zhí)行結(jié)束(無論是否異常,都會(huì)打?。?
        log.info("【@After 最終通知】方法{}執(zhí)行結(jié)束(必執(zhí)行)", methodName);
    }
    // ==================== 3. @Around 環(huán)繞通知 ====================
    @Around("userServicePointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        // ① 執(zhí)行前邏輯:記錄開始時(shí)間 + 獲取方法信息(等效@Before)
        long startTime = System.currentTimeMillis();
        String methodFullName = joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        log.info("【@Around 執(zhí)行前】方法{}入?yún)ⅲ簕}", methodFullName, Arrays.toString(args));
        Object result = null;
        try {
            // ② 手動(dòng)執(zhí)行目標(biāo)方法(核心:必須調(diào)用,否則目標(biāo)方法不執(zhí)行)
            result = joinPoint.proceed();
            // ③ 執(zhí)行成功后邏輯:記錄返回值 + 耗時(shí)
            long costTime = System.currentTimeMillis() - startTime;
            log.info("【@Around 執(zhí)行成功】方法{}返回值:{},耗時(shí):{}ms", methodFullName, result, costTime);
        } catch (Throwable e) {
            // ④ 執(zhí)行異常時(shí)邏輯:記錄異常信息 + 耗時(shí)
            long costTime = System.currentTimeMillis() - startTime;
            log.error("【@Around 執(zhí)行異?!糠椒▄}執(zhí)行失敗,耗時(shí):{}ms,異常:{}", methodFullName, costTime, e.getMessage());
            throw e; // 重新拋出異常,讓全局異常處理器處理(不可省略)
        }
        // ⑤ 返回目標(biāo)方法結(jié)果(核心:必須返回,否則調(diào)用方獲取不到返回值)
        return result;
    }
}

實(shí)戰(zhàn)代碼:

@Aspect
@Component
public class LogAspect {
    // 前置通知:方法執(zhí)行前
    @Before("execution(* com.liu.controller.*.*(..))")
    public void before(JoinPoint joinPoint) {
        log.info("方法執(zhí)行前:{}", joinPoint.getSignature().getName());
    }
    // 后置通知:方法執(zhí)行后
    @After("execution(* com.liu.controller.*.*(..))")
    public void after(JoinPoint joinPoint) {
        log.info("方法執(zhí)行后:{}", joinPoint.getSignature().getName());
    }
    // 環(huán)繞通知:方法執(zhí)行前后
    @Around("execution(* com.liu.controller.*.*(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        Object result = joinPoint.proceed();  // 執(zhí)行方法
        long end = System.currentTimeMillis();
        log.info("方法執(zhí)行耗時(shí):{}ms", end - start);
        return result;
    }
}

6.3 自定義注解

作用:自定義注解是 Java 提供的元編程能力,允許開發(fā)者根據(jù)業(yè)務(wù)需求定義專屬的注解類型,結(jié)合 Spring 框架的 AOP、反射等特性,可實(shí)現(xiàn)無侵入式的業(yè)務(wù)增強(qiáng)(如自定義權(quán)限校驗(yàn)、操作日志、接口限流等),是企業(yè)級(jí)開發(fā)中實(shí)現(xiàn)通用邏輯復(fù)用、簡化業(yè)務(wù)代碼的核心手段。

自定義注解的核心價(jià)值是將通用邏輯與業(yè)務(wù)代碼解耦:通過注解標(biāo)記需要增強(qiáng)的類 / 方法 / 屬性,再通過注解解析器(反射 / AOP)識(shí)別注解并執(zhí)行對應(yīng)的橫切邏輯,無需修改業(yè)務(wù)代碼即可實(shí)現(xiàn)功能增強(qiáng)。

實(shí)戰(zhàn)代碼:

// 1. 定義注解
@Target(ElementType.METHOD)  // 作用在方法上
@Retention(RetentionPolicy.RUNTIME)  // 運(yùn)行時(shí)有效
public @interface RequireRole {
    int[] value() default {};  // 允許的角色
}
// 2. 使用注解
@RestController
@RequestMapping("/admin")
public class AdminController {
    @RequireRole({Constants.ROLE_ADMIN})  // 只允許管理員訪問
    @GetMapping("/users")
    public Result<List<User>> getAllUsers() {
        return Result.success(userService.list());
    }
}
// 3. 切面處理注解
@Aspect
@Component
public class RoleCheckAspect {
    @Before("@annotation(requireRole)")
    public void checkRole(JoinPoint joinPoint, RequireRole requireRole) {
        // 驗(yàn)證權(quán)限
    }
}

使用場景: 權(quán)限驗(yàn)證、日志記錄、緩存控制

七、Lombok注解(5個(gè))

首先先引入依賴:

<!-- Maven 依賴(與其他 Lombok 注解共用) -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.30</version>
    <scope>provided</scope>
</dependency>

7.1 @Data

作用: @DataLombok 框架的核心注解,核心作用是自動(dòng)為 Java 類生成通用的模板代碼,包括所有成員變量的getter/setter方法、toString()equals()、hashCode()方法,以及全參 / 無參構(gòu)造器的核心部分,徹底消除實(shí)體類、POJO 類中大量重復(fù)的模板代碼,大幅簡化類的編寫,提升開發(fā)效率并減少代碼維護(hù)成本。

實(shí)戰(zhàn)代碼:

@Data
public class User {
    private Long userId;
    private String username;
    private String password;
}
// 等價(jià)于手寫:
public class User {
    private Long userId;
    private String username;
    private String password;
    public Long getUserId() { return userId; }
    public void setUserId(Long userId) { this.userId = userId; }
    // ... 其他getter/setter
    @Override
    public String toString() { ... }
    @Override
    public boolean equals(Object o) { ... }
    @Override
    public int hashCode() { ... }
}

7.2 @NoArgsConstructor / @AllArgsConstructor

作用: @NoArgsConstructor@AllArgsConstructorLombok 框架的核心基礎(chǔ)注解,二者配合使用可分別為 Java 類自動(dòng)生成無參構(gòu)造器全參構(gòu)造器,徹底消除手動(dòng)編寫構(gòu)造器的模板代碼,簡化對象實(shí)例化操作,常與 @Data 組合成為實(shí)體類、POJO 類的標(biāo)配注解。

構(gòu)造器是 Java 類實(shí)例化對象的核心入口,手動(dòng)編寫多參構(gòu)造器不僅繁瑣,還會(huì)在新增 / 刪除字段時(shí)需同步修改,而這兩個(gè)注解通過編譯期字節(jié)碼增強(qiáng)自動(dòng)生成構(gòu)造器,開發(fā)時(shí)僅需注解標(biāo)注,編譯后字節(jié)碼中會(huì)包含對應(yīng)構(gòu)造器,與手動(dòng)編寫完全一致且運(yùn)行時(shí)無性能損耗。

實(shí)戰(zhàn)代碼:

@Data
@NoArgsConstructor  // 無參構(gòu)造器
@AllArgsConstructor  // 全參構(gòu)造器
public class User {
    private Long userId;
    private String username;
}
// 等價(jià)于:
public class User {
    public User() {}  // 無參構(gòu)造器
    public User(Long userId, String username) {  // 全參構(gòu)造器
        this.userId = userId;
        this.username = username;
    }
}

7.3 @RequiredArgsConstructor

作用: @RequiredArgsConstructor 是 Lombok 框架的核心構(gòu)造器注解,核心作用是為 Java 類自動(dòng)生成包含「必須初始化成員變量」的構(gòu)造器,這里的「必須初始化變量」特指被 final 修飾的成員變量和被 @NonNull 注解標(biāo)注的成員變量(這兩類變量在 Java 語法中要求必須初始化,否則編譯報(bào)錯(cuò))。該注解精準(zhǔn)解決了「僅為關(guān)鍵變量生成帶參構(gòu)造器」的需求,避免全參構(gòu)造器參數(shù)冗余,常與 @Data、@NoArgsConstructor 等注解組合使用,是實(shí)體類、配置類、服務(wù)類開發(fā)中的常用注解。

實(shí)戰(zhàn)代碼:

@Service
@RequiredArgsConstructor  // 自動(dòng)生成構(gòu)造器
public class UserServiceImpl implements UserService {
    private final UserMapper userMapper;  // final修飾,依賴注入
    private final JwtUtil jwtUtil;
    // Lombok自動(dòng)生成:
    // public UserServiceImpl(UserMapper userMapper, JwtUtil jwtUtil) {
    //     this.userMapper = userMapper;
    //     this.jwtUtil = jwtUtil;
    // }
}

為什么推薦?

  • 代碼簡潔
  • 不可變(final)
  • Spring自動(dòng)注入

7.4 @Slf4j

作用: @Slf4jLombok 框架的核心日志注解,核心作用是為 Java 類自動(dòng)生成基于 SLF4J 規(guī)范的日志對象private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(當(dāng)前類.class);),徹底消除手動(dòng)聲明日志對象的模板代碼,直接通過 log.info()/log.error() 等方法打印日志,是企業(yè)級(jí) Java 開發(fā)中日志記錄的標(biāo)配注解,與 @Data、@Service、@RestController 等注解無縫配合使用。

實(shí)戰(zhàn)代碼:

@Service
@Slf4j  // 自動(dòng)生成log對象
public class UserServiceImpl implements UserService {
    public User login(String username, String password) {
        log.info("用戶登錄:{}", username);  // 直接使用log
        log.error("登錄失敗:{}", username);
        log.debug("調(diào)試信息:{}", username);
    }
}
// 等價(jià)于:
public class UserServiceImpl implements UserService {
    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
}

7.5 @Builder

作用: @BuilderLombok 框架的核心創(chuàng)建型模式注解,核心作用是為 Java 類自動(dòng)實(shí)現(xiàn)建造者(Builder)設(shè)計(jì)模式,通過鏈?zhǔn)秸{(diào)用的方式靈活創(chuàng)建對象,替代傳統(tǒng)的無參構(gòu)造 + 多次 setter、多參構(gòu)造器的對象實(shí)例化方式,解決多字段對象創(chuàng)建時(shí)代碼繁瑣、參數(shù)順序易混淆、可選參數(shù)處理麻煩的問題,是企業(yè)級(jí)開發(fā)中創(chuàng)建復(fù)雜對象的標(biāo)配注解,常與 @Data@NoArgsConstructor、@AllArgsConstructor 組合使用。

實(shí)戰(zhàn)代碼:

@Data
@Builder
public class User {
    private Long userId;
    private String username;
    private String password;
}
// 使用:
User user = User.builder()
    .userId(1L)
    .username("admin")
    .password("123456")
    .build();

使用場景: 構(gòu)建復(fù)雜對象

八、注解組合速查表

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 實(shí)體類常用組合

@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);
    }
}

九、常見錯(cuò)誤匯總

錯(cuò)誤1:忘記加@Component系列注解

// 錯(cuò)誤:沒有@Service注解,Spring不會(huì)管理這個(gè)類
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;  // 注入失敗,userMapper為null
}
// 正確:加上@Service
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;  // 注入成功
}

錯(cuò)誤2:@Autowired注入失敗

// 錯(cuò)誤:UserMapper沒有被Spring管理
public interface UserMapper {  // 缺少@Mapper注解
    User selectById(Long id);
}
// 正確:加上@Mapper或在啟動(dòng)類加@MapperScan
@Mapper
public interface UserMapper {
    User selectById(Long id);
}

錯(cuò)誤3:@Transactional不生效

// 錯(cuò)誤:private方法,事務(wù)不生效
@Transactional
private void saveUser(User user) {
    userMapper.insert(user);
}
// 正確:必須是public方法
@Transactional
public void saveUser(User user) {
    userMapper.insert(user);
}

錯(cuò)誤4:@RequestBody和@RequestParam混用

// 錯(cuò)誤:不能同時(shí)使用
@PostMapping("/add")
public Result<Boolean> add(@RequestBody Bill bill, 
                           @RequestParam Long userId) {
    // 報(bào)錯(cuò)
}
// 正確:要么全用@RequestBody,要么全用@RequestParam
@PostMapping("/add")
public Result<Boolean> add(@RequestBody Map<String, Object> params) {
    Long userId = (Long) params.get("userId");
    Bill bill = (Bill) params.get("bill");
}

十、總結(jié)

10.1 必會(huì)注解(按使用頻率排序)

排名注解使用頻率重要程度
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參數(shù)?@RequestParam
需要獲取JSON數(shù)據(jù)?@RequestBody
需要獲取路徑參數(shù)?@PathVariable
需要參數(shù)校驗(yàn)?@Valid + 校驗(yàn)注解
需要依賴注入?@Autowired@RequiredArgsConstructor
需要事務(wù)?@Transactional
需要日志?@Slf4j
需要權(quán)限驗(yàn)證? → 自定義注解 + @Aspect

寫在最后

這篇文章整理了我在開發(fā)記賬系統(tǒng)時(shí)用到的所有注解,每個(gè)示例都來自真實(shí)項(xiàng)目代碼。

到此這篇關(guān)于Spring Boot常用注解速查表(30個(gè)必會(huì)注解+實(shí)戰(zhàn)案例)的文章就介紹到這了,更多相關(guān)Spring Boot注解速查表內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot獲取前臺(tái)參數(shù)的六種方式以及統(tǒng)一響應(yīng)

    SpringBoot獲取前臺(tái)參數(shù)的六種方式以及統(tǒng)一響應(yīng)

    本文主要介紹了SpringBoot獲取前臺(tái)參數(shù)的六種方式以及統(tǒng)一響應(yīng),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • java 枚舉類定義靜態(tài)valueOf(java.lang.String)方法的問題及解決

    java 枚舉類定義靜態(tài)valueOf(java.lang.String)方法的問題及解決

    這篇文章主要介紹了java 枚舉類定義靜態(tài)valueOf(java.lang.String)方法的問題及解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • 解析java中的error該不該捕獲

    解析java中的error該不該捕獲

    這篇文章主要介紹了java中的error該不該捕獲,需要的朋友可以參考下
    2014-02-02
  • 基于JavaSwing+mysql開發(fā)一個(gè)學(xué)生社團(tuán)管理系統(tǒng)設(shè)計(jì)和實(shí)現(xiàn)

    基于JavaSwing+mysql開發(fā)一個(gè)學(xué)生社團(tuán)管理系統(tǒng)設(shè)計(jì)和實(shí)現(xiàn)

    項(xiàng)目使用Java swing+mysql開發(fā),可實(shí)現(xiàn)基礎(chǔ)數(shù)據(jù)維護(hù)、用戶登錄注冊、社團(tuán)信息列表查看、社團(tuán)信息添加、社團(tuán)信息修改、社團(tuán)信息刪除以及退出注銷等功能、界面設(shè)計(jì)比較簡單易學(xué)、適合作為Java課設(shè)設(shè)計(jì)以及學(xué)習(xí)技術(shù)使用,需要的朋友參考下吧
    2021-08-08
  • java?io文件操作刪除文件或文件夾的7種方法

    java?io文件操作刪除文件或文件夾的7種方法

    這篇文章主要為大家介紹了java?io文件操作刪除文件或文件夾的7種方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步
    2022-03-03
  • SpringSecurity中的UserDetailsService深度解析

    SpringSecurity中的UserDetailsService深度解析

    文章介紹了Spring Security中的UserDetailsService接口,它用于自定義用戶認(rèn)證邏輯,通過實(shí)現(xiàn)該接口,可以自定義用戶認(rèn)證過程,文章詳細(xì)解釋了UserDetailsService接口的返回值、方法參數(shù)以及可能出現(xiàn)的異常,如UsernameNotFoundException,感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • 解讀JVM的生命周期是怎么樣的

    解讀JVM的生命周期是怎么樣的

    JVM的生命周期包括啟動(dòng)、運(yùn)行和終止三個(gè)階段,啟動(dòng)階段包括創(chuàng)建JVM實(shí)例、加載和初始化核心類庫、加載main方法所在的類和初始化類,運(yùn)行階段包括執(zhí)行main方法、類加載、字節(jié)碼執(zhí)行、內(nèi)存管理、線程管理和異常處理,終止階段包括正常終止、異常終止和外部終止
    2025-03-03
  • springboot+jsonp解決前端跨域問題小結(jié)

    springboot+jsonp解決前端跨域問題小結(jié)

    這篇文章主要介紹了springboot+jsonp解決前端跨域問題小結(jié),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-06-06
  • 從實(shí)戰(zhàn)角度詳解Disruptor高性能隊(duì)列

    從實(shí)戰(zhàn)角度詳解Disruptor高性能隊(duì)列

    這篇文章主要介紹了從實(shí)戰(zhàn)角度詳解Disruptor高性能隊(duì)列,對正在學(xué)習(xí)這方面知識(shí)的小伙伴有很大的幫助,感興趣的小伙伴快來一起學(xué)習(xí)吧
    2021-08-08
  • Java 生成簽名證書的實(shí)現(xiàn)示例

    Java 生成簽名證書的實(shí)現(xiàn)示例

    本文主要介紹了Java 生成簽名證書的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-09-09

最新評(píng)論

南部县| 驻马店市| 马边| 桑植县| 桃园市| 孟津县| 资中县| 繁峙县| 邻水| 沐川县| 丁青县| 延庆县| 达尔| 凌海市| 四平市| 苏尼特右旗| 宜阳县| 漳浦县| 新化县| 山东省| 洛阳市| 四平市| 车致| 龙山县| 集安市| 崇信县| 日土县| 福贡县| 襄城县| 永吉县| 乐至县| 开化县| 五常市| 平昌县| 通辽市| 台江县| 阳东县| 承德市| 中牟县| 呼伦贝尔市| 运城市|