TomcatRoute类
TomcatRoute类是Servlet容器,是Tomcat中最核心的部分,其本身是一个HashMap,其功能为:将路径和对象写入Servlet容器中。
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();
}
}
}
}
静态代码块
1. 确保初始化时机
静态代码块在类加载时自动执行 ,且仅执行一次。这确保了路由表在程序启动时就被初始化,后续无需手动调用初始化方法。
对比其他初始化方式:
- 构造函数:每次创建对象时都会执行,而路由表只需初始化一次。
- 普通静态方法:需要手动调用,可能被遗忘或重复调用。
- 静态代码块:自动触发,保证全局唯一性。
2. 全局唯一性
静态代码块属于类,而非某个实例。无论创建多少个TomcatRoute对象,路由表只会初始化一次。
功能
- 自动扫描 :通过
SearchClassUtil.searchClass()扫描项目中的所有类。 - 注解识别 :使用
@YbyServlet注解标记需要注册的 Servlet。 - 路由映射 :将注解中的
url()值作为路径,对应的 Servlet 实例作为值,存入静态的Route映射表。 - 类加载时初始化:利用静态代码块在类加载时执行初始化逻辑,确保路由表在程序启动时就已准备好。
public static HashMap<String, Httpservlet> Route = new HashMap<>();
1. 多态性的应用
Httpservlet是所有具体 Servlet 的抽象父类 (或接口),通过父类类型引用子类实例,可以实现统一调用。
2. 解耦路由逻辑与具体实现
路由系统只需关注请求路径与处理逻辑的映射关系,而无需关心具体 Servlet 的实现细节。
3. 统一接口定义
Httpservlet通常定义了处理请求的标准方法(如service()、doGet()、doPost()),所有子类必须实现这些方法。
4. 符合 Servlet 规范
在标准 Java Web 开发中,所有 Servlet 都必须实现javax.servlet.Servlet接口(或继承HttpServlet)。这种设计模仿了标准 Servlet 容器的工作原理。
MyTomcat
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.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
public class Mytomcat {
static HashMap<String,Httpservlet> routes= TomcatRoute.Route;
static HttpServletRequest request=new HttpServletRequest();
static HttpServletResponse response=new HttpServletResponse();
public static void dispatch(){
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();
// 打印输出
int len = 0;
int ReviceLen = 0;
// 计算机网络数据是以8bit为一个单元进行发送,我们接收到发送方发生的byte数据
// 将其转化为utf-8格式输出
byte[] recvBuf = new byte[1024];
while ((ReviceLen = iStream.read(recvBuf)) != -1) {
String count=new String(recvBuf,0,ReviceLen,"UTF-8");
String method=count.split(" ")[0];
String url=count.split(" ")[1];
request.setMethod(method);
request.setPath(url);
}
dispatch();
}
} catch(Exception e){
// TODO: handle exception
}
}
}
1. 整体架构
这个简易服务器包含三个核心组件:
- Mytomcat:主服务器类,负责接收请求和分发。
- TomcatRoute:路由配置类,通过静态代码块扫描并注册所有 Servlet。
- Httpservlet:抽象 Servlet 基类,定义请求处理接口。
2. 核心成员变量
java
static HashMap<String,Httpservlet> routes = TomcatRoute.Route;
static HttpServletRequest request = new HttpServletRequest();
static HttpServletResponse response = new HttpServletResponse();
routes:从TomcatRoute获取的路由表,存储 URL → Servlet 的映射关系。request和response:静态全局对象,用于存储当前请求和响应信息。
3. 请求分发逻辑
java
public static void dispatch() {
Httpservlet servlet = routes.get(request.getPath());
if (servlet != null) {
servlet.service(request, response);
}
}
- 根据
request.getPath()从路由表中查找对应的 Servlet。 - 调用 Servlet 的
service()方法处理请求(多态调用)。
4. 主服务器逻辑
java
public static void main(String[] args) {
try {
System.out.println("服务器启动......");
ServerSocket serverSocket = new ServerSocket(8080);
while (true) {
// 1. 监听客户端连接(阻塞)
Socket socket = serverSocket.accept();
InputStream iStream = socket.getInputStream();
// 2. 解析HTTP请求
byte[] recvBuf = new byte[1024];
int ReviceLen = iStream.read(recvBuf);
String count = new String(recvBuf, 0, ReviceLen, "UTF-8");
String method = count.split(" ")[0];
String url = count.split(" ")[1];
// 3. 设置请求信息
request.setMethod(method);
request.setPath(url);
// 4. 分发请求
dispatch();
}
} catch (Exception e) {
e.printStackTrace();
}
}
关键步骤:
- 创建服务器套接字:监听 8080 端口。
- 接收客户端连接 :通过
serverSocket.accept()阻塞等待请求。 - 解析 HTTP 请求 :
- 读取请求头的第一行(格式:
GET /path HTTP/1.1)。 - 提取 HTTP 方法(如
GET)和请求路径(如/login)。
- 读取请求头的第一行(格式:
- 设置请求对象 :将解析结果存入静态
request对象。 - 分发请求 :调用
dispatch()方法查找并执行对应的 Servlet。