SpringBoots Konfiguration globaler Ausnahmebehandlungsroutinen zum Abfangen von Ausnahmen

SpringBoots Konfiguration globaler Ausnahmebehandlungsroutinen zum Abfangen von Ausnahmen

1. Einleitung

In jedem System werden Ausnahmen nicht an jedem Ort albern abgefangen und behandelt. Im gesamten System werden Ausnahmen im Allgemeinen an einem Ort behandelt. Die globale Ausnahmebehandlung für Spring Boot ist sehr einfach.

Lassen Sie mich vor der Einführung ein wenig vom Thema abweichen. Unser aktuelles Entwicklungssystem ist vollständig von vorne und hinten getrennt. Das Backend bietet nur die RESTfull-API. Es ist verboten, eine Schnittstelle einzubeziehen. Thymeleaf- und JSP-Backend-Vorlagen sind absolut verboten Werfen Sie den Mülleimer, verschwenden Sie keine große Jugend für die Forschung, das heißt Verderbtheit. Das Front-End ist für den häufig verwendeten Vue mit Schnittstellenbezug verantwortlich. Wenn das Unternehmen das Front-End und das Back-End nicht getrennt hat. und schreibe zusammen in thymeleaf, dann solltest du planen, den Job frühzeitig zu wechseln., Sie können dich nicht unterstützen, geschweige denn deine Familie unterstützen;

Front-End- und Back-End-Trennung, Back-End-API, haben im Allgemeinen zwei Dinge für die Ausnahmebehandlung zu tun:

1. Es zeichnet das Protokoll und die entsprechende interne Benachrichtigungsverarbeitung auf.

2. Das Rückgabeergebnis wird an den externen API-Aufrufer übergeben.

Für den API-Aufrufer benötigt er nur ein Rückgabeergebnis (einschließlich Fehlercode und Eingabeaufforderungsinformationen), und die anderen sind ihm egal

Für das Backend muss er nur Protokolle aufzeichnen, entsprechende Nachrichten benachrichtigen oder in anderen Warteschlangen veröffentlichen, um verwandte Angelegenheiten zu verarbeiten.

Also: Ich habe gesehen, dass viele Leute viele benutzerdefinierte Ausnahmeklassen gekapselt haben. Tatsächlich ist dies völlig unnötig. Es wird nur ein Ausnahmebehandler benötigt, um alle Ausnahmen zu behandeln, und dann wird eine Aufzählung von Fehleridentifikationscodes und Aufforderungsnachrichten für Return to gekapselt Der API-Aufrufer kann dann die Back-End-Verarbeitung direkt in einer Ausnahmebehandlungsmethode verarbeiten. Es ist nicht erforderlich, N mehrere benutzerdefinierte Ausnahmen zu kapseln, was keine Bedeutung hat.

Anomalie denken

Wir sollten uns darüber im Klaren sein, dass alle Ausnahmen ungewöhnliche Verhaltensweisen für das System sind, Fehler darstellen und alle zu BUG gehören, obwohl einige Ausnahmen von uns aus eigener Initiative ausgelöst werden.

Was wir tun müssen, ist, die Verfügbarkeit des Systems zu maximieren und Ausnahmen so weit wie möglich zu vermeiden, anstatt auf eine perfekte Ausnahmebehandlung zu achten, um das System zu verbessern.

Die Ausnahmebehandlung ist eine Notfallmaßnahme, die ergriffen wird, wenn eine Anomalie nicht vermieden werden kann. Der Hauptzweck besteht darin, die Freundlichkeit nach außen zu erhöhen und intern Abhilfe zu schaffen.

Denken Sie nicht, dass die perfekte Ausnahmebehandlung der Kern des Systems ist. Erwarten Sie keine perfekte Ausnahmebehandlung. Erwarten Sie nicht, dass die Ausnahmebehandlung den Grund für Systemfehler beseitigt.

Wenn es zu viele Systemausnahmen gibt, müssen Sie nicht den Ausnahmebehandlungsmechanismus verbessern, sondern darüber nachdenken, ob das Systemarchitekturdesign angemessen und das Systemlogikdesign angemessen ist.

2. Die erste Methode zur globalen Ausnahmebehandlung (@ControllerAdvice und @ExceptionHandler)

================================================

