SpringBootの例外ハンドリング


SpringBootの例外ハンドリング

概要

SpringBootにおいては、SpringMVCの機能を用いた例外ハンドリングやSpringBootのAutoConfigurationと組み込みサーバーを利用した例外ハンドリングなど複数の方法で例外を取り扱うことができる。
公式リファレンスで述べられているが、ハンドリングが可能な範囲や仕組みが若干わかりにくいので主要な方法をまとめる。

例外ハンドリングの方法

一覧

機能名 レイヤ
HandlerExceptionResolver SpringMVC
ErrorPage SpringBoot
ErrorController SpringBoot

HandlerExcepitonResolver

HandlerExceptionResolverはSpringMVCの機能を利用した例外ハンドリングの方法である。
SpringMVCの機能を利用しているため、FilterやViewで例外が生じた場合はハンドリングできない。

ハンドリングの概略図を下記に示す。

HandlerExceptionResolverは下記に示す複数の実装クラスがデフォルトで用意されている。
なお、下記の表において有効/無効はSpringBootのデフォルト設定で有効か無効かを示し、上に来るExceptionResolverが優先される。

クラス名 有効/無効 機能
ExceptionHandlerExceptionResolver 有効 @ExceptionHandlerが付与されたメソッドにより例外ハンドリングを行う
ResponseStatusExceptionResolver 有効 @ResponseStatusが付与されている例外クラスが発生した際にハンドリングを行う
DefaultHandlerExceptionResolver 有効 SpringMVCで定義されている例外クラスのハンドリングを行う
SimpleMappingExceptionResolver 無効 例外クラスとViewを直接マッピングする

下記に一番オーソドックスなExceptionHandlerExceptionResolverによる例外ハンドリングの方法を示す。

ExceptionHandlerExceptionResolverによるハンドリング

例外発生時に、発生した例外クラスのメタ情報が付与された@ExceptionHandlerアノテーションを持つメソッドを走査し、処理が移譲される。

@ExceptionHandlerを付与したメソッドは下記に示すように@Controllerもしくは@ControllerAdviceを付与したクラス内に定義できる。

ThrowExceptionController.java
@Controller
@RequestMapping("web")
public class ThrowExceptionController {

    @GetMapping("original")
    public void throwOriginalException() {
        throw new OriginalWebException("thrown in ThrowExceptionController");

    }

    @ExceptionHandler(OriginalWebException.class)
    public String handleOriginalWebException(OriginalWebException exception) {
        return "OriginalWebException.html";
    }

}
TransverseExceptionHandler.java
@ControllerAdvice
public class ThrowExceptionController {

    @ExceptionHandler(OriginalWebException.class)
    public String handleOriginalWebException(OriginalWebException exception) {
        return "OriginalWebException.html";
    }

}

@Controllerの場合、例外ハンドリングが可能なのは同一Controllerで発生した例外だけだが、@ControllerAdviceの場合は全てのControllerを横断的にハンドリングできる。

また、@Controller@ControllerAdviceどちらでもハンドリング可能な場合は@Controllerに付与された方が優先される。

ErrorPage

SpringBootにおけるErrorPageは従来のSpringFWのWeb.xmlで定義していたErrorPage要素とほぼ等しい。

ErrorPageはステータスコードか例外クラスとパスをマッピングし、ハンドリングを行えるようにする。
概略図を下記に示す。

ErrorPageの登録の仕方は下記に示すようにErrorPageRegistrarの実装クラスを作成することで行える。

AddErrorPage.java

@Configuration
public class AddErrorPage implements ErrorPageRegistrar {

    @Override
    public void registerErrorPages(ErrorPageRegistry registry) {
        registry.addErrorPages(new ErrorPage(exception, path));

        // new ErrorPage(HttpStatusCode, path)でも可能
    }
}

ErrorController

ErrorControllerはSpringBootによって提供される例外ハンドリングの手法であり、SpringBootの例外ハンドリングの中で最も一般的にとられる手法である。
概略図を下記に示す。

SpringBootのアプリケーションで生じる例外がハンドリングされなかった場合、上述のErrorPage機能によって全て/errorのパスへディスパッチされることになっている。
/errorはデフォルトではBasicErrorControllerクラスがマッピングされており、そこでハンドリングが行われる。

BasicErrorControllerでは、ハンドリングはリクエストヘッダーによってHTMLかJSONを返却する。
HTMLの場合はWhiteLabelErrorPageが返却され、返却される内容はErrorAttributesによって規定されている。
JSONの場合はErrorAttributesが返却される。

ErrorControllerによるハンドリング方法をカスタマイズする場合はErrorControllerの実装クラスを作成する。
また、返却内容自体をカスタマイズする場合はErrorAttributesクラスを実装する。

まとめ

SpringBootアプリケーションにおける例外ハンドリングは、基本的にはErrorControllerを用い、より細かいハンドリングを行いたい場合はHandlerExceptionResolverを用いると良い。