目次
1. はじめに
2. グローバル例外処理の方法 1 (@ControllerAdvice および @ExceptionHandler)
3.全局异常并处理的方法二 (AOP)
ホームページ Java &#&チュートリアル 例外をキャッチするために SpringBoot グローバル例外ハンドラーを構成する方法

例外をキャッチするために SpringBoot グローバル例外ハンドラーを構成する方法

May 14, 2023 pm 09:52 PM
springboot

1. はじめに

どんなシステムでも、すべての場所で例外を愚かにキャッチして処理するわけではなく、システム全体の例外を 1 か所で処理し、グローバル例外は Spring Boot で処理するのが一般的です。非常にシンプル;

フロントエンドとバックエンドの分離、バックエンド API、一般的に例外処理の場合、やるべきことは 2 つだけです:

1. ログと対応する通知を記録する処理、これは内部です

2。結果を API 呼び出し元に返すことです、これは外部です

API 呼び出し元にとって、彼のみ必要なのは戻り結果 (エラー コードとプロンプト情報を含む) であり、残りのことは気にしません。

バックエンドの場合は、ログを記録し、対応するメッセージを他のキューに通知またはパブリッシュするだけで済みます。関連事項の処理;

つまり: 多くのカスタム例外クラスをカプセル化している人をたくさん見てきました。実際、これはまったく必要ありません。すべての例外を処理するには 1 つの例外ハンドラーだけが必要で、その後、エラー識別コードとプロンプト メッセージ。列挙は API 呼び出し元に戻るために使用されます。その後、バックエンド処理は 1 つの例外処理メソッドで直接処理できます。N 個の複数のカスタム例外をカプセル化する必要はありませんが、意味がありません。

例外のイデオロギー的理解

すべての異常はシステムの異常な兆候であり、欠陥であり、バグであることを認識する必要があります。ただし、一部の例外は積極的にスローされます;

私たちがしなければならないのは、システムを改善するために完璧な例外処理に依存するのではなく、システムの可用性を可能な限り改善し、例外の発生を最大限に回避することです。

例外処理は例外が必然的に発生した場合に取られる緊急措置。主な目的は、外部への親しみやすさを高め、内部に修復の手がかりを提供することです。

完璧な例外処理がシステムの中核であるとは考えないでください。例外処理が完璧であることを期待しないでください。また、例外処理によってシステムの欠陥が解消されることも期待しないでください。

システムに例外が多すぎる場合、やるべきことは例外を改善することではありません。処理メカニズム、ただしシステム アーキテクチャを反映する: 設計が合理的かどうか、システム ロジック設計が合理的かどうか;

2. グローバル例外処理の方法 1 (@ControllerAdvice および @ExceptionHandler)

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

開発中、次のシナリオが考えられます: 特定のインターフェイスにいくつかのビジネス例外があります。たとえば、ユーザーが入力したパラメータが検証されない、ユーザー名とパスワードが存在しないなどです。これらのビジネス例外がトリガーされた場合、これらのカスタム ビジネス例外をスローして処理する必要があります。一般に、これらの例外情報のステータス コードと例外の説明をわかりやすい方法で呼び出し元に返す必要があり、呼び出し元はステータス コードとその他の情報を使用して例外の具体的な状況を判断します。

以前は、コントローラー層で try/catch を通じてこれを処理する必要があったかもしれません。まずカスタム例外をキャッチし、次に他の例外をキャッチします。さまざまな例外については、キャッチ中に返されるオブジェクトをカプセル化する必要があります。ただし、これの欠点は、コードが冗長になることです。各インターフェイスには try/catch 処理が必要で、調整が必要になるとすべてのインターフェイスを変更する必要があります。これは、次のコード セクションで示すように、コードのメンテナンスに非常に悪影響を及ぼします。

@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;
}
ログイン後にコピー

それでは、これらの例外メッセージを簡単に処理するにはどうすればよいでしょうか?答えは「はい」です。 Spring 3.2 では、@ControllerAdvice アノテーションが追加されました。これは、@ExceptionHandler、@InitBinder、および @ModelAttribute の定義に使用でき、すべての @RequestMapping に適用されます。簡単に言うと、 @ControllerAdvice アノテーションを使用してグローバル例外処理クラスを構成すると、コントローラー層で例外を均一に処理できると同時に、コントローラー内で try/catch を記述する必要がなくなり、コードがクリーンになります。メンテナンスも簡単です。

