一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - 驚呆了!手寫4個mini版的Tomcat!

驚呆了!手寫4個mini版的Tomcat!

2021-03-17 23:25Java后端技術全棧田維常 Java教程

Apache Tomcat 是Java Servlet, JavaServer Pages (JSP),Java表達式語言和Java的WebSocket技術的一個開源實現 ,通常我們將Tomcat稱為Web容器或者Servlet容器 。

 

驚呆了!手寫4個mini版的Tomcat!

 

寫在前面

Apache Tomcat 是Java Servlet, JavaServer Pages (JSP),Java表達式語言和Java的WebSocket技術的一個開源實現 ,通常我們將Tomcat稱為Web容器或者Servlet容器 。

今天,我們就來手寫tomcat,但是說明一下:咱們不是為了裝逼才來寫tomcat,而是希望大家能更多的理解和掌握tomcat。

廢話不多說了,直接開干。

基本結構

 

tomcat架構圖

驚呆了!手寫4個mini版的Tomcat!

我們可以把上面這張架構圖做簡化,簡化后為:

驚呆了!手寫4個mini版的Tomcat!

什么是http協議

Http是一種網絡應用層協議,規定了瀏覽器與web服務器之間如何通信以及數據包的結構。

通信大致可以分為四步:

  1. 先建立連接。
  2. 發送請求數據包。
  3. 發送響應數據包。
  4. 關閉連接。

優點

web服務器可以利用有限的連接為盡可能多的客戶請求服務。

tomcat中Servlet的運作方式

  1. 在瀏覽器地址欄輸入http://ip:port/servlet-day01/hello
  2. 瀏覽器依據IP、port建立連接(即與web服務器之間建立網絡連接)。
  3. 瀏覽器需要將相關數據打包(即按照http協議要求,制作一個 請求數據包,包含了一些數據,比如請求資源路徑),并且將請求 數據包發送出去。
  4. web服務器會將請求數據包中數據解析出來,并且將這些數據添加 到request對象,同時,還會創建一個response對象。
  5. web服務器創建Servlet對象,然后調用該對象的service方法(會將request和response作為參數)。注:在service方法里面,通過使用request獲得請求相關的數據, 比如請求參數值,然后將處理結果寫到response。
  6. web服務器將response中的數據取出來,制作響應數據包,然后發送給瀏覽器。
  7. 瀏覽器解析響應數據包,然后展現。

可以總結唯一張圖:

驚呆了!手寫4個mini版的Tomcat!

什么是Servlet呢?

 

Servlet是JavaEE規范的一種,主要是為了擴展Java作為Web服務的功能,統一接口。由其他內部廠商如tomcat,jetty內部實現web的功能。如一個http請求到來:容器將請求封裝為servlet中的HttpServletRequest對象,調用init(),service()等方法輸出response,由容器包裝為httpresponse返回給客戶端的過程。

驚呆了!手寫4個mini版的Tomcat!

什么是Servlet規范?

 

  1. 從 Jar 包上來說,Servlet 規范就是兩個 Jar 文件。servlet-api.jar 和 jsp-api.jar,Jsp 也是一種 Servlet。
  2. 從package上來說,就是 javax.servlet 和 javax.servlet.http 兩個包。
  3. 從接口來說,就是規范了 Servlet 接口、Filter 接口、Listener 接口、ServletRequest 接口、ServletResponse 接口等。類圖如下:

驚呆了!手寫4個mini版的Tomcat!

第一版:Socket版

 

使用Socket編程,實現簡單的客戶端和服務端的聊天。

