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

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

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

      異常體系與項目實踐

      程序式陰影:為什么不報錯?

      一、簡介

      在程序開發的過程中,異常處理從來都是一個復雜的維度,無論是新手還是經驗老到的選手,在編碼時都會面對各種異常情況;

      程序中的異常可以反映系統的缺陷和待優化的點,并且是無法完全避免的,如何處理異常和降低異常出現的頻率,是系統質量的基礎保障;

      隨著分布式架構的流行,各種復雜的請求鏈路給異常處理帶來了巨大的麻煩,需要全面的監控來定位原因,才能快速的優化和解決;

      二、異常體系

      不論是JDK基礎,還是各類組件,在源碼中都涉及大量的異常封裝,從而精確的反映出描述信息,先來看看Java中的異常體系基礎;

      Throwable:是所有錯誤「Error」和異常「Exception」的超類,

      Error:通常是底層的不可恢復的類,此類錯誤一般都比較嚴重,JVM將終止其運行的線程;

      Exception:程序自身可以捕獲并且可以預處理的異常,例如捕獲處理或者拋出;

      針對「編譯器」來說,異常又分為「檢查」異常和「非檢查」異常;

      檢查異常:即編譯時異常,在編譯時期就會被編譯器查驗到的異常,這類異常要么捕獲處理要么拋出,否則就會報編譯錯誤;

      非檢查異常:即運行時異常,在編譯時期不會被編譯器查驗到的異常,這類異常只有在程序運行的時候,才會有可能被拋出;

      三、異常用法

      1、使用細節

      Java異常處理關鍵字,分別是:「try」可能拋異常的代碼塊,「catch」捕獲異常、「finally」必須執行的代碼塊、「throw」方法內拋指定異常、「throws」方法聲明拋多個異常;

      public class UseExe01 {
          public static void main(String[] args) {
              try {
                  strStm ();
                  ioStm();
              } catch (NullPointerException e) {
                  System.out.println("空指針異常:"+e.getMessage());
                  e.printStackTrace();
              } catch (IOException e) {
                  System.out.println("IO流異常:"+e.getMessage());
                  e.printStackTrace();
              } catch (Exception e) {
                  System.out.println("異常:"+e.getMessage());
                  e.printStackTrace();
              } finally {
                  System.out.println("execute...finally");
              }
          }
          public static void ioStm () throws FileNotFoundException {
              new FileInputStream(new File("file_path"));
          }
          public static String strStm () throws NullPointerException {
              Object object = new Object() ;
              return object.getClass().getName() ;
          }
      }
      

      案例分析

      細節分析

      • 如果「try」代碼塊中沒有拋出異常,執行完會跳到「finally」代碼塊;
      • 如果「try」代碼塊中拋出異常,則執行「catch」代碼塊,無論是否捕獲異常,最終都要執行「finally」代碼塊;
      • 可以存在多個「catch」代碼塊,但是最多只匹配一個異常;
      • 捕獲異常與拋出異常的類型可以匹配,或者捕獲異常的類型是拋出異常的父類;
      • 在異常捕獲時,同一個繼承體系內,先捕獲子類異常,再捕獲父類異常;

      2、返回值問題

      在異常處理邏輯中,有一個非常經典的問題,就是「return」返回值,如果在「try.catch.finally」代碼塊中都存在「return」關鍵字,則要分情況討論;

      2.1 值類型

      public class UseExe02 {
          // 返回【2】
          public static int getInt1 () {
              try {
                  int i = 1 / 0;
              } catch (ArithmeticException e){
                  e.printStackTrace();
                  return 1;
              } finally {
                  System.out.println("execute...finally");
                  return 2;
              }
          }
          // 返回【1】
          public static int getInt2 () {
              int a = 1;
              try{
                  int i = 1/0;
                  return a;
              }catch (ArithmeticException e){
                  e.printStackTrace();
                  return a;
              }finally {
                  ++a;
                  System.out.println("execute...finally");
              }
          }
          // 返回【3】
          public static int getInt3 () {
              int a = 1;
              try{
                  int i = 1/0;
                  a++;
                  return a ;
              }catch (ArithmeticException e){
                  a++;
                  e.printStackTrace();
              }finally {
                  a++;
                  System.out.println("execute...finally");
              }
              return a ;
          }
      }
      

      邏輯分析

      2.2 引用類型

      public class UseExe03 {
          // 返回【張三】
          public static String getStr1 () {
              String var ;
              try {
                  var = new String("張三");
                  return var ;
              } catch (ArithmeticException e){
                  e.printStackTrace();
              } finally {
                  var = new String("李四");
                  System.out.println("execute...finally:"+var);
              }
              return var ;
          }
          // 返回【李四】
          public static String getStr2 () {
              String var ;
              try{
                  int i = 1/0;
                  var = new String("張三");
                  return var;
              }catch (ArithmeticException e){
                  e.printStackTrace();
                  var = new String("李四");
                  return var;
              }finally {
                  var = new String("王五");
                  System.out.println("execute...finally:"+var);
              }
          }
          // 返回【王五】
          public static String getStr3 () {
              String var ;
              try{
                  int i = 1/0;
                  var = new String("張三");
                  return var ;
              }catch (ArithmeticException e){
                  var = new String("李四");
                  e.printStackTrace();
              }finally {
                  var = new String("王五");
                  System.out.println("execute...finally:"+var);
              }
              return var ;
          }
      }
      

      邏輯分析

      2.3 結論說明

      • 如果只有「try」代碼塊中有「return」關鍵字,邏輯執行正常則得到「try」處的返回值;
      • 如果只有「try.catch」代碼塊中有「return」關鍵字,「try」代碼塊異常,「catch」代碼塊執行正常,則得到「catch」處的返回值;
      • 如果「finally」代碼塊中有「return」關鍵字,當該代碼塊執行正常時會得到此處的返回值;

      值得說明的一點是,從異常的設計原理來來說,并不推薦在「finally」代碼塊中使用「return」關鍵字,可能會導致程序提前結束,這也是常見的開發規范;

      四、項目實踐

      1、異常定義

      對于復雜的分布式工程來說,系統發生問題時,十分依賴異常信息的捕獲,從而快速定位原因和解決;

      項目在處理異常時,需要考慮兩個核心維度:「1」捕獲和解決異常信息,「2」傳遞異常信息到應用端,從而引導用戶的動作;

      在系統中,通常依賴很多自定義的異常,比如常見:系統異常,業務異常,第三方異常;基本都是「運行時」異常;

      系統異常:比如超時請求或者服務級別異常,導致流程無法執行,需要研發人員介入處理;

      業務異常:基于響應的提示信息,用戶可以自行解決的問題,比如常見的參數校驗,授權問題等;

      第三方異常:可以是內部不同系統的交互,也可以是第三方的交互,可能會涉及到各種響應狀態,通過內部的封裝進行統一管理,并且要保留第三方的響應;

      2、異常封裝

      基于運行時異常「RuntimeException」類,分別定義「系統」、「業務」、「第三方」三類異常;

      自定義異常基礎類,注意此處省略很多構造方法,作為「RuntimeException」的子類,具體參考其源碼的構造方法即可;

      public class BaseExe extends RuntimeException {
          private String code ;
          public BaseExe (String code,String msg) {
              super(msg);
              this.code = code ;
          }
          public BaseExe(String message, Throwable cause) {
              super(message, cause);
          }
          // 省略其他構造方法
      }
      

      系統異常類,并提供常用的系統異常信息枚舉類;

      public enum SysExeCode {
          SYSTEM_EXE("S00000", "系統異常");
      }
      public class SysException extends BaseExe {
          public SysException(String code, String msg) {
              super(code, msg);
          }
          public SysException(SysExeCode sysExeCode) {
              super(sysExeCode.getCode(), sysExeCode.getMsg());
          }
      }
      

      業務異常類,并提供常用的業務異常信息枚舉類;

      public enum BizExeCode {
          BIZ_EXE("B00000", "業務異常");
      }
      public class BizException extends BaseExe {
          public BizException(String code, String msg) {
              super(code, msg);
          }
          public BizException(BizExeCode bizExeCode) {
              super(bizExeCode.getCode(), bizExeCode.getMsg());
          }
      }
      

      第三方異常類,并提供常用的第三方異常信息枚舉類;

      public enum ThirdExeCode {
          THIRD_EXE("T00000", "第三方異常");
      }
      public class ThirdException extends BaseExe {
          // 第三方交互異常響應信息
          private String thirdCode ;
          private String thirdMsg ;
          public ThirdException(String code, String msg) {
              super(code, msg);
          }
          public ThirdException(String code, String msg,String thirdCode,String thirdMsg) {
              super(code, msg);
              this.thirdCode = thirdCode ;
              this.thirdMsg = thirdMsg ;
          }
          public ThirdException(ThirdExeCode thirdExeCode,String thirdCode,String thirdMsg) {
              super(thirdExeCode.getCode(), thirdExeCode.getMsg());
              this.thirdCode = thirdCode ;
              this.thirdMsg = thirdMsg ;
          }
      }
      

      從開發規范來說,不允許在代碼中隨意添加異常描述信息,必須都維護在相應的枚舉類中,不同的異常類型,要在合適的場景下拋出,盡量由最上層統一捕獲并處理,再轉換為統一的響應結果;

      3、異常處理

      3.1 響應方式

      在微服務項目中,通常采用RestControllerAdviceExceptionHandler注解,實現全局異常的捕獲和處理;

      @RestControllerAdvice
      public class ExeHandler {
          /**
           * 默認異常
           */
          @ExceptionHandler(value = Exception.class)
          public void defaultException(Exception e) {
              // 統一返回
          }
          /**
           * 系統異常
           */
          @ExceptionHandler(value = SysException.class)
          public void sysException(SysException e) {
              // 統一返回
          }
          /**
           * 業務異常
           */
          @ExceptionHandler(value = BizException.class)
          public void bizException(BizException e) {
              // 統一返回
          }
          /**
           * 第三方異常
           */
          @ExceptionHandler(value = ThirdException.class)
          public void thirdException(ThirdException e) {
              // 統一返回
          }
      }
      

      3.2 記錄方式

      通常在一些核心的業務流程中,會通過注解的方式記錄日志,于研發而言,最關心的還是異常日志,以此為邏輯優化的關鍵依據;

      比較常用的技術手段是自定義注解+切面編程來實現,細節參考開源倉庫中《集成日志,復雜業務下的自定義實現》篇幅內容;

      @Component
      @Aspect
      public class LogAop {
          /**
           * 日志切入點
           */
          @Pointcut("@annotation(com.defined.log.annotation.DefinedLog)")
          public void logPointCut() {
          }
          /**
           * 環繞切入
           */
          @Around("logPointCut()")
          public Object around (ProceedingJoinPoint proceedingJoinPoint) {
              try{
                  // 執行方法
                  result = proceedingJoinPoint.proceed();
              } catch (SysException e){
                  // 系統異常
              } catch (BizException e){
                  // 業務異常
              } catch (ThirdException e){
                  // 第三方異常
              } catch (Exception e){
                  // 默認異常
              } finally {
                  // 信息處理
              }
              return result ;
          }
      }
      

      4、異常通知

      拋開業務異常不說,對于「系統」和「第三方」異常,通常都會第一時間觸達到研發,從而快速定位原因和處理;

      一般會根據異常的級別,將進行不同維度的消息觸達,比如某微,某釘,郵件,短信等;

      從技術的實現上來看,常規也是采用切面編程的方式,細節參考開源倉庫中《基于AOP切面,實現系統告警功能》篇幅內容;關于消息中心的搭建設計,同樣可以參考開源倉庫中《聊聊消息中心的設計與實現邏輯》篇幅內容;

      5、系統故障

      從系統架構的層面來分析,大部分組件都提供了必要的監控能力,而這種監控手段的核心價值在于快速發現故障,并且提供一定的分析能力;

      比如分布式系統中,復雜的請求的鏈路,對于故障的定位和排查難度都是極大的,需要將各種組件的監控信息進行統籌分析;

      系統層面監控

      請求鏈路分析

      日志記錄能力

      可以從關鍵的日志記錄作為問題切入點,再基于系統層面的監控能力縮小問題范圍,分析請求鏈路的異常原因,最后通過完整的日志分析細節,從而提升問題解決的效率;

      關于這些技術的應用,在開源倉庫中都有詳細案例,此處不再贅述;

      五、參考源碼

      編程文檔:
      https://gitee.com/cicadasmile/butte-java-note
      
      應用倉庫:
      https://gitee.com/cicadasmile/butte-flyer-parent
      
      posted @ 2023-05-19 08:12  七號樓  閱讀(1103)  評論(1)    收藏  舉報
      主站蜘蛛池模板: 国内少妇人妻偷人精品| 亚洲国产成人综合精品| 重口SM一区二区三区视频| 欧美性猛交xxxx免费看| 九九热在线视频免费观看| av永久天堂一区| 起碰免费公开97在线视频| 无码一区二区三区av在线播放| 免费又大粗又爽又黄少妇毛片| 久久精品中文字幕免费| 精品亚洲国产成人| 日韩午夜福利视频在线观看 | 国产AV福利第一精品| 国产中文字幕在线一区| 狠狠躁日日躁夜夜躁欧美老妇| 麻豆最新国产AV原创精品| 国产精品无码av不卡| 无遮挡午夜男女xx00动态| 欧美一本大道香蕉综合视频| 高陵县| 日韩一区二区黄色一级片| 国产精品国三级国产av| 免费的很黄很污的视频| 在线永久看片免费的视频| 欧美熟妇乱子伦XX视频| 治多县| 国产精品一线天在线播放| 国产精品普通话国语对白露脸| 欧美乱大交xxxxx疯狂俱乐部| xxxxbbbb欧美残疾人| 99九九视频高清在线| 国产睡熟迷奷系列网站| 强奷白丝美女在线观看| 亚洲一区二区视频在线观看| 日照市| 精品精品久久宅男的天堂| 不卡乱辈伦在线看中文字幕| 国产一区二区亚洲精品| 国产成人免费ā片在线观看| 亚洲香蕉网久久综合影视| 麻豆天美国产一区在线播放|