Tomcat でのサーブレットの作成と実装に関する深い理解

Tomcat でのサーブレットの作成と実装に関する深い理解

1. サーブレットとは何か

1.1. 正式な言葉で説明する:

サーブレットは、動的な Web リソースを開発するために Oracle が提供するテクノロジであり、 JavaEEシステムのコア仕様です。
簡単に言うと、開発者が作成したクラスは、JavaEE のコア仕様を直接的または間接的に実装する必要があります。つまり、Servlet インターフェースを実装する必要があります。このクラスによって生成されたオブジェクトはブラウザからアクセスできるため、Servlet と呼ばれます。JavaEEでは、Servlet 実装クラスによって生成されたオブジェクトのみがブラウザからアクセス可能、つまり Servlet であると規定されています。(つまり、このクラスは Servlet インターフェースを直接的または間接的に実装する必要があります)

2. サーブレットの作成を開始する

2.1. これまでの紹介で、ブラウザからアクセスできるオブジェクトを作成するクラスの種類がわかりました。まずは、コードを直接見てみましょう。

パッケージ com.briup.web;
java.io.IOException をインポートします。
javax.servlet.Servlet をインポートします。
javax.servlet.ServletConfig をインポートします。
javax.servlet.ServletException をインポートします。
javax.servlet.ServletRequest をインポートします。
javax.servlet.ServletResponse をインポートします。

パブリッククラスFirstWayはServletを実装します{
	パブリックFirstWay() {
		System.out.println("オブジェクトが作成されました");
	}
	@オーバーライド
	パブリック void init(ServletConfig config) は ServletException をスローします {
		// TODO 自動生成されたメソッドスタブ
		System.out.println("私はinitです: 呼び出されました");
	}
	@オーバーライド
	パブリック ServletConfig getServletConfig() {
		// TODO 自動生成されたメソッドスタブ
		null を返します。
	}
	@オーバーライド
	パブリック void service(ServletRequest req, ServletResponse res) は ServletException、IOException をスローします {
		// TODO 自動生成されたメソッドスタブ
		System.out.println("私はサービスです、呼ばれました");	
	}
	@オーバーライド
	パブリック文字列 getServletInfo() {
		// TODO 自動生成されたメソッドスタブ
		null を返します。
	}
	@オーバーライド
	パブリックvoidの破棄(){
		// TODO 自動生成されたメソッドスタブ
		System.out.println("私は破壊されました: 私は呼ばれました");
	}

}

サーブレットを満たすクラスが作成されました。次の質問は

誰がサーブレットオブジェクトを作成しますか?

そこに実装されているどのインターフェース メソッドが呼び出され、いつ呼び出され、何回呼び出されるのでしょうか。
最初の質問は、サーブレット クラスであるため、開発者が手動でオブジェクトを作成するのは明らかに不合理であるため、このオブジェクトの作成は Tomcat に引き渡されるということです。開発者は、Tomcat にオブジェクトを作成するように指示するだけで、いつでも作成できます。
どうやって見分ける?

1. 方法 1: webxml を構成する。 (あまりお勧めしません)

動的Webプロジェクト全体において、web.xmlは最初に読み込まれる構成ファイルなので、web.xmlで構成します。

<?xml バージョン="1.0" エンコーディング="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" バージョン="3.1">
 <display-name>firstWay</display-name>
 <サーブレット>
 		<サーブレット名>FirstWay</サーブレット名>
 		<サーブレットクラス>com.briup.web.FirstWay</サーブレットクラス>
 		<!-- <load-on-startup>1</load-on-startup> -->
 </サーブレット>
 <サーブレットマッピング>
 	<サーブレット名>FirstWay</サーブレット名>
 	<url-pattern>/FirstWay</url-pattern>
 </サーブレットマッピング>
</ウェブアプリ>

説明する:
1. servlet-name: サーブレットの名前。以下のマッピングで設定した名前と一致する必要があります。
2. serlvet-class: serlvetの完全修飾名
3. load-on-startup: Tomcat の起動時にサーブレット オブジェクトを作成するかどうかを指定します。0 より大きい整数を渡します (デフォルトでは、ブラウザーが初めて要求したときにサーブレット オブジェクトが作成されます)
4. サーブレットマッピング: 名前の通り、ブラウザアクセスマッピングを設定します。
5. servlet-name: 上記に対応
6. url-pattern: ブラウザ アクセス マッピング (デフォルトがローカル マシンで、Tomcat のポート番号が 8080 であると仮定すると、ブラウザがこのサーブレットにアクセスするためのパスは次のようになります: localhost:8080/プロジェクト名/FirstWay )
これらの基礎が整ったところで、見てみましょう。