Während der Entwicklung haben wir das folgende Szenario: In einer bestimmten Schnittstelle gibt es einige geschäftliche Ausnahmen. Beispielsweise schlägt die Überprüfung der vom Benutzer eingegebenen Parameter fehl und der Benutzername und das Kennwort sind nicht vorhanden. Wenn diese Geschäftsausnahmen ausgelöst werden, müssen wir diese benutzerdefinierten Geschäftsausnahmen auslösen und behandeln. Im Allgemeinen müssen wir den Statuscode und die Ausnahmebeschreibung der Ausnahmeinformationen an den anruferfreundlichen Benutzer zurückgeben, und der Anrufer verwendet den Statuscode und andere Informationen, um die spezifische Situation der Ausnahme zu bestimmen.

In der Vergangenheit mussten wir möglicherweise try / catch auf der Controller-Ebene ausführen. Fangen Sie zuerst die benutzerdefinierte Ausnahme und dann andere Ausnahmen ab. Für verschiedene Ausnahmen müssen wir das Objekt einkapseln, das beim Abfangen zurückgegeben werden soll. Dies hat jedoch den Nachteil, dass der Code ausführlich wird. Jede Schnittstelle muss eine Try / Catch-Verarbeitung sein, und sobald sie angepasst werden muss, müssen alle Schnittstellen erneut geändert werden, was für die Codepflege sehr ungünstig ist, wie im folgenden Code gezeigt

@RequestMapping (value = "/test")
public ResponseEntity test() {
    ResponseEntity re = new ResponseEntity();
    // 业务处理
    // ...
    try {
        // 业务
    } catch (BusinessException e) {
        logger.info("业务发生异常,code:" + e.getCode() + "msg:" + e.getMsg());
        re.setCode(e.getCode());
        re.setMsg(e.getMsg());
        return re;
    } catch (Exception e) {
        logger.error("服务错误:", e);
        re.setCode("xxxxx");
        re.setMsg("服务错误");
        return re;
    }
    return re;
}

Gibt es eine Möglichkeit, mit diesen abnormalen Informationen einfach umzugehen? Die Antwort ist ja. In Spring 3.2 wird die Annotation @ControllerAdvice hinzugefügt, mit der @ExceptionHandler, @InitBinder, @ModelAttribute definiert und auf alle @RequestMapping angewendet werden können. Einfach ausgedrückt, können Sie eine globale Ausnahmebehandlungsklasse über die Annotation @ControllerAdvice konfigurieren, um Ausnahmen in der Controller-Schicht einheitlich zu behandeln. Gleichzeitig müssen Sie try / catch nicht in den Controller schreiben, wodurch der Code sauber und einfach wird aufrecht erhalten.

Anleitung

Definieren Sie eine benutzerdefinierte Ausnahme

Die relevanten Wissenspunkte zu benutzerdefinierten Ausnahmen werden hier nicht im Detail erläutert. Wenn Sie es nicht wissen, suchen Sie es bitte selbst. Fügen Sie hier eine einfache benutzerdefinierte Business-Ausnahmeklasse ein.

/**
 * 自定义业务异常类
 *
 * @author Yuzhe Ma
 * @date 2018/11/28
 */
@Data
public class BusinessException extends RuntimeException {
    private String code;
    private String msg;

