古典的な質問へのインタビューSpringMVC実行プロセス(ソースコード解釈分析)

この記事はGitHubでホストされています。GitHubで確認できます。スターへのボスを歓迎します。
WeChatパブリックアカウント[コードアウトオファー]を検索してフォローすると、さまざまな学習資料受け取ることができます。

SpringMVC実行プロセス

SpringMVCの概要

Spring MVCはSpringFrameWorkのフォローアップ製品であり、Spring WebFlowに統合されています。Springフレームワークは、Webアプリケーションを構築するためのフル機能のMVCモジュールを提供します。Springのプラグ可能なMVCアーキテクチャを使用するため、Web開発にSpringを使用する場合は、SpringのSpring MVCフレームワークを使用するか、他のMVC開発フレームワークを統合するかを選択できます。

SpringMVC実行プロセスの概要

SpringMVCフレームワークは強力ですが、その実行プロセスはさらに素晴らしいものです。そこで今回は、簡単な例を使用して、SpringMVCの基礎となる実行プロセスについて詳しく説明します。

以下は、SpringMVCの実行プロセスの概略図です。概略図のこれらの部分と、基礎となるプロセスの分析におけるそれらの機能に焦点を当てます。


SpringMVC実行プロセスの概要図(覚えておいてください:この図はアイデアを整理するためのものであり、特に厳密ではありません。理解してください)
springMVC実行プロセス
SpringMVCの重要なコンポーネント(ビジュアルコンポーネント)

SpringMVCの基礎となる実行プロセスを分析することを選択する必要があるため、最初に、表面に表示されるMVCの重要なコンポーネントを分析する必要があります。このように、ビジュアルコンポーネントを分析した後、SpringMVCの基礎となる実行プロセスを分析するための入り口を見つけることができるため、その重要なコンポーネントを分析することがさらに重要になります。

SpringMVCの重要なコンポーネントが構成されている核心的前端控制器(web.xml)后端控制器(Controller)spring-mvc.xml配置文件

  • コアフロントコントローラー: MVCフレームワークとして、最初に解決することは、要求を受信する方法です。したがって、ほとんどのMVCフレームワークは、サーブレットまたはフィルターのいずれかで選択されるフロントエンドコントローラー(エントリポイントまたは開始ポイント)を設計します。フロントエンドコントローラーが主導権を握り、要求を受信します。SpringMVCでは、フロントコントローラーの選択はServlet(DispatcherServlet)であると判断されます。リクエストを受信した後、このフロントコントローラーはSpringMVCのコアスケジューリング管理も担当するため、フロントエンドとコアの両方になります。
  • バックエンドコントローラー:バックエンドコントローラーはコントローラーであり、以前に定義されたサーブレットと同等です。MVCフレームワークでは、バックエンドコントローラーも不可欠な重要なコンポーネントの1つです。ユーザーから要求された大量のデータを受信するため、パラメーターオブジェクト(またはJson)は、ページ(JSP)値を容易にするためにドメインに格納されるか、リダイレクト(リダイレクトまたは要求された転送)が必要なページにデータを戻します。ここで、バックエンドコントローラーの本質は通常のServletでもBaseServletでもないことに注意してください。これは単なる通常のクラスですが、以前はBaseServletのような多くのメソッドを持つことができます。これらのメソッドはSpringMVCで1つずつなります。ハンドラー(薬を変えずにスープを変える、本質は残る)。したがって、MVCモデルの実行プロセスでは、バックエンドコントローラがページジャンプとデータ送信を制御し、ここでも高い位置にあります。
  • spring-mvc.xml構成ファイル:この構成ファイルは、実行中にロードする必要のある多くのコンポーネントを構成します。たとえば、注釈スキャナー、注釈スキャンドライバー、試行パーサー、静的リソースプロセッサー、例外パーサー、インターセプター、アップロードなどです。パーサーなど、これらのコンポーネントを使用する場合は、これらのコンポーネントの関連する構成を構成ファイルに挿入する必要があります。構成が挿入された後、SpringMVCファクトリは、これらのコンポーネントを使用する目的を達成するために、実行プロセス中にこれらのコンポーネントをロードします。だからそれが人気がある理由です。
SpringMVC実行プロセスの分析

上記は核心的前端控制器,即web.xml実行プロセス分析への入り口がであるということを学びました。それで、フロントコントローラーで何が構成されているかを理解する資格があります。次のように:

フロントコントローラー
画像-20200719185840281