ステップ1: Tomcatを起動する

ここに画像の説明を挿入

tomcatが正常に起動します

ステップ 2:ブラウザからアクセスします (ここでは手動で 3 回アクセスします)

ここに画像の説明を挿入

ブラウザアクセスは正常です

ステップ3:コンソールを観察する

ここに画像の説明を挿入

結果分析を実行すると、次のようになります。

サーバーを初めて起動すると、オブジェクトは作成されません

ブラウザは 3 回リクエストしますが、オブジェクトは 1 回だけ作成され、init() メソッドは 1 回だけ呼び出されます。

オブジェクトにアクセスするたびに、service()メソッドが呼び出されます。

他のメソッドは呼び出されない

呼び出されない理由を説明します: getServletConfig(): ServletConfig オブジェクトを取得します: getServletInfo(): 作成者などのサーブレットの信頼性を取得します: destroy(): このメソッドは、サーブレットが破棄されるときに呼び出されます (例: tomcati は正常に閉じられます。ここではテストしません。テストする場合は、サービスを右クリックして停止をクリックできます)。その後、コンソールを観察して確認してください。

2. 方法2: Tomcatにアノテーションで伝える(前者と比較して推奨)

@WebServlet(値 = "マッピングパス")
パブリックファーストサーブレットはServeltを実装します{
}

このアノテーションは、サーバーの起動時にオブジェクトを作成するかどうかを設定する場合にも使用できます。ここでは説明しません。
注意: (アノテーションを使用して Tomcat にオブジェクトを作成するように指示すると、web.xml でサーブレットにアクセスして設定することはできなくなります)

3. 話題に戻り、サーブレットを作成する2番目の方法

前回の説明を踏まえて、コードを直接分析してみましょう。

パッケージ com.briup.web;

java.io.IOException をインポートします。

javax.servlet.GenericServlet をインポートします。
javax.servlet.ServletException をインポートします。
javax.servlet.ServletRequest をインポートします。
javax.servlet.ServletResponse をインポートします。
javax.servlet.annotation.WebServlet をインポートします。
@WebServlet(値 = "/secondWay")
パブリッククラスSecondWayCreateはGenericServletを拡張します{

	@オーバーライド
	パブリック void service(ServletRequest req, ServletResponse res) は ServletException、IOException をスローします {
		// TODO 自動生成されたメソッドスタブ
		System.out.println("サービスメソッドが呼び出されました");
	}

}

1. 最初の方法よりもシンプルで、GenericServletクラスを実装します

2. GenericServlet のソースコードを見て分析してみましょう。

パブリック抽象クラスGenericServletはServlet、ServletConfigを実装します。

これはドロワー クラスであり、サーブレット インターフェイスの実装クラスであることがわかります。そのため、GenericServlet は間接的にサーブレット インターフェイスを実装します。
最初の方法と比較すると、開発者は一部のインターフェースに不要なメソッドを実装する必要がなく、選択的になり、コードの量を削減できます。しかし、それは上記ほど有用ではなく、単にBのふりをしているだけです

3. 3番目の方法に焦点を当てる(最初の2つと比較して、3番目の方法をお勧めします)

コードに直接

パッケージ com.briup.web;

java.io.IOException をインポートします。

javax.servlet.ServletException をインポートします。
javax.servlet.annotation.WebServlet をインポートします。
javax.servlet.http.HttpServlet をインポートします。
javax.servlet.http.HttpServletRequest をインポートします。
javax.servlet.http.HttpServletResponse をインポートします。
@WebServlet(値 = "/ThreeWayCreate")
パブリッククラスThreeWayCreateはHttpServletを拡張します{
	@オーバーライド
	保護された void doGet(HttpServletRequest req, HttpServletResponse resp) は ServletException、IOException をスローします {
		// TODO 自動生成されたメソッドスタブ
		super.doGet(要求、応答);
	}
	@オーバーライド
	保護された void doPost(HttpServletRequest req, HttpServletResponse resp) は ServletException、IOException をスローします {
		// TODO 自動生成されたメソッドスタブ
		super.doPost(req, resp);
	}
}

上記のコードを見て、サーブレットはサーブレット インターフェイスを直接的または間接的に実装する必要があるのではないのか、ブラウザーはリクエストごとにサービス メソッドを 1 回呼び出す必要があるのではないのか、と疑問に思う人もいるかもしれません。方法はどこにありますか?これは以前の理論と矛盾しませんか?
引き続きソースコードを見てみましょう。ソースコードは真実です。 以下にソースコードの核となる部分をリストします。より深く理解する必要がある友人は、ソースコードに直接アクセスできます。Tomcatはオープンソースです