服務端代碼如下:

  1. package com.tian.v1; 
  2.  
  3. import java.io.*; 
  4. import java.net.*; 
  5.  
  6.  
  7. public class Server { 
  8.  
  9.     public static String readline = null
  10.     public static String inTemp = null
  11.     public static String turnLine = "\n"
  12.     public static final String client = "客戶端:"
  13.     public static final String server = "服務端:"
  14.     public static final int PORT = 8090; 
  15.  
  16.     public static void main(String[] args) throws Exception { 
  17.         ServerSocket serverSocket = new ServerSocket(PORT); 
  18.         System.out.println("服務端已經準備好了"); 
  19.         Socket socket = serverSocket.accept(); 
  20.  
  21.         BufferedReader systemIn = new BufferedReader(new InputStreamReader(System.in)); 
  22.         BufferedReader socketIn = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
  23.         PrintWriter socketOut = new PrintWriter(socket.getOutputStream()); 
  24.         while (true) { 
  25.             inTemp = socketIn.readLine(); 
  26.             if (inTemp != null &&inTemp.contains("over")) { 
  27.                 systemIn.close(); 
  28.                 socketIn.close(); 
  29.                 socketOut.close(); 
  30.                 socket.close(); 
  31.                 serverSocket.close(); 
  32.             } 
  33.             System.out.println(client + inTemp); 
  34.             System.out.print(server); 
  35.  
  36.             readline = systemIn.readLine(); 
  37.  
  38.             socketOut.println(readline); 
  39.             socketOut.flush(); 
  40.         } 
  41.     } 

客戶端代碼如下:

  1. package com.tian.v1; 
  2.  
  3. import java.io.*; 
  4. import java.net.*; 
  5.  
  6. public class Client { 
  7.  
  8.     public static void main(String[] args) throws Exception { 
  9.         String readline; 
  10.         String inTemp; 
  11.         final String client = "客戶端說:"
  12.         final String server = "服務端回復:"
  13.  
  14.         int port = 8090; 
  15.         byte[] ipAddressTemp = {127, 0, 0, 1}; 
  16.         InetAddress ipAddress = InetAddress.getByAddress(ipAddressTemp); 
  17.  
  18.         //首先直接創建socket,端口號1~1023為系統保存,一般設在1023之外 
  19.         Socket socket = new Socket(ipAddress, port); 
  20.  
  21.         BufferedReader systemIn = new BufferedReader(new InputStreamReader(System.in)); 
  22.         BufferedReader socketIn = new BufferedReader(new InputStreamReader(socket.getInputStream())); 
  23.         PrintWriter socketOut = new PrintWriter(socket.getOutputStream()); 
  24.         while (true) { 
  25.             System.out.print(client); 
  26.             readline = systemIn.readLine(); 
  27.  
  28.             socketOut.println(readline); 
  29.             socketOut.flush(); 
  30.             //處理 
  31.             inTemp = socketIn.readLine(); 
  32.             if (inTemp != null && inTemp.contains("over")) { 
  33.                 systemIn.close(); 
  34.                 socketIn.close(); 
  35.                 socketOut.close(); 
  36.                 socket.close(); 
  37.             } 
  38.             System.out.println(server + inTemp); 
  39.         } 
  40.     } 

過程如下:

第二版:我們直接請求http://localhost:8090

 

實現代碼如下:

  1. package com.tian.v2; 
  2.  
  3. import java.io.IOException; 
  4. import java.io.OutputStream; 
  5. import java.net.ServerSocket; 
  6. import java.net.Socket; 
  7.  
  8. public class MyTomcat { 
  9.     /** 
  10.      * 設定啟動和監聽端口 
  11.      */ 
  12.     private int port = 8090; 
  13.  
  14.     /** 
  15.      * 啟動函數 
  16.      * 
  17.      * @throws IOException 
  18.      */ 
  19.     public void start() throws IOException { 
  20.         System.out.println("my tomcat starting..."); 
  21.         String responseData = "6666666"
  22.         ServerSocket socket = new ServerSocket(port); 
  23.         while (true) { 
  24.             Socket accept = socket.accept(); 
  25.             OutputStream outputStream = accept.getOutputStream(); 
  26.             String responseText = HttpProtocolUtil.getHttpHeader200(responseData.length()) + responseData; 
  27.             outputStream.write(responseText.getBytes()); 
  28.             accept.close(); 
  29.         } 
  30.     } 
  31.  
  32.     /** 
  33.      * 啟動入口 
  34.      */ 
  35.     public static void main(String[] args) throws IOException { 
  36.         MyTomcat tomcat = new MyTomcat(); 
  37.         tomcat.start(); 
  38.     } 

再寫一個工具類,內容如下;

  1. ackage com.tian.v2; 
  2.  
  3. public class HttpProtocolUtil { 
  4.  
  5.     /** 
  6.      * 200 狀態碼,頭信息 
  7.      * 
  8.      * @param contentLength 響應信息長度 
  9.      * @return 200 header info 
  10.      */ 
  11.     public static String getHttpHeader200(long contentLength) { 
  12.         return "HTTP/1.1 200 OK \n" + "Content-Type: text/html \n" 
  13.                 + "Content-Length: " + contentLength + " \n" + "\r\n"
  14.     } 
  15.  
  16.     /** 
  17.      * 為響應碼 404 提供請求頭信息(此處也包含了數據內容) 
  18.      * 
  19.      * @return 404 header info 
  20.      */ 
  21.     public static String getHttpHeader404() { 
  22.         String str404 = "<h1>404 not found</h1>"
  23.         return "HTTP/1.1 404 NOT Found \n" + "Content-Type: text/html \n" 
  24.                 + "Content-Length: " + str404.getBytes().length + " \n" + "\r\n" + str404; 
  25.     } 

啟動main方法:

驚呆了!手寫4個mini版的Tomcat!

使用IDEA訪問:

驚呆了!手寫4個mini版的Tomcat!

在瀏覽器訪問:

驚呆了!手寫4個mini版的Tomcat!

自此,我們的第二版本搞定。下面繼續第三個版本;

第三版:封裝請求信息和響應信息

 

一個http協議的請求包含三部分:

  • 方法 URI 協議/版本
  • 請求的頭部
  • 主體內容

比如

  1. POST /index.html HTTP/1.1 
  2. Accept: text/plain; text/html 
  3. Accept-Language: en-gb 
  4. Connection: Keep-Alive 
  5. Host: localhost 
  6. User-Agent: Mozilla/4.0 (compatible; MSIE 4.01; Windows 98) 
  7. Content-Length: 33 
  8. Content-Type: application/x-www-form-urlencoded 
  9. Accept-Encoding: gzip, deflate 
  10.  
  11. lastName=tian&firstName=JohnTian 

簡單的解釋

  • 數據的第一行包括:方法、URI、協議和版本。在這個例子里,方法為POST,URI為/index.html,協議為HTTP/1.1,協議版本號為1.1。他們之間通過空格來分離。
  • 請求頭部從第二行開始,使用英文冒號(:)來分離鍵和值。
  • 請求頭部和主體內容之間通過空行來分離,例子中的請求體為表單數據。

類似于http協議的請求,響應也包含三個部分。

  • 協議 狀態 狀態描述
  • 響應的頭部
  • 主體內容

比如:

  1. HTTP/1.1 200 OK 
  2. Server: Microsoft-IIS/4.0 
  3. Date: Mon, 5 Jan 2004 13:13:33 GMT 
  4. Content-Type: text/html 
  5. Last-Modified: Mon, 5 Jan 2004 13:13:12 GMT 
  6. Content-Length: 112 
  7.  
  8. <html> 
  9. <head> 
  10. <title>HTTP Response Example</title> </head> 
  11. <body> 
  12. Welcome to Brainy Software 
  13. </body> 
  14. </html> 

簡單解釋

  • 第一行,HTTP/1.1 200 OK表示協議、狀態和狀態描述。
  • 之后表示響應頭部。
  • 響應頭部和主體內容之間使用空行來分離。

代碼實現

創建一個工具類,用來獲取靜態資源信息。

  1. package com.tian.v3; 
  2.  
  3. import com.tian.v2.HttpProtocolUtil; 
  4.  
  5. import java.io.IOException; 
  6. import java.io.InputStream; 
  7. import java.io.OutputStream; 
  8.  
  9. /** 
  10.  * 提取了一些共用類和函數 
  11.  */ 
  12. public class ResourceUtil { 
  13.  
  14.     /** 
  15.      * 根據請求 url 獲取完整絕對路徑 
  16.      */ 
  17.     public static String getPath(String url) { 
  18.         String path = ResourceUtil.class.getResource("/").getPath(); 
  19.         return path.replaceAll("\\\\", "/") + url; 
  20.     } 
  21.  
  22.     /** 
  23.      * 輸出靜態資源信息 
  24.      */ 
  25.     public static void outputResource(InputStream input, OutputStream output) throws IOException { 
  26.         int count = 0; 
  27.         while (count == 0) { 
  28.             count = input.available(); 
  29.         } 
  30.         int resourceSize = count
  31.         output.write(HttpProtocolUtil.getHttpHeader200(resourceSize).getBytes()); 
  32.         long written = 0; 
  33.         int byteSize = 1024; 
  34.         byte[] bytes = new byte[byteSize]; 
  35.         while (written < resourceSize) { 
  36.             if (written + byteSize > resourceSize) { 
  37.                 byteSize = (int) (resourceSize - written); 
  38.                 bytes = new byte[byteSize]; 
  39.             } 
  40.             input.read(bytes); 
  41.             output.write(bytes); 
  42.             output.flush(); 
  43.             written += byteSize; 
  44.         } 
  45.     } 

另外HttpProtocolUtil照樣用第二版本中。

再創建Request類,用來解析并存放請求相關參數。

  1. package com.tian.v3; 
  2.  
  3. import java.io.IOException; 
  4. import java.io.InputStream; 
  5.  
  6. public class Request { 
  7.     /** 
  8.      * 請求方式, eg: GET、POST 
  9.      */ 
  10.     private String method; 
  11.  
  12.     /** 
  13.      * 請求路徑,eg: /index.html 
  14.      */ 
  15.     private String url; 
  16.  
  17.     /** 
  18.      * 請求信息輸入流 <br> 
  19.      * 示例 
  20.      * <pre> 
  21.      *  GET / HTTP/1.1 
  22.      *  Host: localhost 
  23.      *  Connection: keep-alive 
  24.      *  Pragma: no-cache 
  25.      *  Cache-Control: no-cache 
  26.      *  Upgrade-Insecure-Requests: 1 
  27.      *  User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36 
  28.      * </pre> 
  29.      */ 
  30.     private InputStream inputStream; 
  31.  
  32.     public Request() { 
  33.     } 
  34.  
  35.     public Request(InputStream inputStream) throws IOException { 
  36.         this.inputStream = inputStream; 
  37.         int count = 0; 
  38.         while (count == 0) { 
  39.             count = inputStream.available(); 
  40.         } 
  41.         byte[] bytes = new byte[count]; 
  42.         inputStream.read(bytes); 
  43.         // requestString 參考:this.inputStream 示例 
  44.         String requestString = new String(bytes); 
  45.         // 按換行分隔 
  46.         String[] requestStringArray = requestString.split("\\n"); 
  47.         // 讀取第一行數據,即:GET / HTTP/1.1 
  48.         String firstLine = requestStringArray[0]; 
  49.         // 遍歷第一行數據按空格分隔 
  50.         String[] firstLineArray = firstLine.split(" "); 
  51.         this.method = firstLineArray[0]; 
  52.         this.url = firstLineArray[1]; 
  53.     } 
  54.  
  55.     public String getMethod() { 
  56.         return method; 
  57.     } 
  58.  
  59.     public void setMethod(String method) { 
  60.         this.method = method; 
  61.     } 
  62.  
  63.     public String getUrl() { 
  64.         return url; 
  65.     } 
  66.  
  67.     public void setUrl(String url) { 
  68.         this.url = url; 
  69.     } 
  70.  
  71.     public InputStream getInputStream() { 
  72.         return inputStream; 
  73.     } 
  74.  
  75.     public void setInputStream(InputStream inputStream) { 
  76.         this.inputStream = inputStream; 
  77.     } 

把第二版的MyTomcat進行小小調整:

  1. package com.tian.v3; 
  2.  
  3. import java.io.IOException; 
  4. import java.io.OutputStream; 
  5. import java.net.ServerSocket; 
  6. import java.net.Socket; 
  7.  
  8. public class MyTomcat { 
  9.  
  10.     private static final int PORT = 8090; 
  11.     public void start() throws IOException { 
  12.         System.out.println("my tomcat starting..."); 
  13.         ServerSocket socket = new ServerSocket(PORT); 
  14.         while (true) { 
  15.             Socket accept = socket.accept(); 
  16.             OutputStream outputStream = accept.getOutputStream(); 
  17.             // 分別封裝 Request 和 Response 
  18.             Request request = new Request(accept.getInputStream()); 
  19.             Response response = new Response(outputStream); 
  20.             // 根據 request 中的 url,輸出 
  21.             response.outputHtml(request.getUrl()); 
  22.             accept.close(); 
  23.         } 
  24.     } 
  25.     
  26.     public static void main(String[] args) throws IOException { 
  27.         MyTomcat tomcat = new MyTomcat(); 
  28.         tomcat.start(); 
  29.     } 

然后再創建一個index.html,內容很簡單:

  1. <!DOCTYPE html> 
  2. <html lang="en"
  3. <head> 
  4.     <meta charset="UTF-8"
  5.     <title>hello world</title> 
  6. </head> 
  7. <body> 
  8. <h2> you already succeed!</h2> 
  9. </body> 
  10. </html> 

這一需要注意,index.html文件的存放路徑不放錯了,視本地路徑來定哈,放在classes文件夾下的。你可以debug試試,看看你應該放在那個目錄下。

啟動MyTomcat。

驚呆了!手寫4個mini版的Tomcat!

訪問http://localhost:8090/index.html

驚呆了!手寫4個mini版的Tomcat!

自此,我們針對于Http請求參數和相應參數做了一個簡單的解析以及封裝。

盡管其中還有很多問題,但是字少看起來有那點像樣了。我們繼續第四版,

第四版:實現動態請求資源

 

用過servlet的同學都知道,Servlet中有三個很重要的方法init、destroy 、service 。其中還記得我們自己寫LoginServlet的時候,還會重寫HttpServlet中的doGet()和doPost()方法。下面們就自己來搞一個:

Servlet類代碼如下:

  1. public interface Servlet { 
  2.     void init() throws Exception; 
  3.     void destroy() throws Exception; 
  4.     void service(Request request, Response response) throws Exception; 

然后再寫一個HttpServlet來實現Servlet。

代碼實現如下:

  1. package com.tian.v4; 
  2.  
  3. public abstract class HttpServlet implements Servlet { 
  4.     @Override 
  5.     public void init() throws Exception { 
  6.  
  7.     } 
  8.  
  9.     @Override 
  10.     public void destroy() throws Exception { 
  11.  
  12.     } 
  13.  
  14.     @Override 
  15.     public void service(Request request, Response response) throws Exception { 
  16.         String method = request.getMethod(); 
  17.         if ("GET".equalsIgnoreCase(method)) { 
  18.             doGet(request, response); 
  19.         } else { 
  20.             doPost(request, response); 
  21.         } 
  22.     } 
  23.     public abstract void doGet(Request request, Response response) throws Exception; 
  24.  
  25.     public abstract void doPost(Request request, Response response) throws Exception; 

下面我們就來寫一個自己的Servlet,比如LoginServlet。

  1. package com.tian.v4; 
  2.  
  3. public class LoginServlet  extends HttpServlet { 
  4.  
  5.     @Override 
  6.     public void doGet(Request request, Response response) throws Exception { 
  7.         String repText = "<h1> LoginServlet by GET method</h1>"
  8.         response.output(HttpProtocolUtil.getHttpHeader200(repText.length()) + repText); 
  9.     } 
  10.  
  11.     @Override 
  12.     public void doPost(Request request, Response response) throws Exception { 
  13.         String repText = "<h1>LoginServlet by POST method</h1>"
  14.         response.output(HttpProtocolUtil.getHttpHeader200(repText.length()) + repText); 
  15.     } 
  16.  
  17.     @Override 
  18.     public void init() throws Exception { 
  19.     } 
  20.  
  21.     @Override 
  22.     public void destroy() throws Exception { 
  23.     } 

大家是否還記得,我們在學習Servlet的時候,在resources目錄下面有個web.xml。我們這個版本也把這個xml文件給引入。

  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <web-app> 
  3.     <servlet> 
  4.         <servlet-name>login</servlet-name
  5.         <servlet-class>com.tian.v4.LoginServlet</servlet-class> 
  6.     </servlet> 
  7.  
  8.     <servlet-mapping> 
  9.         <servlet-name>login</servlet-name
  10.         <url-pattern>/login</url-pattern> 
  11.     </servlet-mapping> 
  12. </web-app> 

既然引入了xml文件,那我們就需要去讀取這個xml文件,并解析器內容。所以這里我們需要引入兩個jar包。

  1. <dependencies> 
  2.     <dependency> 
  3.         <groupId>dom4j</groupId> 
  4.         <artifactId>dom4j</artifactId> 
  5.         <version>1.6.1</version> 
  6.     </dependency> 
  7.     <dependency> 
  8.         <groupId>jaxen</groupId> 
  9.         <artifactId>jaxen</artifactId> 
  10.         <version>1.1.6</version> 
  11.     </dependency> 
  12. </dependencies> 

萬事俱備,只欠東風了。這時候我們來吧MyTomcat這個類做一些調整即可。

下面有個很重要的initServlet()方法,剛剛是對應下面這張圖中的List servlets,但是我們代碼里使用的是Map來存儲Servlet的,意思就那么個意思,把Servlet放在集合里。

驚呆了!手寫4個mini版的Tomcat!

這也就是為什么大家都把Tomcat叫做Servlet容器的原因,其實真正的容器還是java集合。

  1. package com.tian.v4; 
  2.  
  3. import com.tian.v3.RequestV3; 
  4. import com.tian.v3.ResponseV3; 
  5. import org.dom4j.Document; 
  6. import org.dom4j.Element; 
  7. import org.dom4j.io.SAXReader; 
  8.  
  9. import java.io.IOException; 
  10. import java.io.InputStream; 
  11. import java.io.OutputStream; 
  12. import java.net.ServerSocket; 
  13. import java.net.Socket; 
  14. import java.util.HashMap; 
  15. import java.util.List; 
  16. import java.util.Map; 
  17.  
  18. public class MyTomcat { 
  19.     /** 
  20.      * 設定啟動和監聽端口 
  21.      */ 
  22.     private static final int PORT = 8090; 
  23.     /** 
  24.      * 存放 Servlet信息,url: Servlet 實例 
  25.      */ 
  26.     private Map<String, HttpServlet> servletMap = new HashMap<>(); 
  27.   
  28.     public void start() throws Exception { 
  29.  
  30.         System.out.println("my tomcat starting..."); 
  31.         initServlet(); 
  32.         ServerSocket socket = new ServerSocket(PORT); 
  33.         while (true) { 
  34.             Socket accept = socket.accept(); 
  35.             OutputStream outputStream = accept.getOutputStream(); 
  36.             // 分別封裝 RequestV3 和 ResponseV3 
  37.             RequestV4 requestV3 = new RequestV4(accept.getInputStream()); 
  38.             ResponseV4 responseV3 = new ResponseV4(outputStream); 
  39.             // 根據 url 來獲取 Servlet 
  40.             HttpServlet httpServlet = servletMap.get(requestV3.getUrl()); 
  41.             // 如果 Servlet 為空,說明是靜態資源,不為空即為動態資源,需要執行 Servlet 里的方法 
  42.             if (httpServlet == null) { 
  43.                 responseV3.outputHtml(requestV3.getUrl()); 
  44.             } else { 
  45.                 httpServlet.service(requestV3, responseV3); 
  46.             } 
  47.             accept.close(); 
  48.         } 
  49.     }  
  50.      
  51.     public static void main(String[] args) throws Exception { 
  52.         MyTomcat tomcat = new MyTomcat(); 
  53.         tomcat.start(); 
  54.     } 
  55.  
  56.  
  57.     /** 
  58.      * 解析web.xml文件,把url和servlet解析出來, 
  59.      * 并保存到一個java集合里(Map) 
  60.      */ 
  61.     public void initServlet() throws Exception { 
  62.         InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("web.xml"); 
  63.         SAXReader saxReader = new SAXReader(); 
  64.         Document document = saxReader.read(resourceAsStream); 
  65.         Element rootElement = document.getRootElement(); 
  66.         List<Element> list = rootElement.selectNodes("//servlet"); 
  67.         for (Element element : list) { 
  68.             // <servlet-name>show</servlet-name
  69.             Element servletnameElement = (Element) element.selectSingleNode("servlet-name"); 
  70.             String servletName = servletnameElement.getStringValue(); 
  71.             // <servlet-class>server.ShowServlet</servlet-class> 
  72.             Element servletclassElement = (Element) element.selectSingleNode("servlet-class"); 
  73.             String servletClass = servletclassElement.getStringValue(); 
  74.  
  75.             // 根據 servlet-name 的值找到 url-pattern 
  76.             Element servletMapping = (Element) rootElement.selectSingleNode("/web-app/servlet-mapping[servlet-name='" + servletName + "']"); 
  77.             // /show 
  78.             String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue(); 
  79.             servletMap.put(urlPattern, (HttpServlet) Class.forName(servletClass).getDeclaredConstructor().newInstance()); 
  80.         } 
  81.     } 

啟動,再次訪問http://localhost:8090/index.html

驚呆了!手寫4個mini版的Tomcat!

同時,我們可以訪問http://localhost:8090/login圖片

到此,第四個版本也搞定了。

但是前面四個版本都有一個共同的問題,全部使用的是BIO。

BIO:同步并阻塞,服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器端就需要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷,當然可以通過線程池機制改善。

所以,大家在網上看到的手寫tomcat的,也有使用線程池來做的,這里希望大家能get到為什么使用線程池來實現。另外,其實在tomcat高版本中已經沒有使用BIO了。

驚呆了!手寫4個mini版的Tomcat!

而 HTTP/1.1默認使用的就是NIO了。

但這個只是通信方式,重點是我們要理解和掌握tomcat的整體實現。

總結

 

另外,發現上面都是講配置文件解析,并將對應數據保存起來。熟悉這個套路后,大家是不是想到,我們很多配置項都是在server.xml中,還記得否?也是可以通過解析某個目錄下的server.xml文件,并把內容賦給java中相應的變量罷了。

比如:

1.server.xml中的端口配置,我們是在代碼里寫死的而已,改成MyTomcat啟動的時候去解析并獲取不久得了嗎?

2.我們通常是將我們項目的打成war,然后解壓到某個目錄下,最后還不是可以通過讀取這個解壓后的某個目錄中找到web.xml,然后用回到上面的web.xml解析了。

本文主要是分享如何從一個塑料版到黃金版、然后鉑金版,最后到磚石版??梢园鸭尤刖€程池的版本稱之為星耀版,最后把相關server.xml解析,以及讀取我們放入到tomcat中項目解析可以稱之為王者版。

技術點:Socket編程、InputStream、OutputStream、線程池、xml文件解析、反射。更高級版本中NIO,AIO等。

不是為了裝逼而來搞這個tomcat,而是為了我們更深刻的理解tomcat的原理。

原文地址:https://mp.weixin.qq.com/s/gu49D6O4LhcoZlHoOg5A8A

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 大象传媒短视频网站 | 免费观看成年肉动漫网站 | 91九色porny国产美女一区 | 午夜毛片在线观看 | 大桥未久aⅴ一区二区 | 国产精品一区二区不卡的视频 | 国产成+人+亚洲+欧美综合 | 欧美日韩1区 | 日韩大片免费观看 | 亚洲无人区乱码中文字幕 | 四缺一写的小说 | 亚洲视频在线观看免费视频 | 美女福利视频午夜在线 | 农村美女沟厕嘘嘘被偷看 | 亚洲色域网 | 国产日韩欧美精品在线 | 欧美一级欧美三级 | 国产乱子伦在线观看不卡 | 91传媒制片厂果冻有限公司 | 精品久久99麻豆蜜桃666 | 2018天天拍拍拍免费视频 | 91久| 国产全部理论片线观看 | 国产第一页在线视频 | 蝴蝶传媒3o45 | 亚洲欧美优优色在线影院 | 四虎影音 | 男女发生性关系视频 | 亚洲AV精品一区二区三区不卡 | 91女神在线观看 | 福利视频一区二区思瑞 | 国色天香视频完整版 | 日韩在线一区二区三区 | 国产成人精品一区二区不卡 | 精品久久一区 | 人人斗地主| 日韩妹妹 | blacked黑人hd2021| 香蕉久久夜色精品国产尤物 | 国产一区私人高清影院 | 91制片厂果冻传媒杨柳作品 |