正面から見てみましょう: 写真の一部は、Ma Bingbing 教師のサーブレットと JSP の
講義ノートから引用したものです。
ビデオリンク: https://www.bilibili.com/video/BV1cV411H7RY?p=1
** Tomcat の動作原理:
*
インタラクションプロセス:
クライアントはサーバーにリクエストを送信し、Tomcat リクエストはそのリクエストを受信し、サービスリクエストオブジェクトに送信します。リクエストオブジェクトは、リクエストを処理するために事前に作成されたアプレットプログラムを選択し、サービスを完了するために応答します。このプロセスでは、Web サーバー コンテナには多くのアプレットがありますが、サービスはどのアプレットを呼び出すべきかをどのように判断するのでしょうか? アプレットにはリクエストの処理が備わっています。ただし、最初に処理する必要があるのは、リクエスト オブジェクトと応答オブジェクトをカプセル化することです。
リクエストメッセージの形式:
package com.msb;
import java.io.IOException;
import java.io.InputStream;
public class MyRequest {
private String requestMethod;
private String requestUrl;
public MyRequest(InputStream inputStream) throws IOException {
//创建缓冲区
byte[] buffer=new byte[1024];
int len=0;
String str=null;
if((len=inputStream.read(buffer))>0) {
str=new String(buffer,0,len);
}
String data=str.split("\n")[0];
String[] params=data.split(" ");
this.requestMethod=params[0];
this.requestUrl=params[1];
}
public String getRequestMethod() {
return requestMethod;
}
public void setRequestMethod(String requestMethod) {
this.requestMethod = requestMethod;
}
public String getRequestUrl() {
return requestUrl;
}
public void setRequestUrl(String requestUrl) {
this.requestUrl = requestUrl;
}
}
以下はリクエストの単純なカプセル化であり、シミュレーションの原理だけです。
コードの解釈: データ送信はストリーム送信であることに変わりはなく、リクエスト オブジェクトは入力ストリーム ストリームを受信し、それを分割して文字列型データに解析して処理するためのバッファを設定します。
package com.msb;
import java.io.IOException;
import java.io.OutputStream;
public class MyResponse {
private OutputStream outputStream;
public MyResponse(OutputStream outputStream) {
this.outputStream=outputStream;
}
public void write(String str) throws IOException {
StringBuilder builder = new StringBuilder();
builder.append("HTTP/1.1 200 OK\n")
.append("Content-Type:text/html\n")
.append("\r\n")
.append("<html>")
.append("<body>")
.append("<h1>"+str+"</h1>")
.append("</body>")
.append("</html>");
this.outputStream.write(builder.toString().getBytes());
}
}
コードの解釈: 応答は、処理された文字列をストリーム応答に変換します。「append ("\r\n")」に注意してください。カプセル化後、次のことがわかります。実際、このプロセスはリクエスト (リクエスト) と
(どのアプレットをリクエストしますか (requesturl)? 各 requesturl とアプレットのカプセル化クラスの間にマッピング関係を作成できます。各アプレットには同じメソッドがありますが、メソッド本体が異なるため、抽象クラスを使用できます。それらをすべて継承させるか、インターフェースを使用してそれらを標準化します。
package com.msb;
public abstract class MyHttpServlet {
public static final String METHOD_GET="GET";
public static final String METHOD_POST="POST";
public abstract void doGet(MyRequest request,MyResponse response);
public abstract void doPost(MyRequest request,MyResponse response);
//根据请求判断调用哪个方法
public void service(MyRequest request,MyResponse response) {
if(METHOD_GET.equals(request.getRequestMethod())) {
doGet(request,response);
}else if(METHOD_POST.equals(response)) {
doPost(request,response);}
}
}
package com.msb;
import java.io.IOException;
public class MyServlet extends MyHttpServlet {
@Override
public void doGet(MyRequest request, MyResponse response) {
try {
response.write("doget:MyServlet");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
public void doPost(MyRequest request, MyResponse response) {
try {
response.write("doPost:MyServlet");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
マッピング関係:
package com.msb;
import java.util.HashMap;
public class MyMapping {
public static HashMap<String,String> mapping=new HashMap<String,String>();
static {
mapping.put("/MyTomCat", "com.msb.MyServlet");
}
public static HashMap<String, String> getMapping() {
return mapping;
}
}
図 1 に戻る:
サービス、インターフェイス、アプレットをカプセル化しましたが、ネットワークの相互作用とサービスとアプレットの相互作用がまだ不足しています。サーバーはこのプロセスを完了します。
package com.msb;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
//定义服务端的接收程序,接收socket请求
public class MyServer {
//定义服务端的接受程序,接受socket请求
@SuppressWarnings("deprecation")
public static void startServer(int port) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
ServerSocket serverSocket = new ServerSocket(port);
Socket socket=null;
while(true) {
socket=serverSocket.accept();
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
MyRequest request=new MyRequest(inputStream);
MyResponse response = new MyResponse(outputStream);
String clazzName = new MyMapping().getMapping().get(request.getRequestUrl());
if(clazzName!=null) {
Class<? extends MyHttpServlet> clazz = (Class<? extends MyHttpServlet>)Class.forName(clazzName);
MyHttpServlet newInstance = clazz.newInstance();
newInstance.service(request, response);
}
}
}
public static void main(String[] args) {
try {
startServer(1775);
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
コードの解釈: 静的メソッド startserver メソッドのパラメーター: ポート番号。パラメータをサーバーソケット (serversocket) に渡し、鉄のドアボルト (無限ループ) が長いサービスを実装します。サーバーはリクエストを受信し、処理のためにソケットに割り当てます。ソケットはストリームを取得し、MyRequest と MyRespond を渡し、作成します。キーコード: String clazzName = new MyMapping().getMapping().get(request.getRequestUrl()); リクエスト URL マッピングによって呼び出されるアプレットを取得し、リフレクション メカニズムを使用してアプレット オブジェクトを作成し、多態的にアプレット オブジェクトを作成します。 doget/dopost メソッドを呼び出してリクエストを処理し、応答します。
実行後、ブラウザは結果をリクエストします。
ただし、マルチスレッドや高い同時実行性など、後で実装される問題がまだいくつかあります。