パッケージ com.briup.web;

java.io.IOException をインポートします。

javax.servlet.ServletException をインポートします。
javax.servlet.annotation.WebServlet をインポートします。
javax.servlet.http.HttpServlet をインポートします。
javax.servlet.http.HttpServletRequest をインポートします。
javax.servlet.http.HttpServletResponse をインポートします。
@WebServlet(値 = "/ThreeWayCreate")
パブリッククラスThreeWayCreateはHttpServletを拡張します{
	@オーバーライド
	保護された void doGet(HttpServletRequest req, HttpServletResponse resp) は ServletException、IOException をスローします {
		// TODO 自動生成されたメソッドスタブ
		super.doGet(要求、応答);
	}
	@オーバーライド
	保護された void doPost(HttpServletRequest req, HttpServletResponse resp) は ServletException、IOException をスローします {
		// TODO 自動生成されたメソッドスタブ
		super.doPost(req, resp);
	}
}

分析:

最初のステップの分析

ここに画像の説明を挿入

この抽象クラスは抽象クラス GennericeServlet を継承していることがわかります。つまり、レイヤーごとにプッシュダウンされ、Servle インターフェイスを実装します。次に、この抽出クラスも serice メソッドを継承する必要があります。

第二段階の分析

ここに画像の説明を挿入

これはサーブレットインターフェースを継承したサービスメソッドです。このメソッドはブラウザがリクエストするたびに呼び出されます。図に示すように、このメソッドは HttpServlet によって実装されています。実装クラスからは、リクエストオブジェクト req とレスポンスオブジェクト res が HttpServletRequest と HttpServletResponse に強制的に変換され (下方変換)、その後、強制的に変換されたオブジェクトが HttpServlet のオーバーロードされたサービスメソッドに渡されて呼び出されると結論付けることができます。3 番目のステップは、オーバーロードされたサービス (HttpRequest req、HttpResponse res) を分析することです。

ステップ3 分析

保護された void サービス (HttpServletRequest 要求、HttpServletResponse 応答)
    ServletException、IOException をスローします {

    文字列メソッド = req.getMethod();

    メソッドがMETHOD_GETと等しい場合
      lastModified は、req に格納されます。
      (最終変更 == -1)の場合{
        // サーブレットは理由もなく if-modified-since をサポートしていません
        // さらに高価なロジックを実行する
        要求、応答を取得します。
      } それ以外 {
        長い ifModifiedSince;
        試す {
          変更された日付が返されるかどうか。
        } キャッチ (IllegalArgumentException iae) {
          // 日付ヘッダーが無効です - 何も設定されていないものとして続行します
          変更された場合 = -1;
        }
        if (ifModifiedSince < (lastModified / 1000 * 1000)) {
          // サーブレットの変更時刻が遅い場合は、doGet() を呼び出します
          // 適切な比較のために最も近い秒に切り捨てます
          // ifModifiedSinceが-1の場合は常に
          おそらく、LastModified を設定します(resp、lastModified);
          要求、応答を取得します。
        } それ以外 {
          resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
        }
      }

    } そうでない場合 (method.equals(METHOD_HEAD)) {
      lastModified は、req に格納されます。
      おそらく、LastModified を設定します(resp、lastModified);
      要求されたレスポンスを返す。

    } それ以外の場合 (method.equals(METHOD_POST)) {
      要求をポストします。

    } それ以外の場合 (method.equals(METHOD_PUT)) {
      要求、応答を返す。

    } そうでない場合 (method.equals(METHOD_DELETE)) {
      要求、応答を削除します。

    } そうでない場合 (method.equals(METHOD_OPTIONS)) {
      オプションを(req,resp)実行します。

    } そうでない場合 (method.equals(METHOD_TRACE)) {
      トレースを実行します(req,resp);

    } それ以外 {
      //
      // これは、どのサーブレットもサポートしていないことを意味することに注意してください
      // メソッドがこのサーバーのどこからでも要求されました。
      //

      文字列 errMsg = lStrings.getString("http.method_not_implemented");
      オブジェクト[] errArgs = 新しいオブジェクト[1];
      errArgs[0] = メソッド;
      errMsg = MessageFormat.format(errMsg, errArgs);

      resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED、errMsg);
    }
  }

