逻辑架构
HTTP 请求与 Socket:
- 左侧的 "HTTP 请求" 箭头指向 "socket",表示客户端发送的 HTTP 请求通过 socket 传输到服务器。Socket 负责接收请求,并提取出其中的 请求路径 (如
/first
)和 请求方法(如 GET、POST),为后续处理做准备。
Servlet 容器的路由机制:
- 图中粉色表格代表 Servlet 容器内的路由映射表,每一行记录了一个 URL 路径与对应 Servlet 对象的映射关系。例如,路径
/first
对应firstServlet
对象,/second
对应secondServlet
对象。容器根据 socket 提取的请求路径,从映射表中找到匹配的 Servlet 来处理请求。
Web 应用结构(webapps):
webapps
是存放 Web 应用的目录,图中myweb
是其中一个应用,包含两类资源:- Servlet 资源:动态处理请求的 Servlet 程序。
- 静态资源:如 HTML、CSS、图片等无需动态处理的文件。
核心类与注解支持:
- 右侧蓝色区域包含
HttpServlet
类、HttpRequest
和HttpResponse
,它们是处理请求和响应的核心类。HttpServlet
是 Servlet 的基类,HttpRequest
用于封装请求信息,HttpResponse
用于构造响应数据。 - 紫色区域表示对
@WebServlet
注解的支持。该注解用于配置 Servlet 对应的 URL 路径等信息,简化 Servlet 的注册过程,与图中路由映射表的功能相呼应。
TomcatRoute类
java
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")。
一、核心功能与设计思想
java
public class TomcatRoute {
public static HashMap<String, Httpservlet> Route = new HashMap<>();
static { ... }
}
功能 :自动扫描并注册所有带有YbyServlet
注解的 Servlet 类
设计思想:
- 基于 "约定优于配置" 原则,通过注解简化 Servlet 注册
- 使用静态代码块确保在类加载时完成初始化
- 采用单例模式管理 Servlet 实例(每个 Servlet 只有一个实例)
二、核心组件详解
1. 路由注册表
java
public static HashMap<String, Httpservlet> Route = new HashMap<>();
- 数据结构:静态 HashMap 存储路径到 Servlet 的映射
- 键 :URL 路径(如
/user
),来自YbyServlet
注解的url()
属性 - 值 :实现了
Httpservlet
接口的 Servlet 实例
2. 类扫描机制
java
List<String> classesPath = SearchClassUtil.searchClass();
SearchClassUtil
功能 :- 扫描指定包下的所有类
- 返回类的全限定名列表(如
["com.qcby.servlet.UserServlet", "com.qcby.servlet.OrderServlet"]
)
- 实现方式 :
- 使用类加载器获取资源路径
- 递归遍历所有
.class
文件 - 将文件路径转换为类的全限定名
HttpServletResponse类
java
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
java
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();
}
}
}