上の図からわかるように、フロントコントローラーに含まれているのは、SpringMVCファクトリーとSpringファクトリーの両方を同時に起動し、2つのファクトリーが同時に動作して要求を処理して応答できるようにすることです。SpringMVCの基礎となる実行プロセスを分析する必要があるため、SpringMVCファクトリのロードから開始する必要がありDispatcherServletます。次の図に示すように、最初にDispatcherServletに入り、ソースコードのすべてのメソッドを表示します。

DispatcherServletソースコードのすべてのメソッド
画像-20200719190557728
DispatcherServlet继承FrameworkServlet
画像-20200719190959184

上の図に示すように、DispatcherServletに入りました。これはサーブレットであるため、サービスメソッドである必要があります。これは、サービスメソッドがサーブレットのコアであるためです。そこで、IDEAメソッドリストを開いてサービスメソッドを検索しましたが、失敗しました。失敗しましたが、2つの重要な手がかりを見つけました。1つは、ServletにdoSerivceメソッドがあること、もう1つは、DispatcherServletがFrameworkServletを継承することです。サブクラスにはサービスメソッドがないため、親クラスにサービスメソッドが必要なので、FrameworkServletビューソースに入りました。次の図に示すようなコード:

FrameworkServletソースコード
画像-20200719193120903

親クラス(FrameworkServlet)でサービスメソッドを見つけることに興奮していますが、それでも早すぎると感じていますresolveリクエストを取得するメソッドとメソッド以外は、サービスメソッドprocessRequestについて何も知りません。それから私は赤い矢印がsuper.service(request, response);何を指しているのかを発見しました。これはどういう意味ですか?これは、親クラスが所有するサービスメソッドを継承していることを意味するので、スーパーピリオドの後にサービスメソッドをクリックしてソースコードを表示しました。このクラスがHttpServletであることがわかったのは驚きでした。明らかに、サービスメソッドを見つける方法は終わりました。その中には2つのメソッドがあります。1つはresolveリクエストを取得する方法であるメソッドです。それが何であるかわからない別の方法があるので、以下に示すように、クリックしてソースコードを表示しました。

processRequestメソッドのソースコード
画像-20200719193708541

processRequestメソッドのソースコードを見に行ったので、重要なメソッドを見つける必要があります。重要なメソッドとは何ですか?一般に、tryブロックでラップされたメソッドは重要なメソッドである必要があるためdoService(request, response);、次の図に示すように、メソッドを見つけてクリックし続け、doServiceメソッドのソースコードを確認しました。

doService(request、response);メソッドのソースコード
画像-20200719194003105

私は徐々に忍耐力を失っていました。本当に驚きました。doServiceメソッドに入った後、他のクラスにジャンプしませんでしたが、このクラスの空のdoService();メソッドにジャンプしました。残念ながら、見つけるのは本当に簡単ではありません〜私はため息をつきました。落ち着いて考えてみてください。親クラスには空のメソッドが実装されていないため、コアロジックコードはサブクラスに含まれている必要があります。これは多形ではありません!そのため、入口ロジックコードを見つけるのは難しいが、DispatcherServletのdoServiceメソッドを振り返ることは難しいという結論に達しました。現時点では、これは長い道のりになることを私は知っていました。そのため、原則を探求するという精神で、以下に示すように、見逃したDispatcherServletのdoSerivceメソッドをもう一度クリックしました。

DispatcherServletのdoService()メソッド
画像-20200719195305154

これが基本的な原則の調査の始まりであると判断されたので、doServie()メソッドで重要なロジックを探しているので、tryブロックで名前が付けられたdoDispatch(request, response);メソッドをもう一度見つけました(さまざまな初期化とストレージドメインデータ)。根底にある原則を探求する途中で、あなたは真実にますます近づくでしょうが、これは探求の長いプロセスになる運命にありますが、私も好みます。したがって、次の図に示すように、クリックしてdoDispatch()メソッドにソースコードを入力します。

doDispatch()メソッドのソースコード
画像-20200719200052667

doDispatch()メソッドのソースコードを調べた後、私はあなたを誤解していないことに気づきました。コメントでマークされているものは、いくつかの重要な実行ロジックメソッドです。次に、1つずつ分析し、SpringMVCの実行プロセスを徐々に理解していきます。実行フローを調べたので、Debug(Debugデバッグ機能、Debugは実行フローを明確に見ることができます)なので、getHandler()メソッド行のブレークポイントに到達しました次のステップはgetHandler()、次の図に示すように、実行プロセスをフォローアップしてメソッドを入力することです。

getHandlerメソッドのソースコード(説明に注意してください:現在のリクエストのハンドラーオブジェクトを見つけて返します)
画像-20200719201557155

