当前位置: 首页 > news >正文

手写tomcat:基本功能实现(3)

 TomcatRoute类

TomcatRoute类是Servlet容器,是Tomcat中最核心的部分,其本身是一个HashMap,其功能为:将路径和对象写入Servlet容器中。

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

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. 核心成员变量 

static HashMap<String,Httpservlet> routes = TomcatRoute.Route;
static HttpServletRequest request = new HttpServletRequest();
static HttpServletResponse response = new HttpServletResponse();
  • routes:从 TomcatRoute 获取的路由表,存储 URL → Servlet 的映射关系。
  • request 和 response:静态全局对象,用于存储当前请求和响应信息。

 3. 请求分发逻辑

public static void dispatch() {Httpservlet servlet = routes.get(request.getPath());if (servlet != null) {servlet.service(request, response);}
}
  • 根据 request.getPath() 从路由表中查找对应的 Servlet。
  • 调用 Servlet 的 service() 方法处理请求(多态调用)。

4. 主服务器逻辑

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();}
}

关键步骤

  1. 创建服务器套接字:监听 8080 端口。
  2. 接收客户端连接:通过 serverSocket.accept() 阻塞等待请求。
  3. 解析 HTTP 请求
    • 读取请求头的第一行(格式:GET /path HTTP/1.1)。
    • 提取 HTTP 方法(如 GET)和请求路径(如 /login)。
  4. 设置请求对象:将解析结果存入静态 request 对象。
  5. 分发请求:调用 dispatch() 方法查找并执行对应的 Servlet。

相关文章:

  • Java IO流进阶实战详解(含文件读写、拷贝、加密、字符集)
  • R语言空间数据处理入门教程
  • BC 范式与 4NF
  • AI日报 - 2024年5月17日
  • 【React中虚拟DOM与Diff算法详解】
  • 日期数据渲染转换问题
  • Animaster:一次由 CodeBuddy 主导的 CSS 动画编辑器诞生记
  • C++高级应用(1)-类型擦除(Type Erasure)和模板特化(Template Specialization)详解
  • aksharetools:大模型智能体框架agno可直接获取A股金融数据
  • [Mac] 开发环境部署工具ServBay 1.12.2
  • React Hooks 必须在组件最顶层调用的原因解析
  • 【机器人】复现 WMNav 具身导航 | 将VLM集成到世界模型中
  • Spring Boot 项目的计算机专业论文参考文献
  • 创建react工程并集成tailwindcss
  • React中useState中更新是同步的还是异步的?
  • 文件读取漏洞路径与防御总结
  • c++重要知识点汇总(不定期更新)
  • 机器学习 day04
  • leetcode 239. 滑动窗口最大值
  • gcc/g++常用参数
  • 墨西哥海军一载两百余人帆船撞上纽约布鲁克林大桥,多人落水
  • 海外市场,押注中国无人驾驶龙头
  • 新华每日电讯:博物馆正以可亲可近替代“高冷范儿”
  • 魔都眼|邮轮港国际帆船赛启动,120名中外选手展开角逐
  • 上海国际碳中和博览会下月举办,首次打造民营经济专区
  • 曾犯强奸罪教师出狱后办教培机构?柳州鱼峰区教育局回应