邏輯架構
?
-
HTTP 請求與 Socket:
- 左側的 “HTTP 請求” 箭頭指向 “socket”,表示客戶端發送的 HTTP 請求通過 socket 傳輸到服務器。Socket 負責接收請求,并提取出其中的?請求路徑(如?
/first
)和?請求方法(如 GET、POST),為后續處理做準備。
- 左側的 “HTTP 請求” 箭頭指向 “socket”,表示客戶端發送的 HTTP 請求通過 socket 傳輸到服務器。Socket 負責接收請求,并提取出其中的?請求路徑(如?
-
Servlet 容器的路由機制:
- 圖中粉色表格代表 Servlet 容器內的路由映射表,每一行記錄了一個 URL 路徑與對應 Servlet 對象的映射關系。例如,路徑?
/first
?對應?firstServlet
?對象,/second
?對應?secondServlet
?對象。容器根據 socket 提取的請求路徑,從映射表中找到匹配的 Servlet 來處理請求。
- 圖中粉色表格代表 Servlet 容器內的路由映射表,每一行記錄了一個 URL 路徑與對應 Servlet 對象的映射關系。例如,路徑?
-
Web 應用結構(webapps):
webapps
?是存放 Web 應用的目錄,圖中?myweb
?是其中一個應用,包含兩類資源:- Servlet 資源:動態處理請求的 Servlet 程序。
- 靜態資源:如 HTML、CSS、圖片等無需動態處理的文件。
-
核心類與注解支持:
- 右側藍色區域包含?
HttpServlet
?類、HttpRequest
?和?HttpResponse
,它們是處理請求和響應的核心類。HttpServlet
?是 Servlet 的基類,HttpRequest
?用于封裝請求信息,HttpResponse
?用于構造響應數據。 - 紫色區域表示對?
@WebServlet
?注解的支持。該注解用于配置 Servlet 對應的 URL 路徑等信息,簡化 Servlet 的注冊過程,與圖中路由映射表的功能相呼應。
- 右側藍色區域包含?
TomcatRoute類
package com.qcby.config;import com.qcby.Util.SearchClassUtil;
import com.qcby.servlet.Httpservlet;
import com.qcby.zj.YbyServlet;import java.util.HashMap;
import java.util.List;import java.util.List;
import java.util.Map;public class TomcatRoute {public static HashMap<String, Httpservlet> Route = new HashMap<>();static {List<String> classesPath = SearchClassUtil.searchClass();for (String path : classesPath) {try {//加載類Class clazz = Class.forName(path);//獲取注解YbyServlet webServlet = (YbyServlet) clazz.getDeclaredAnnotation(YbyServlet.class);
// 對象Object servlet = clazz.getDeclaredConstructor().newInstance();Route.put(webServlet.url(), (Httpservlet) servlet);
// Httpservlet servlet = (Httpservlet) clazz.newInstance();
// servletMap.put(webServlet.url(),servlet);System.out.println(Route);} catch (Exception e) {e.printStackTrace();}}}}
主要功能是自動掃描帶有特定注解的 Servlet 類并注冊到路由表中。使用靜態 HashMap 存儲路徑到 Servlet 的映射關系。加載類:Class.forName("com.qcby.servlet.HomeServlet")。
一、核心功能與設計思想
public class TomcatRoute {public static HashMap<String, Httpservlet> Route = new HashMap<>();static { ... }
}
功能:自動掃描并注冊所有帶有YbyServlet
注解的 Servlet 類
設計思想:
- 基于 "約定優于配置" 原則,通過注解簡化 Servlet 注冊
- 使用靜態代碼塊確保在類加載時完成初始化
- 采用單例模式管理 Servlet 實例(每個 Servlet 只有一個實例)
二、核心組件詳解
1. 路由注冊表
public static HashMap<String, Httpservlet> Route = new HashMap<>();
- 數據結構:靜態 HashMap 存儲路徑到 Servlet 的映射
- 鍵:URL 路徑(如
/user
),來自YbyServlet
注解的url()
屬性 - 值:實現了
Httpservlet
接口的 Servlet 實例
2. 類掃描機制
List<String> classesPath = SearchClassUtil.searchClass();
SearchClassUtil
功能:- 掃描指定包下的所有類
- 返回類的全限定名列表(如
["com.qcby.servlet.UserServlet", "com.qcby.servlet.OrderServlet"]
)
- 實現方式:
- 使用類加載器獲取資源路徑
- 遞歸遍歷所有
.class
文件 - 將文件路徑轉換為類的全限定名
HttpServletResponse類
package com.qcby.Response;import com.qcby.Request.HttpServletRequest;import java.io.IOException;
import java.io.OutputStream;public class HttpServletResponse {private OutputStream outputStream;public HttpServletResponse(OutputStream outputStream){this.outputStream = outputStream;}public void writeServlet(String context) throws IOException {outputStream.write(context.getBytes());}
}
這段代碼實現了 HTTP 響應的基礎功能,負責將服務器處理結果返回給客戶端
Tomcat
package com.qcby;
//tomcat主啟動類
import com.qcby.config.TomcatRoute;
import com.qcby.servlet.Httpservlet;
import com.qcby.Request.HttpServletRequest;
import com.qcby.Response.HttpServletResponse;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;public class Mytomcat {static HashMap<String,Httpservlet> routes= TomcatRoute.Route;public static void dispatch(HttpServletRequest request,HttpServletResponse response) throws IOException {Httpservlet servlet=routes.get(request.getPath());if(servlet!=null){servlet.service(request,response);}}public static void main(String[] args) {try {System.out.append("服務器啟動......");
// 1.定義ServerSocket對象進行服務器的端口注冊ServerSocket serverSocket = new ServerSocket(8080);while (true) {
// 2.監聽客戶端的socket鏈接程序Socket socket = serverSocket.accept();//阻塞監聽
// 3.從socket對象當中獲得一個字節流對象InputStream iStream = socket.getInputStream();HttpServletRequest request=new HttpServletRequest();BufferedReader reader=new BufferedReader(new InputStreamReader(iStream));String str=reader.readLine();request.setMethod(str.split("\\s")[0]);request.setPath(str.split("\\s")[1]);System.out.println(request.getMethod() + " " + request.getPath());OutputStream outputStream=socket.getOutputStream();HttpServletResponse response=new HttpServletResponse(outputStream);dispatch(request,response);}} catch(Exception e){e.printStackTrace();}}}