使用方法

カスタム例外の定義

カスタム例外に関する関連知識ポイントの詳細については説明しません。分からない場合は、自分で調べてください。単純なカスタム ビジネス例外クラスをここに貼り付けます。

/**
 * 自定义业务异常类
 *
 * @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;
    }
}
ログイン後にコピー

注: @Data は Lombok プラグインです。 set/getメソッドを自動生成します。具体的な利用方法についてはここでは紹介しません。

@ControllerAdvice @ExceptionHand` グローバル例外処理クラスを設定します

/**
 * 全局异常处理器
 *
 * @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

このクラスをグローバル例外として定義します取り扱い種類。

#@ExceptionHandler

このメソッドを例外処理メソッドとして定義します。 value の値は、処理する必要がある例外クラスのクラス ファイルです。この例では、メソッドは 2 つのパラメーターで渡されます。 1 つは対応する Exception 例外クラスで、もう 1 つは HttpServletRequest クラスです。もちろん、これら 2 つのパラメータに加えて、他のいくつかのパラメータもサポートされます。

このようにして、さまざまな例外を均一に処理できます。通常、コントローラー内での try/catch の使用を避けるために、GlobalExceptionHandler 内で例外を一律に処理することもできます。このようにして、@ExceptionHandler で構成されていない他の例外は均一に処理されます。

例外が発生した場合は例外をスローするだけです

ビジネスでは、ビジネス例外が発生した場合は、 throw を使用して対応するビジネス例外をスローするだけです。たとえば、

throw new BusinessException("3000", "账户密码错误");
ログイン後にコピー

は、Controller に記述されます。

Controller 中,不需要再写 try/catch,除非特殊用途。

@RequestMapping(value = "/test")
public ResponseEntity test() {
    ResponseEntity re = new ResponseEntity();
    // 业务处理
    // ...
    return re;
}
ログイン後にコピー

结果展示

异常抛出后,返回如下结果。

{
    "code": "3000",
    "msg": "账户密码错误",
    "data": null
}
ログイン後にコピー

注意 不一定必须在 controller 层本身抛出异常才能被 GlobalExceptionHandler 处理,只要异常最后是从 contoller 层抛出去的就可以被全局异常处理器处理。异步方法中的异常不会被全局异常处理。抛出的异常如果被代码内的 try/catch 捕获了,就不会被 GlobalExceptionHandler 处理了。总结

本文介绍了在 SpringBoot 中,通过配置全局异常处理器统一处理 Controller 层引发的异常。

优点

减少代码冗余,代码便于维护

缺点

只能处理 controller 层抛出的异常,对例如 Interceptor(拦截器)层的异常、定时任务中的异常、异步方法中的异常,不会进行处理。

3.全局异常并处理的方法二 (AOP)

虽然@ControllerAdvice注解通常和@ExceptionHandler注解用于全局异常的处理。

但是这种方式有个缺点就是,只是对控制层进行了异常拦截,比如像工具类中或者其他类中的异常,并不会拦截。

由于业务执行时不能保证程序不出错,所以写代码必须添加try-catch,但是如果频繁的添加try-catch则必然导致代码结构混乱.所以需要进行优化.

原则:如果出现了问题一般将检查异常,转化为运行时异常.

核心原理: 代理动态思想------->AOP操作

采用自定义AOP的方式可以实现拦截。

有几个关键点

  1. 定义切入点为最大项目包

  2. 采用AOP的@AfterThrowing注解获取到全局异常捕获一个例子package com.example.promethuesdemo.exception; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; /** * @author chenzhen * Created by chenzhen on 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 想要执行的操作
        }
 
    }
ログイン後にコピー

aop中相关概念

Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。* Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它

joint point。* Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。* Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。* Target(目标对象):织入 Advice 的目标对象.。 Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程

Advice(增强)的类型

before advice, 在 join point 前被执行的 advice. 虽然 before advice 是在 join point 前被执行, 但是它并不能够阻止 join point 的执行, 除非发生了异常(即我们在 before advice 代码中,不能人为地决定是否继续执行 join point 中的代码)* after return advice, 在一个 join point 正常返回后执行的 advice* after throwing advice, 当一个 join point 抛出异常后执行的 advice* after(final) advice, 无论一个 join point 是正常退出还是发生了异常, 都会被执行的 advice.* around advice, 在 join point 前和 joint point 退出后都执行的 advice. 这个是最常用的 advice.* introduction,introduction可以为原有的对象增加新的属性和方法。

注意

spring AOP中的AfterThrowing增强处理可以对目标方法的异常进行处理,但这种处理与直接使用catch捕捉处理异常的方式不同,catch捕捉意味着能完全处理异常,即只要catch块本身不抛出新的异常,则被处理的异常不会往上级调用者进一步传播下去;但是如果使用了AfterThrowing增强处理用于对异常进行处理,处理后异常仍然会往上一级调用者传播,如果是在main中调用的目标方法,那么异常会直接传到JVM,如下截图所示:

例外をキャッチするために SpringBoot グローバル例外ハンドラーを構成する方法

SpringBoot 之配置全局异常处理器捕获异常

また、ターゲット メソッドで例外が発生し、catch によってキャッチおよび処理され、catch が新しい例外をスローしない場合、ターゲット メソッドの AfterThrowing 拡張処理は実行されないことに注意してください。

以上が例外をキャッチするために SpringBoot グローバル例外ハンドラーを構成する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Springboot が Jasypt を統合して構成ファイルの暗号化を実装する方法 Springboot が Jasypt を統合して構成ファイルの暗号化を実装する方法 Jun 01, 2023 am 08:55 AM

Jasypt の概要 Jasypt は、開発者が最小限の労力で基本的な暗号化機能を自分のプロジェクトに追加できる Java ライブラリであり、暗号化の仕組みを深く理解する必要はありません。一方向および双方向暗号化の高いセキュリティ。標準ベースの暗号化テクノロジー。パスワード、テキスト、数値、バイナリを暗号化します... Spring ベースのアプリケーション、オープン API への統合、JCE プロバイダーでの使用に適しています... 次の依存関係を追加します: com.github.ulisesbocchiojasypt-spring-boot-starter2. 1.1 Jasypt の特典はシステムのセキュリティを保護し、コードが漏洩した場合でもデータ ソースは保証されます。

SpringBoot が Redisson を統合して遅延キューを実装する方法 SpringBoot が Redisson を統合して遅延キューを実装する方法 May 30, 2023 pm 02:40 PM

使用シナリオ 1. 注文は正常に行われましたが、支払いが 30 分以内に行われませんでした。支払いがタイムアウトになり、注文が自動的にキャンセルされました 2. 注文に署名があり、署名後 7 日間評価が行われませんでした。注文がタイムアウトして評価されない場合、システムはデフォルトでプラスの評価を設定します 3. 注文は正常に行われます。販売者が 5 分間注文を受け取らない場合、注文はキャンセルされます。 4. 配送がタイムアウトします。 SMS リマインダーをプッシュします... 遅延が長く、リアルタイム パフォーマンスが低いシナリオでは、タスク スケジュールを使用して定期的なポーリング処理を実行できます。例: xxl-job 今日は選択します

Redis を使用して SpringBoot に分散ロックを実装する方法 Redis を使用して SpringBoot に分散ロックを実装する方法 Jun 03, 2023 am 08:16 AM

1. Redis は分散ロックの原則を実装しており、分散ロックが必要な理由 分散ロックについて話す前に、分散ロックが必要な理由を説明する必要があります。分散ロックの反対はスタンドアロン ロックです。マルチスレッド プログラムを作成するとき、共有変数を同時に操作することによって引き起こされるデータの問題を回避します。通常、ロックを使用して共有変数を相互に除外し、データの正確性を確保します。共有変数の使用範囲は同じプロセス内です。共有リソースを同時に操作する必要があるプロセスが複数ある場合、どうすれば相互排他的になるのでしょうか?今日のビジネス アプリケーションは通常マイクロサービス アーキテクチャであり、これは 1 つのアプリケーションが複数のプロセスをデプロイすることも意味します。複数のプロセスが MySQL の同じレコード行を変更する必要がある場合、順序の乱れた操作によって引き起こされるダーティ データを避けるために、分散が必要です。今回導入するスタイルはロックされています。ポイントを獲得したい

Springbootがjarパッケージにファイルを読み込んだ後にファイルにアクセスできない問題を解決する方法 Springbootがjarパッケージにファイルを読み込んだ後にファイルにアクセスできない問題を解決する方法 Jun 03, 2023 pm 04:38 PM

Springboot はファイルを読み取りますが、jar パッケージにパッケージ化した後、最新の開発にアクセスできません。jar パッケージにパッケージ化した後、Springboot がファイルを読み取れない状況があります。その理由は、パッケージ化後、ファイルの仮想パスが変更されるためです。は無効であり、ストリーム経由でのみアクセスできます。読み取ります。ファイルはリソースの下にあります publicvoidtest(){Listnames=newArrayList();InputStreamReaderread=null;try{ClassPathResourceresource=newClassPathResource("name.txt");Input

SQL ステートメントを使用せずに Springboot+Mybatis-plus を実装して複数のテーブルを追加する方法 SQL ステートメントを使用せずに Springboot+Mybatis-plus を実装して複数のテーブルを追加する方法 Jun 02, 2023 am 11:07 AM

Springboot+Mybatis-plus が SQL ステートメントを使用して複数テーブルの追加操作を実行しない場合、私が遭遇した問題は、テスト環境で思考をシミュレートすることによって分解されます: パラメーターを含む BrandDTO オブジェクトを作成し、パラメーターをバックグラウンドに渡すことをシミュレートします。 Mybatis-plus で複数テーブルの操作を実行するのは非常に難しいことを理解してください。Mybatis-plus-join などのツールを使用しない場合は、対応する Mapper.xml ファイルを設定し、臭くて長い ResultMap を設定するだけです。対応する SQL ステートメントを記述します。この方法は面倒に見えますが、柔軟性が高く、次のことが可能です。

SpringBootとSpringMVCの比較と差異分析 SpringBootとSpringMVCの比較と差異分析 Dec 29, 2023 am 11:02 AM

SpringBoot と SpringMVC はどちらも Java 開発で一般的に使用されるフレームワークですが、それらの間には明らかな違いがいくつかあります。この記事では、これら 2 つのフレームワークの機能と使用法を調べ、その違いを比較します。まず、SpringBoot について学びましょう。 SpringBoot は、Spring フレームワークに基づいたアプリケーションの作成と展開を簡素化するために、Pivo​​tal チームによって開発されました。スタンドアロンの実行可能ファイルを構築するための高速かつ軽量な方法を提供します。

SpringBoot が Redis をカスタマイズしてキャッシュのシリアル化を実装する方法 SpringBoot が Redis をカスタマイズしてキャッシュのシリアル化を実装する方法 Jun 03, 2023 am 11:32 AM

1. RedisAPI のデフォルトのシリアル化メカニズムである RedisTemplate1.1 をカスタマイズします。API ベースの Redis キャッシュ実装では、データ キャッシュ操作に RedisTemplate テンプレートを使用します。ここで、RedisTemplate クラスを開いて、クラスのソース コード情報を表示します。publicclassRedisTemplateextendsRedisAccessorimplementsRedisOperations、BeanClassLoaderAware{//キーを宣言、値の各種シリアル化メソッド、初期値は空 @NullableprivateRedisSe

SpringBoot+Dubbo+Nacos開発実践チュートリアル SpringBoot+Dubbo+Nacos開発実践チュートリアル Aug 15, 2023 pm 04:49 PM

この記事では、dubbo+nacos+Spring Boot の実際の開発について詳しく説明する例を書きます。この記事では理論的な知識はあまり取り上げませんが、dubbo を nacos と統合して開発環境を迅速に構築する方法を説明する最も簡単な例を書きます。

See all articles