<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      代碼的隱形守護者:Spring AOP 是如何做到的?

      如何使用AOP

      用 “打針” 場景一次性記住 AOP 核心概念

      想象你去醫院打針的過程:

      目標對象(Target)

      就是 “你”(被打針的人),核心業務是 “生病看病”。

      連接點(Join Point)

      你身體上所有能打針的地方(胳膊、屁股等所有可能的位置)。

      用打針場景重新理解「切點(Pointcut)」

      還是以打針為例,但更貼近@Pointcut注解和表達式的作用:

      你去醫院打針時,護士不會隨便找個地方扎,而是要按「規則」精準定位 —— 這個「規則」就是切點。

      比如醫院規定:
      「只給兒科發燒患者,在胳膊三角肌退燒針
      這里的「兒科患者 + 發燒 + 胳膊三角肌 + 退燒針」就是一套「切點規則」,對應 AOP 中@Pointcut的表達式邏輯。

      對應到代碼中的切點定義

      @Pointcut注解就像醫院的「打針規則手冊」,而execution 表達式就是手冊里的具體條款:

      // 例:攔截所有Controller中public方法的切點
      @Pointcut("execution(public * cn.soboys.controller.*.*(..))")
      public void controllerPointcut() {}
      

      這個表達式的含義,對應到打針場景就是:

      • execution:「在打針動作執行時生效」(方法執行時觸發);

      • public :「不管是哪種針(肌肉針 / 靜脈針),只要是公開給患者的操作」(任意返回值的 public 方法);

      • cn.soboys.controller.*:「只針對兒科診室里的所有病床」(指定包下的所有類);

      • *(..):「不管患者年齡、體重如何,只要是打針操作都算」(任意方法名,任意參數)。

      切點的核心作用:精準篩選,可重用

      • 精準篩選:就像醫院用「兒科 + 發燒 + 退燒針」篩出需要特殊處理的患者,execution表達式通過「返回值 + 類名 + 方法名 + 參數」精準定位要攔截的方法(比如只攔截UserController里帶@PostMapping的方法)。
      • 可重用:定義一次@Pointcut("xxx"),后續所有通知(前置 / 后置等)都能直接引用這個切點,就像醫院把「兒科退燒針規則」寫在手冊里,所有護士都能按同一套規則執行,不用每次重新定義。

      通知(Advice)

      打針的具體動作:

      • 前置通知:打針前 “用酒精棉消毒”;
      • 后置通知:打完后 “貼創可貼”;
      • 環繞通知:“按住皮膚→扎針→推藥→拔針”(全程包圍核心動作);
      • 異常通知:如果 “打針時出血了”,醫生會額外 “止血”。

      切面(Aspect)

      醫生的 “打針流程手冊”,里面寫清了 “在胳膊三角?。ㄇ悬c)打針,步驟是消毒→扎針→貼創可貼(通知)”——切點 + 通知 = 切面。

      • 織入(Weaving):醫生按照手冊給你打針的過程(把流程 “套” 到你身上)。

      一句話總結

      • 連接點:所有可能被 “切” 的地方(能打針的所有位置);
      • 切點:實際被 “切” 的地方(選好的打針位置);
      • 通知:“切” 的時候做什么(消毒、扎針等動作);
      • 切面:規定 “在哪里切 + 切了做什么”(完整的打針方案)。

      AOP 最適合的場景

      記?。?strong>所有 “重復出現在多個業務里,但又不是核心業務” 的功能,都該用 AOP。
      比如:

      • 日志:每個接口都要記錄請求,但日志不是業務本身;
      • 權限:每個敏感操作都要驗權限,驗權限不是業務目的;
      • 事務:訂單、支付等操作都要事務控制,控制事務不是業務核心;
      • 監控:統計每個方法的執行時間,統計不是業務邏輯。

      就像打針時,“消毒、貼創可貼” 不是看病的核心(核心是給藥),但每個打針流程都需要 —— 這就是 AOP 要干的事。

      案例說明

      本案例的主要目標是通過兩個不同的業務類(CalculatorUserService),展示 AOP 在實際項目中的應用。具體來說,使用 AOP 實現以下功能:

      1. Calculator 類的所有方法進行日志記錄,包括方法調用前、調用后、正常返回和拋出異常時的日志。
      2. UserService 類的方法進行日志記錄、數據脫敏和權限檢查。

      導入依賴

      <!--aop 切面-->
              <dependency>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-starter-aop</artifactId>
              </dependency>
      

      定義業務邏輯類

      UserService

      import lombok.Data;
      import org.springframework.stereotype.Service;
      
      @Service
      public class UserService {
          public User getUserById(int id) {
              // 模擬返回用戶信息
              return new User(id, "Alice", "alice@example.com");
          }
      
          public void createUser(User user) {
              // 模擬創建用戶
              System.out.println("創建用戶: " + user);
          }
      
          public void updateUser(User user) {
              // 模擬更新用戶
              System.out.println("更新用戶: " + user);
          }
      
          public void deleteUser(int id) {
              // 模擬刪除用戶
              System.out.println("刪除用戶,ID: " + id);
          }
      }
      
      
      @Data
      class User {
          private int id;
          private String name;
          private String email;
      
          public User(int id, String name, String email) {
              this.id = id;
              this.name = name;
              this.email = email;
          }
      
          @Override
          public String toString() {
              return "User{" +
                      "id=" + id +
                      ", name='" + name + '\'' +
                      ", email='" + email + '\'' +
                      '}';
          }
      }
      

      意義UserService 類模擬了一個用戶服務,包含了獲取用戶信息、創建用戶、更新用戶和刪除用戶的方法。通過對這個類的方法進行 AOP 處理,可以展示 AOP 在更復雜業務場景下的應用,如數據脫敏和權限檢查。

      定義切面

      @Aspect
      @Component
      public class UserAspect {
      
          // 定義切點,攔截UserService類的所有方法
          @Pointcut("execution(* org.example.aopdemo.UserService.*(..))")
          public void allMethods() {}
      
          // 定義切點,攔截UserService類中createUser和updateUser方法
          @Pointcut("execution(* org.example.aopdemo.UserService.createUser(..)) || execution(* org.example.aopdemo.UserService.updateUser(..))")
          public void userOperations() {}
      
          // 定義切點,攔截UserService類中getUserById方法
          @Pointcut("execution(* org.example.aopdemo.UserService.getUserById(..))")
          public void getUserOperations() {}
      
          // 前置通知:在方法執行之前執行
          @Before("allMethods()")
          public void beforeAdvice(JoinPoint joinPoint) {
              MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
              String methodName = methodSignature.getMethod().getName();
              System.out.println("前置通知:方法 " + methodName + " 被調用,參數為 " + Arrays.toString(joinPoint.getArgs()));
          }
      
          // 后置通知:在方法執行之后執行,無論是否發生異常
          @After("allMethods()")
          public void afterAdvice(JoinPoint joinPoint) {
              MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
              String methodName = methodSignature.getMethod().getName();
              System.out.println("后置通知:方法 " + methodName + " 已執行完畢。");
          }
      
          // 返回通知:在方法正常返回后執行
          @AfterReturning(pointcut = "getUserOperations()", returning = "result")
          public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
              MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
              String methodName = methodSignature.getMethod().getName();
              System.out.println("返回通知:方法 " + methodName + " 返回結果為 " + result);
              // 數據脫敏處理
              if (result instanceof User) {
                  User user = (User) result;
                  System.out.println("數據脫敏處理:用戶信息已脫敏,返回的用戶ID為 " + user.getId());
              }
          }
      
          // 異常通知:在方法拋出異常后執行
          @AfterThrowing(pointcut = "allMethods()", throwing = "exception")
          public void afterThrowingAdvice(JoinPoint joinPoint, Throwable exception) {
              MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
              String methodName = methodSignature.getMethod().getName();
              System.out.println("異常通知:方法 " + methodName + " 拋出異常:" + exception.getMessage());
          }
      
          // 環繞通知:對createUser和updateUser方法進行權限檢查
          @Around("userOperations()")
          public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
              MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
              String methodName = methodSignature.getMethod().getName();
              System.out.println("環繞通知:方法 " + methodName + " 開始執行,進行權限檢查...");
              // 模擬權限檢查
              if (!hasPermission()) {
                  throw new SecurityException("沒有權限執行此操作!");
              }
              Object result = joinPoint.proceed(); // 繼續執行原方法
              System.out.println("環繞通知:方法 " + methodName + " 執行完成。");
              return result;
          }
      
          private boolean hasPermission() {
              // 模擬權限檢查邏輯
              return true; // 假設當前用戶有權限
          }
      }
      
      

      在 AOP(面向切面編程)中,JoinPoint 是一個非常重要的概念,JoinPoint joinPoint 中的 JoinPoint 是一個接口,它代表程序執行過程中的某個特定位置,例如方法調用、異常拋出等。下面詳細解釋 JoinPoint 的含義、作用以及在提供的代碼中的使用方式。

      JoinPoint 的含義

      JoinPoint 是 AOP 中的一個抽象概念,它表示程序執行過程中可以插入切面代碼的點。在 Spring AOP 里,JoinPoint 通常代表方法的執行,因為 Spring AOP 主要基于方法攔截來實現。

      JoinPoint 的作用

      JoinPoint 提供了一系列方法,用于獲取與當前連接點相關的信息,比如:

      • 獲取方法簽名:可以獲取被調用方法的名稱、參數類型等信息。
      • 獲取方法參數:可以獲取傳遞給被調用方法的實際參數。
      • 獲取目標對象:可以獲取被調用方法所在的對象實例。

      以這個為例子說明:

        public void beforeAdvice(JoinPoint joinPoint) {
              MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
              String methodName = methodSignature.getMethod().getName();
              System.out.println("前置通知:方法 " + methodName + " 被調用,參數為 " + Arrays.toString(joinPoint.getArgs()));
          }
      
      • joinPoint.getSignature()getSignature()JoinPoint 接口的一個方法,用于獲取當前連接點的簽名信息,返回的是一個 Signature 類型的對象。
      • (MethodSignature):由于我們處理的是方法調用,所以將 Signature 對象強制轉換為 MethodSignature 類型,以便獲取方法的具體信息。

      測試執行

      @SpringBootApplication
      public class AopDemoApplication {
      
          public static void main(String[] args) {
              ApplicationContext context = SpringApplication.run(AopDemoApplication.class, args);
      
              UserService userService = context.getBean(UserService.class);
      
              System.out.println("\n測試getUserById方法:");
              User user = userService.getUserById(1);
      
              System.out.println("\n測試createUser方法:");
              userService.createUser(new User(2, "Bob", "bob@example.com"));
      
              System.out.println("\n測試updateUser方法:");
              userService.updateUser(new User(2, "Bob Updated", "bob-updated@example.com"));
      
              System.out.println("\n測試deleteUser方法:");
              userService.deleteUser(2);
          }
      }
      

      這里寫的只不過是測試方法,在項目中應該是寫到config文件中。直接配置,注入到springboot容器中。

      posted @ 2025-07-12 11:33  叮咚~到賬一個億  閱讀(15)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 一区二区国产精品精华液| 公与淑婷厨房猛烈进出视频免费| 亚洲人成色77777| 久久精品一区二区三区av| 40岁大乳的熟妇在线观看| 无码av中文一区二区三区桃花岛| 婷婷六月色| 在线亚洲午夜理论av大片| 日本免费一区二区三区| 久久久久噜噜噜亚洲熟女综合| 久久国产精品成人影院| 亚洲精品无码成人A片九色播放| 91久久偷偷做嫩草影院免费看| 亚洲AV日韩AV永久无码下载| 亚洲色成人一区二区三区| 97久久久精品综合88久久| 久久精品人人槡人妻人人玩| 91亚洲国产三上悠亚在线播放| 亚洲男人天堂东京热加勒比 | 年日韩激情国产自偷亚洲| www久久只有这里有精品| 日韩av第一页在线播放| 国产一区二区不卡在线| 中文字幕在线看视频一区二区三区 | 国产真实younv在线| 加勒比无码人妻东京热| 国产精品免费视频不卡| 国产精品三级黄色小视频| 97久久久亚洲综合久久| 日本免费一区二区三区日本| 无码日韩精品一区二区三区免费| 人妻人人澡人人添人人爽| 99RE6在线观看国产精品| 一本大道无码av天堂| 水蜜桃视频在线观看免费18| a级国产乱理伦片在线观看al| 国产网红女主播精品视频| 亚洲欧美日韩久久一区二区| 精品视频一区二区| 色综合久久久久综合体桃花网| 日本一区二区三区小视频|