リクエストメソッドは渡されたHttpRequestオブジェクトによって決定され、呼び出されるメソッドはリクエストメソッドによって決定されます(リクエストメソッドがpostの場合、doPost(HttpRequest req,HttpRestpone Res)メソッドが呼び出されます

4 番目のステップの分析: 上記の分析に基づいて、次のように結論付けることができます。Tomcat はオブジェクトを作成し、ブラウザーが要求すると、サーブレットの Service(ServeltRequest req, ServletRespone res) メソッドを呼び出します。次に、このメソッドは HttpServlet 内のオーバーロードされた Servlet(HttpServletReqeust req, HttpServletRespone res) メソッドを呼び出します。次に、このメソッドは要求メソッドに従って doPost() メソッドまたは doGet() メソッドを選択的に呼び出します (もちろん、ここに記載されていない他の多くの方法があります)。したがって、3 番目の方法の本質は、ブラウザーが要求を開始すると、サーブレット インターフェイス内の Service(ServeltRequest req, ServletRespone res) メソッドが呼び出され、次に実装クラスのロジックを通じて doPost() メソッドと他のメソッドが間接的に呼び出されることにあります。

アドバンテージ:

1. 対応するリクエストはリクエストメソッドを通じて処理できるため、ロジックが明確になります。

2. コードの量を減らしてプログラムを簡潔にする

3. リクエストやレスポンスをより操作しやすくする

4…

IV. 要約:

注:ブラウザはサーブレットのサービス メソッドを呼び出すリクエストを開始する必要があります。

Tomcat でのサーブレット作成の実装に関する詳細な理解に関するこの記事はこれで終わりです。Tomcat サーブレット作成に関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • アイデアのMavenWebプロジェクトのソリューションではサーブレットを作成できない
  • アイデアファイルを右クリックしても「新規サーブレットの作成」が表示されない問題の解決方法の詳細説明
  • IDEA で Maven プロジェクト サーブレットを作成する方法の詳細なチュートリアル
  • IDEAはサーブレットを作成し、web.xmlの実装を構成します。
  • IntelliJ IDEA2020.2.2 はサーブレット メソッドと 404 問題を作成します
  • myeclipse が servlet_PowerNode を作成する Java アカデミー
  • エディターなしでサーブレット (Tomcat + Java) プロジェクトを作成する方法は?

<<:  JavaScript にはすでに Object があるのに、なぜ Map が必要なのでしょうか?

>>:  IntelliJ IDEA で Java を使用して MySQL データベースに接続する方法の詳細な説明

推薦する

NGINXがウェブサイトのPV、UV、独立IPをカウントする方法の詳細な説明

Nginx: PV、UV、独立IPウェブサイトを作成する人なら誰でも、ウェブサイトのPV、UV、その...

Vue における ref と $refs の紹介と使用例

序文JavaScript では、document.querySelector("#demo...

Webデザイン: タイトルが完全に表示できない場合

<br />今日、新しくなった ChinaUI.com の Web サイトを見たのですが...

WeChatアプレットにナンバープレート入力機能を実装

目次序文背景大きな推測パターンを見つける構造とスタイルコンポーネントの実装パラメータキーボードの種類...

アルバムと写真をアルバムに保存するためのWeChatアプレット

私は現在、Xiao Nian Gao に似たビデオおよびツール アプリを開発しています。ユーザーが作...

HTMLフレームワーク_Powernode Javaアカデミー

1. フレームワークブラウザのドキュメント ウィンドウには 1 つの Web ページ ファイルしか表...

MySQL 5.7.20\5.7.21 無料インストール版のインストールと設定のチュートリアル

参考までに、mysql 5.7.20 / 5.7.21 をダウンロード、インストール、構成します。具...

Ubuntu の仮想環境に Django をインストールする方法

Ubuntu コマンドライン ウィンドウで次の操作を実行します。 1. 仮想環境をインストールする...

OpenLayers 3 のベクターマップソースの読み込みの問題を解決する

1. ベクターマップベクター グラフィックスは直線と曲線を使用してグラフィックスを表します。これらの...

UbuntuでGRUBの起動時間を変更する

grubの起動時間を変更するためのオンライン検索は基本的に/etc/default/grubを変更す...

Windows で Graphviz をインストールして開始する方法のチュートリアル

ダウンロードとインストール環境変数の設定インストール環境変数の設定確認基本的な描画の紹介グラフディグ...

MySQL 5.7.23 のインストールと設定のグラフィックチュートリアル

この記事では、mysql5.7.23 の詳細なインストールプロセスを記録し、皆さんと共有します。 1...

JS 面接の質問: forEach はループから抜け出すことができますか?

この質問をされたとき、私は無知で頭が真っ白になりました。もちろん、正しく答えられませんでした。私はず...

22 Vue 最適化のヒント (プロジェクトの実践)

目次コードの最適化v-for でキーを使用するv-if/v-else-if/v-else でキーを使...

React refsの詳細な紹介

1. 何ですかRefs 、コンピューターでは Resilient File System (ReF...