Spring Bootでリクエストをコントローラにマッピングする処理を解析してみました。
思いの外シンプルな仕組みでちょっと驚いています。
また、リクエストに対するマッピングする処理を、新しく作成できることも分かりました。
順を追って説明します。
HandlerMappingインターフェイス
リクエストをコントローラ等にマッピングには、 org.springframework.web.servlet.HandlerMapping
インターフェイスを実装したクラスのインスタンスをDIコンテナにに登録する必要があります。
複数のインスタンスを登録することができます。
public interface HandlerMapping {
@Nullable
HandlerExecutionChain getHandler(HttpServletRequesxt request) throws Exception;
}
HandlerMapping
インターフェイスを実装したクラスの getHandler
メソッドは、以下のように動作します。
- 該当のクラスでそのリクエストを処理できる場合
HandlerExecutionChain
のインスタンスを返却 - リクエストを処理できない場合
null
を返却
null
を返却した場合、次の HandlerMapping
インスタンスに処理が引き継がれます。
Spring Bootでは、 HanlderMapping
を実装した以下の5つのクラスのインスタンスがDIコンテナにあらかじめ登録されています。
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
org.springframework.web.servlet.function.support.RouterFunctionMapping
org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
org.springframework.boot.autoconfigure.web.servlet.WelcomePageHandlerMapping
Orderedインターフェイス
HandlerMapping
を実装した既存の5つのクラスには、 Ordered
インターフェイスも実装されています。
public interface Ordererd {
int getOrder();
}
既存の複数の HandlerMapping
インスタンスは getOrder
の戻り値の順でソートされ、リクエストに対して順番に処理する仕組みとなっています。
ここからは HandlerMapping
インターフェイスを実装した既存のクラスについて説明します。
RequestMappingHandlerMappingクラス
コントローラとリクエストをマッピングするクラスです。
@Controller
アノテーションが付与されたクラスの @RequestMapping
アノテーションが付与されたメソッドを元に、事前にマッピング情報を生成しています。
リクエストのたびに、パスやHTTPメソッドを元に、コントローラのメソッドをマッピングした情報を返却するようになっています。
BeanNameUrlHandlerMappingクラス
@Bean
アノテーションの name
属性をパスとして、Beanとリクエストをマッピングするクラスです。
@Bean
アノテーションを付与するメソッドの戻り値の型は、 Controller
インターフェイスとするようです。
RouterFunctionMappingクラス
RouterFunction
インターフェイスによるルーティングとリクエストをマッピングするクラスです。
SimpleUrlHandlerMappingクラス
src/main/resources/static
ディレクトリ配下のリソースとリクエストをマッピングするクラスです。
このクラスではパスとのマッピングパターンに /**
を使用しているため、すべてのリクエストがマッチします。
そのため gerOrder
でこのクラスより大きな値を返すクラスは、マッピング処理で呼び出されないことになります。
WelcomePageHandlerMappingクラス
src/main/resources/templates/index.html
をサイトトップにマッピングするクラスです。
最近のSpring Bootでは、 SimpleUrlHandlerMapping
クラスより getOrder
が返す値が大きくなっているため、使用されません。
なお、 HanlderMapping
クラスを実装したクラスをDIコンテナに登録するだけでは、リクエストに関する処理を完成できるわけではありません。
別途アダプタが必要になります。
こちらについては次回の記事で説明します。