getHandler()名前が示すように、コントローラー層でハンドラーを取得するためブレークポイントはこの行にとどまりますどうやってそれを手に入れたのですか?ブレークポイントの変数表示ボックスでは、handlerMappingsが3つのオブジェクトを持つ配列であることがわかります。次の図に示すように、これらはさまざまなハンドラーをさまざまな方法で処理できます。その中で、これら3つのオブジェクトをクリックし、オブジェクトを1つずつ展開して、重要なプロパティを表示できます。

0 = {RequestMappingHandlerMapping}
画像-20200719202203776
2 = {SimpleUrlHandlerMapping}
画像-20200719202458924

上の図に示すように、RequestMappingHandlerMappingオブジェクトは、コントローラー内の@RequestMappingアノテーションと、各ハンドラーの上のアノテーションパスを識別します。SimpleUrlHandlerMappingオブジェクトは、静的リソースを処理するためにドライバーによって作成されたデフォルトのサーブレットを識別し、静的リソースを処理するためのデフォルトのサーブレットパスが指定され/**、このパスを識別します。次の図に示すように、HanderMappingマッパー内のオブジェクトは、アノテーション認識を通じてControllerレイヤーの各Handler要求パスのアノテーションを取得した後、次の行に実行されます。

getHandlerメソッドのソースコード
画像-20200719203457220

すべてのハンドラーは注釈を介して見つけることができ、それらはすべてその中に格納されhandlerMappingsているため、このオブジェクトをトラバースします。次に、それぞれの要求オブジェクトに従って対応するハンドラーを取得し、取得した対応するハンドラーオブジェクトをnullとして返します。実行を続けると、以下に示すようなものが見つかります。

getHandler方法
画像-20200719204645324

はい、返そうとしているハンドラーはHandlerExecutionChainと呼ばれる実行チェーンであることがわかります。実行チェーンには、返されるハンドラーオブジェクトとinterceptorListコレクションが含まれています。コレクションには2つのオブジェクトがあり、これら2つのオブジェクトはインターセプターです。したがって、インターセプターを自分で使用するかどうかに関係なく(内部の下部にインターセプターがあります)、これらのインターセプターとハンドラーオブジェクトはチェーンで実行されます(インターセプターが最初、ハンドラーオブジェクトが後ろ)。実行プロセスは、最初にインターセプターを実行し、次にハンドラーオブジェクトを返して実行するという順序に従います。HandlerExecutionChain実行チェーンに戻り、実行チェーンが開始されようとしています。問題は、インターセプターオブジェクトとハンドラーオブジェクトを順番に正確に実行するのは誰ですか?以下に示すように:

doDispatch()メソッドのソースコード
画像-20200719210132545

実行チェーンに戻った後、このコード行が実行されるまで実行が続行され、コメントは現在の要求オブジェクトのハンドラーアダプターを探していると解釈されます。アダプターの設計パターンを習得していれば理解しやすいかもしれませんが、習得していなくても構いません。その後の説明も理解できます。リクエストオブジェクトのアダプタを探していることがわかっているので、実行を続行すると、次の情報が得られます。

getHandlerAdapterメソッドのソースコード
画像-20200719210604037

実行フローがgetHandlerAdapterメソッドに入りました。遠くから見ると、このメソッドはなじみのある感じがします。はい、HandlerMappingマッパーと非常によく似ており、単なる双子の兄弟です。このメソッドは、現在返されるハンドラーオブジェクトに基づいてハンドラーオブジェクトのアダプターを見つける必要があり、handlerAdaptersコレクションオブジェクトに3つのアダプターが格納されています。マッパーで実行チェーンを取得するときに考えてみてください。はい、それらはペアで表示され、ハンドラーのオブジェクトは、対応するアダプターを見つけた後にのみ実行を続行できます。現在のハンドラーオブジェクトとペアになっているアダプターを見つけると、アダプターが返されます。アダプターが戻った後、次のメソッドが実行されます。

doDispatch()メソッドのソースコード
画像-20200719211355102

このコードを通過した後、要求オブジェクトの要求メソッドが取得され、一連の判断操作が実行されました。以下まで実行を続けます。実行applyPreHandler方法を判断する以下のif判定があります。この方法は、インターセプターの事前メソッドです。インターセプターのfrontメソッドを実行した後、引き続き下向きに実行します。このとき、次のコードを実行する必要があります。

doDispatch()メソッドのソースコード
画像-20200719211927390

このメソッドからha、この時点でオブジェクトがハンドラオブジェクトであることがわかります。これは、ハンドラオブジェクトが実行される前にインターセプタが実行され、実行チェーンの順序にも従うことを示しています。要求パラメータオブジェクトのカプセル化とJson文字列と応答内のオブジェクトの変換が完了した後、実行を続行すると、mvオブジェクトが返されます。では、mvオブジェクトとは何ですか?実際、これは上で定義したModelAndViewオブジェクトです。mvオブジェクトを返した後、実行は次の重要な実行ロジックを実行し続けます。

doDispatch()メソッドのソースコード
画像-20200719213149039

実行過程では、インターセプターのpostメソッドを判定して実行しました。postメソッドが実行された後、一連の判断が行われ、processDispatchResult(processdRequest, response, mappdeHandler, mv, dispatchException)メソッドが実行されます。メソッドは、要求オブジェクト、応答オブジェクト、ハンドラーオブジェクト、ModelAndViewオブジェクトなどを運び、このメソッドのソースコードを入力すると、実行されることがわかります。一連の判断の後、ModelAndViewオブジェクトは次のメソッドを介してレンダリングされました。

レンダリングメソッドのソースコード
画像-20200719213629854

ModelAndViewオブジェクトをレンダリングしてビューを解析した後、勝利が間もなく来るので、メソッドのフォローアップを続けます。以下に示すように:

レンダリングメソッドのソースコード
画像-20200719213959635

実行を続けると、resolveViewNameメソッドを介してビューの解決が開始れることがわかります。したがって、以下に示すように、メソッドを入力します。

resolveViewNameメソッドのソースコード
画像-20200719214336328

まず、このメソッドのソースコードを見ると、viewResolversビューリゾルバーがModelAndViewオブジェクトを解析し、Viewオブジェクトを返すことがわかります。後で、Viewオブジェクトもrender次の名前のメソッドによってレンダリングれます。

view.render()
画像-20200719214907676

このViewオブジェクトは単純ではないことがわかります。しばらく実行された後、Webページがリダイレクトされるときに使用される要求転送のため、ページのソースコードは次のとおりです。

InternalResourceViewソースコード
画像-20200719215303749

このメソッドをクリックすると、使い慣れたリクエスト転送がここspring-mvc.xml読み取られて解析され、内部のデフォルトのリクエスト転送用にパスがスプライスされますforward:/XXX/XXX(今回はspring-mvc.xml構成ファイルも解析されます)その他のコンポーネント)、以下に示すように:

転送のリクエスト(InternalResourceView.java)
画像-20200719215453276

リダイレクトの場合は、次の図に示すように、次のクラスのリダイレクトメソッドです。

リダイレクト(RedirectView.java)
画像-20200719215921537

続いて、JSPページ(ビューレイヤー)に転送またはリダイレクトした後、データをHTMLにレンダリングし、HTMLコンテンツをレンダリングした後、ブラウザーに出力して応答し、ブラウザーに表示します。

このSpringMVCでは、ポイントのデバッグを中断することにより、基礎となる実行プロセスについて説明しました。自分でデバッグを中断すれば良い結果が得られると思います!

SpringMVCの内部コンポーネント
  • HandlerMapping(プロセッサマッパー)
  • HandlerAdapter
  • ViewResolver(ビューリゾルバー)
SpringMVCのデフォルトコンポーネントの初期ロード

上記では、単にDebugを介してSpringMVCの実行プロセスを説明しましたが、これほど多くの内部コンポーネントはどのようにして生まれたのでしょうか。そこで、DispatherServletからinitStrategies次のようなメソッドを見つけました

initStrategiesメソッドのソースコード
画像-20200720214203411

実行プロセスが開始する前に、内部コンポーネントの一連の初期化操作が実行されます。ここでは、initHandlerMappingsメソッドをさかのぼって、SpringMVCのデフォルト構成ファイルを見つけます。構成しなかったため(注釈またはBeanタグ)、initHandlerMappingsメソッドを入力します。このため、このメソッドの最初の2つのケースはスキップされ、一番下のデフォルトケースになり、getDefaultStrategiesメソッドを呼び出し、デフォルトの構成を読み取ります。ファイル。

initHandlerMappingsメソッドのソースコード
画像-20200720214539186
getDefaultStrategiesメソッドのソースコード
画像-20200720214701181

getDefaultStrategiesメソッドにはdefaultStrategiesがあります。以下に示すように、このクラスを見てみましょう。

defaultStrategiesソースコード
画像-20200720214907843

これは、デフォルトの構成ファイルをロードする場所です。DEFAULT_STRATEGIES_PATH定数をクリックして、デフォルトの構成構成ファイルを見つけます。

DEFAULT_STRATEGIES_PATH定数
画像-20200720215021940

そこで、さまざまなコンポーネントを初期化したこの構成ファイルを見つける方法を見つけようとしました。次のことを確認できます。

DispatcherServlet.properties構成ファイル
画像-20200720215320968

ここに写真の説明を挿入

おすすめ

転載: blog.csdn.net/weixin_44170221/article/details/107497117