1. ホーム
  2. spring-mvc

[解決済み] 複数の @ControllerAdvice @ExceptionHandler の優先順位を設定する。

2022-12-23 22:49:56

質問

でアノテーションされた複数のクラスがあります。 @ControllerAdvice でアノテーションされた複数のクラスがあり、それぞれのクラスには @ExceptionHandler のメソッドを使用します。

一つはハンドル Exception を扱うもので、より具体的なハンドラが見つからなければ、これを使うべきという意図です。

悲しいことに、Spring MVCは常に最も一般的なケース( Exception ) を使うようです。 IOException など) よりも、より具体的なものです。

これはSpring MVCがどのように振る舞うかを期待するものでしょうか?私はJerseyのパターンをエミュレートしようとしていて、それぞれの ExceptionMapper (等価なコンポーネント)を評価して、それが扱う宣言された型が投げられた例外からどれだけ離れているかを判断し、常に最も近い祖先を使用します。

どのように解決するのか?

Spring MVCの動作はこのようなものでしょうか?

Spring 4.3.7では、Spring MVCの動作は次のようになっています。 HandlerExceptionResolver インスタンスを使用して、ハンドラメソッドによってスローされる例外を処理します。

デフォルトでは、web MVC の構成は単一の HandlerExceptionResolver ビーンを登録します。 HandlerExceptionResolverComposite であり、これは

のリストに委ねる。 HandlerExceptionResolvers .

それらの他のリゾルバは

  1. ExceptionHandlerExceptionResolver
  2. ResponseStatusExceptionResolver
  3. DefaultHandlerExceptionResolver

の順で登録されています。この質問の目的では、私たちが気にするのは ExceptionHandlerExceptionResolver .

An AbstractHandlerMethodExceptionResolver で例外を解決する を通して @ExceptionHandler メソッドによって例外を解決します。

コンテキストの初期化時に、Springは ControllerAdviceBean を生成します。 @ControllerAdvice アノテーションされたクラスが検出されます。その ExceptionHandlerExceptionResolver は、これらをコンテキストから取得し AnnotationAwareOrderComparator という

の拡張です。 OrderComparator の拡張で、Springの Ordered インターフェースだけでなく @Order@Priority アノテーションがあり アノテーションの値は、Orderedインスタンスによって提供され、静的に定義されたアノテーションの値をオーバーライドします。 アノテーションの値があれば、それを上書きします。

次に ExceptionHandlerMethodResolver を登録します。 ControllerAdviceBean インスタンス(マッピング可能な @ExceptionHandler メソッドを処理するための例外の種類に対応させます)。これらは最終的に同じ順序で LinkedHashMap に同じ順序で追加されます (これは反復の順序を維持します)。

例外が発生した場合は ExceptionHandlerExceptionResolver はこれらの ExceptionHandlerMethodResolver を順に処理し、例外を処理できる最初のものを使用します。

つまり、ここでのポイントは @ControllerAdvice@ExceptionHandler に対して Exception の前に登録される @ControllerAdvice クラスで @ExceptionHandler のように、より具体的な例外を表すために IOException のように、より具体的な例外が発生した場合は、 その最初のものが呼ばれることになります。先に述べたように、この登録順序は @ControllerAdvice アノテーションされたクラスが Ordered でアノテーションを付けるか @Order または @Priority というように、適切な値を与えてください。