    public BusinessException(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}

Hinweis: @Data ist das Lombok-Plugin. Set / Get-Methoden automatisch generieren. Die spezifische Verwendungsmethode wird hier nicht vorgestellt.

@ControllerAdvice + @ ExceptionHand` Konfigurieren Sie die globale Ausnahmebehandlungsklasse

/**
 * 全局异常处理器
 *
 * @author Yuzhe Ma
 * @date 2018/11/12
 */
@ControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 处理 Exception 异常
     *
     * @param httpServletRequest httpServletRequest
     * @param e                  异常
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public ResponseEntity exceptionHandler(HttpServletRequest httpServletRequest, Exception e) {
        logger.error("服务错误:", e);
        return new ResponseEntity("xxx", "服务出错");
    }

    /**
     * 处理 BusinessException 异常
     *
     * @param httpServletRequest httpServletRequest
     * @param e                  异常
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = BusinessException.class)
    public ResponseEntity businessExceptionHandler(HttpServletRequest httpServletRequest, BusinessException e) {
        logger.info("业务异常。code:" + e.getCode() + "msg:" + e.getMsg());
        return new ResponseEntity(e.getCode(), e.getMsg());
    }
}

@ControllerAdvice

Definieren Sie diese Klasse als globale Ausnahmebehandlungsklasse.

@ExceptionHandler

Definieren Sie diese Methode als Ausnahmebehandlungsmethode. Der Wert von value ist die Klassendatei der zu behandelnden Ausnahmeklasse. Im Beispiel übergibt die Methode zwei Parameter. Eine ist die entsprechende Exception-Ausnahmeklasse und die andere ist die HttpServletRequest-Klasse. Zusätzlich zu diesen beiden Parametern werden natürlich auch einige andere Parameter unterstützt. Weitere Informationen finden Sie im Dokument https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ExceptionHandler.html

Auf diese Weise können verschiedene Ausnahmen einheitlich behandelt werden. Normalerweise können Sie in GlobalExceptionHandler auch eine einheitliche Behandlung der Ausnahme durchführen, damit der Controller kein Try / Catch mehr verwendet. Auf diese Weise werden andere Ausnahmen, die nicht mit @ExceptionHandler konfiguriert sind, einheitlich behandelt.

Lösen Sie eine Ausnahme aus, wenn Sie auf eine Ausnahme stoßen

In Unternehmen, in denen Geschäftsausnahmen auftreten, lösen Sie die entsprechenden Geschäftsausnahmen direkt mit throw aus. Z.B

throw new BusinessException("3000", "账户密码错误");

Wie schreibe ich in Controller

In Controller muss try / catch nur für spezielle Zwecke geschrieben werden.

@RequestMapping(value = "/test")
public ResponseEntity test() {
    ResponseEntity re = new ResponseEntity();
    // 业务处理
    // ...
    return re;
}

Ergebnisanzeige

Nachdem die Ausnahme ausgelöst wurde, wird das folgende Ergebnis zurückgegeben.

{
    "code": "3000",
    "msg": "账户密码错误",
    "data": null
}

Hinweis

  1. Es ist nicht erforderlich, eine Ausnahme auf der Controller-Ebene selbst auszulösen, die vom GlobalExceptionHandler verarbeitet werden soll. Solange die Ausnahme endgültig von der Controller-Ebene ausgelöst wird, kann sie vom globalen Exception-Handler verarbeitet werden.
  2. Ausnahmen in asynchronen Methoden werden nicht von globalen Ausnahmen behandelt.
  3. Wenn die ausgelöste Ausnahme vom try / catch im Code abgefangen wird, wird sie vom GlobalExceptionHandler nicht behandelt.

um zusammenzufassen

Dieser Artikel beschreibt die Behandlung von Ausnahmen, die von der Controller-Ebene ausgelöst werden, indem der globale Ausnahmebehandler in SpringBoot konfiguriert wird.

Vorteil

Reduzieren Sie die Code-Redundanz, der Code ist einfach zu warten

Nachteil

Es können nur Ausnahmen behandelt werden, die von der Controller-Schicht ausgelöst werden. Beispielsweise werden Ausnahmen in der Interceptor-Schicht (Interceptor), Ausnahmen in Timing-Tasks und Ausnahmen in asynchronen Methoden nicht verarbeitet.

Im obigen Abschnitt wird @ControllerAdvice + @ExceptionHand verwendet, um die Methode zum Abfangen und Behandeln globaler Ausnahmen auf der Controller-Ebene in SpringBoot zu implementieren.

3. Die zweite Methode zur globalen Ausnahmebehandlung (AOP)

Obwohl die Annotation @ControllerAdvice normalerweise mit der Annotation @ExceptionHandler für die globale Ausnahmebehandlung verwendet wird.

Diese Methode hat jedoch den Nachteil, dass sie nur Ausnahmen in der Steuerebene abfängt, z. B. Ausnahmen in der Werkzeugklasse oder anderen Klassen, und diese nicht abfängt.

Da nicht garantiert werden kann, dass das Programm während der Geschäftsausführung fehlerfrei ist, muss Try-Catch hinzugefügt werden, um Code zu schreiben. Wenn jedoch häufig Try-Catch hinzugefügt wird, führt die Codestruktur unweigerlich zu Verwirrung. Daher ist eine Optimierung erforderlich.

Prinzip: Wenn ein Problem auftritt, wird die Ausnahme überprüft und in eine Laufzeitausnahme konvertiert.

Kernprinzip: Dynamisches Denken der Agenten -------> AOP-Betrieb

Das Abfangen kann mithilfe von benutzerdefiniertem AOP erreicht werden.

Es gibt einige wichtige Punkte

  1. Definieren Sie den Einstiegspunkt als größtes Projektpaket
  2. Verwenden Sie die @ AfterThrowing-Annotation von AOP, um ein Beispiel für das globale Ausnahmeerfassungspaket com.example.promethuesdemo.exception abzurufen ; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; / ** * @author chenzhen * Erstellt von chenzhen am 2020/7/20.
*/
    @Aspect
    @Slf4j
    @Component
    public class GlobalExceptionAspect {
        @Pointcut("execution(* com.example..*.*(..))")
        public void pointcut(){

        }

        @AfterThrowing(pointcut = "pointcut()",throwing = "e")
        public void afterThrowing(JoinPoint joinPoint,Throwable e){
            log.error("全局捕获到异常了..............");
            //纪录错误信息
            log.error("系统错误:{}", e.getMessage());
            // todo 想要执行的操作
        }

    }

Verwandte Konzepte in aop

  • Aspekt (Aspekt): Die Aspektdeklaration ähnelt der Klassendeklaration in Java. Der Aspekt enthält einige Pointcuts und entsprechende Hinweise. * Joint Point (Joint Point): Gibt einen klar definierten Punkt im Programm an, der normalerweise Methodenaufrufe, den Zugriff auf Klassenmitglieder und die Ausführung von Ausnahmebehandlungsblöcken usw. umfasst. Er kann auch andere
    Joint Points verschachteln . * Pointcut (Pointcut): Stellt eine Reihe von Verbindungspunkten dar. Diese Verbindungspunkte werden entweder durch logische Beziehungen kombiniert oder durch Platzhalter, reguläre Ausdrücke usw. zentralisiert, die den Ort definieren, an dem die entsprechenden Hinweise erfolgen. * Hinweis (erweitert): Hinweis definiert die spezifischen Vorgänge, die an den in Pointcut definierten Programmpunkten ausgeführt werden sollen. Er unterscheidet, ob vor, nach oder anstelle von Code vor, nach und um. * Ziel (Zielobjekt): Das in Advice eingewebte Zielobjekt. Weben: Der Prozess des Verbindens von Aspect und anderen Objekten und des Erstellens eines empfohlenen Objekts

Beratungstyp (erweitert)

  • Vor der Beratung die Beratung, die vor dem Verknüpfungspunkt ausgeführt wird. Obwohl die Beratung vor dem Verknüpfungspunkt ausgeführt wird, kann sie die Ausführung des Verknüpfungspunkts nicht verhindern, es sei denn, es liegt eine Ausnahme vor (dh wir
    können den Code vor der Verknüpfung nicht künstlich ausführen. Entscheiden Sie, ob die Ausführung des Codes im Join-Punkt fortgesetzt werden soll. * * Nach der Rückgabe von Ratschlägen. Ratschläge, die nach einem Join-Punkt ausgeführt werden, werden normal zurückgegeben. Unabhängig davon, ob der Verbindungspunkt normal beendet wird oder eine Ausnahme auftritt, wird der Hinweis ausgeführt, der ausgeführt wird. * Um den Hinweis herum wird der Hinweis ausgeführt, der vor dem Verbindungspunkt und nach dem Verlassen des Verbindungspunkts ausgeführt wird. Dies ist der am häufigsten verwendete Hinweis . * Einführung, die Einführung kann das Original sein. Das Objekt fügt neue Eigenschaften und Methoden hinzu.

Hinweis

AfterThrowing Erweiterte Verarbeitung im Frühjahr AOP kann die Ausnahmen der Zielmethode verarbeiten. Diese Verarbeitung unterscheidet sich jedoch von der direkten Verwendung von catch zur Behandlung von Ausnahmen. Catch Catching bedeutet, dass Ausnahmen vollständig behandelt werden können, dh solange der catch-Block selbst löst keine neue Ausnahme aus, die verarbeitete Ausnahme wird nicht weiter an den übergeordneten Aufrufer weitergegeben. Wenn jedoch die erweiterte AfterThrowing-Verarbeitung zur Behandlung der Ausnahme verwendet wird, wird die Ausnahme nach der Verarbeitung weiterhin an den übergeordneten Aufrufer weitergegeben. Wenn es in der Hauptzielmethode aufgerufen wird, wird die Ausnahme direkt an die JVM übertragen, wie im folgenden Screenshot gezeigt:

SpringBoots Konfiguration globaler Ausnahmebehandlungsroutinen zum Abfangen von Ausnahmen

Darüber hinaus sollte beachtet werden, dass die AfterThrowing-Erweiterungsverarbeitung für die Zielmethode nicht ausgeführt wird, wenn eine Ausnahme in der Zielmethode auftritt und vom catch abgefangen wird und der catch keine neue Ausnahme auslöst.

Ich denke du magst

Origin blog.csdn.net/doubututou/article/details/112858562
Empfohlen
Rangfolge