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

手写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。

相关文章:

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

TomcatRoute类 TomcatRoute类是Servlet容器&#xff0c;是Tomcat中最核心的部分&#xff0c;其本身是一个HashMap&#xff0c;其功能为&#xff1a;将路径和对象写入Servlet容器中。 package com.qcby.config;import com.qcby.Util.SearchClassUtil; import com.qcby.servlet…...

Spring Cloud Seata 快速入门及生产实战指南

文章目录 前言一、快速入门&#xff08;AT模式&#xff09;二、生产环境实战要点总结 前言 上一篇博客带大家深入解析Seata的核心原理及架构&#xff0c;理解了“为什么需要分布式事务”以及“Seata如何解决数据一致性问题”&#xff0c;相信大家已经对分布式事务的理论框架有…...

电商平台自动化

为什么要进行独立站自动化 纯人工测试人力成本高&#xff0c;相对效率低 回归测试在通用模块重复进行人工测试&#xff0c;测试效率低 前期调研备选自动化框架&#xff08;工具&#xff09;&#xff1a; Katalon Applitools Testim 阿里云EMAS Playwright Appium Cypress 相关…...

Java微服务架构实战:Spring Boot与Spring Cloud的完美结合

Java微服务架构实战&#xff1a;Spring Boot与Spring Cloud的完美结合 引言 随着云计算和分布式系统的快速发展&#xff0c;微服务架构已成为现代软件开发的主流模式。Java作为企业级应用开发的核心语言&#xff0c;结合Spring Boot和Spring Cloud&#xff0c;为开发者提供了…...

王树森推荐系统公开课 召回11:地理位置召回、作者召回、缓存召回

GeoHash 召回 属于地理位置召回&#xff0c;用户可能对附近发生的事情感兴趣。GeoHash 是一种对经纬度的编码&#xff0c;地图上每个单位矩形的 GeoHash 的前几位是相同的&#xff0c;GeoHash 编码截取前几位后&#xff0c;将相同编码发布的内容按时间顺序&#xff08;先是时间…...

无刷直流水泵构成及工作原理详解--【其利天下技术】

无刷直流水泵是相对于有刷直流泵而言的。 一&#xff1a;无刷直流水泵简介 无刷直流水泵即BLDC PUMP&#xff0c;其中“BL”意为“无刷”&#xff0c;DC即直流电机。 无刷直流水泵(BLDC PUMP)以电子换向器取代了机械换向器&#xff0c;所以无刷直流水泵既具有直流电机良好的调…...

less中使用 @supports

在Less中使用supports supports 是CSS的条件规则&#xff0c;用于检测浏览器是否支持特定的CSS属性或值。在Less中&#xff0c;你可以像在普通CSS中一样使用supports&#xff0c;同时还能利用Less的特性来增强它。 基本用法 /* 检测浏览器是否支持display: flex */ supports …...

大数据:新能源汽车宇宙的未来曲率引擎

** 发布日期&#xff1a;2025-05-14** 关键词&#xff1a;大数据、新能源、机器学习、碳中和、CSDN爆款 1. 大数据科普&#xff1a;定义、特征与技术核心 1.1 什么是大数据&#xff1f; 大数据&#xff08;Big Data&#xff09;指规模巨大、类型多样、生成速度快且价值密度低…...

【Java ee】关于抓包软件Fiddler Classic的安装与使用

Web Debugging Proxy Tool | Fiddler Classic 安装网站↑ 下载好安装包之后&#xff0c;双击一路next就可以了 一、抓包软件 电脑上安装了抓包软件之后&#xff0c;抓包软件就可以监听你的网卡上通过的数据。 本来是你的客户端通过网卡&#xff0c;把数据发给目标服务器&a…...

第五部分:第五节 - Express 路由与中间件进阶:厨房的分工与异常处理

随着你的 Express 应用变得越来越大&#xff0c;所有的路由和中间件都写在一个文件里会变得难以管理。这时候就需要将代码进行拆分和组织。此外&#xff0c;一个健壮的后端应用必须能够优雅地处理错误和一些常见的 Web 开发问题&#xff0c;比如跨域。 路由模块化 (express.Ro…...

在 CentOS 7.9 上部署 node_exporter 并接入 Prometheus + Grafana 实现主机监控

文章目录 在 CentOS 7.9 上部署 node_exporter 并接入 Prometheus Grafana 实现主机监控环境说明node_exporter 安装与配置下载并解压 node_exporter创建 Systemd 启动服务验证服务状态验证端口监听 Prometheus 配置 node_exporter 监控项修改 prometheus.yml重新加载 Prometh…...

C++--内存管理

内存管理 1. C/C内存分布 在C语言阶段&#xff0c;常说局部变量存储在栈区&#xff0c;动态内存中的数据存储在堆区&#xff0c;静态变量存储在静态区&#xff08;数据段&#xff09;&#xff0c;常量存储在常量区&#xff08;代码段&#xff09;&#xff0c;其实这里所说的栈…...

Java实现PDF加水印功能:技术解析与实践指南

Java实现PDF加水印功能&#xff1a;技术解析与实践指南 在当今数字化办公环境中&#xff0c;PDF文件因其跨平台兼容性和格式稳定性而被广泛应用。然而&#xff0c;为了保护文档的版权、标记文档状态&#xff08;如“草稿”“机密”等&#xff09;或增加文档的可追溯性&#xf…...

Django + Celery 打造企业级大模型异步任务管理平台 —— 从需求到完整实践(含全模板源码)

如需完整工程文件(含所有模板),可回复获取详细模板代码。 面向人群:自动化测试工程师、企业中后台开发人员、希望提升效率的 AI 业务从业者 核心收获:掌握 Django 三表关系设计、Celery 异步任务实践、基础 Web 交互与前后端分离思路,源码可直接落地,方便二次扩展 一、系…...

TC3xx学习笔记-UCB BMHD使用详解(二)

文章目录 前言Confirmation的定义Dual UCB: Confirmation StatesDual UCB: Errored State or ECC Error in the UCB Confirmation CodesECC Error in the UCB ContentDual Password UCB ORIG and COPY Re-programming UCB_BMHDx_ORIG and UCB_BMHDx_COPY (x 0-3)BMHD Protecti…...

用Python实现数据库数据自动化导出PDF报告:从MySQL到个性化文档的全流程实践

本文将介绍如何使用Python构建一个自动化工具&#xff0c;实现从MySQL数据库提取员工数据&#xff0c;并为每位员工生成包含定制化表格的PDF报告。通过该方案&#xff0c;可显著提升数据导出效率&#xff0c;避免手动操作误差&#xff0c;同时支持灵活的格式定制。 需求&#…...

实战设计模式之状态模式

概述 作为一种行为设计模式&#xff0c;状态模式允许对象在其内部状态改变时&#xff0c;改变其行为。这种模式通过将状态逻辑从对象中分离出来&#xff0c;并封装到独立的状态类中来实现。每个状态类代表一种特定的状态&#xff0c;拥有自己的一套行为方法。当对象的状态发生变…...

人工智能、机器学习与深度学习:概念解析与内在联系

人工智能、机器学习与深度学习&#xff1a;概念解析与内在联系 一、人工智能&#xff08;Artificial Intelligence, AI&#xff09; &#xff08;一&#xff09;人工智能的定义 人工智能的定义随着技术发展不断演变。从广义上讲&#xff0c;人工智能是指通过计算机技术实现的…...

什么是着色器 Shader

本人就是图形学结课了&#xff0c;对 OpenGL着色器还有很多疑问嘿嘿 文章目录 为什么要有着色器vshaderfshader 本文围绕 vshader 和 fshader 代码示例讲解。 &#xff08;着色器代码取自本人简单OpenGL项目 https://github.com/DBWGLX/-OpenGL-3D-Lighting-and-Shadow-Modeli…...

Redis的主从架构

主从模式 全量同步 首先主从同步过程第一步 会先比较replication id 判断是否是第一次同步假设为第一次同步 那么就会 启动bgsave异步生成RDB 同时fork子进程记录生成期间的新数据发送RDB给从节点 清空本地数据写入RDB 增量同步 对比ReplicationID不同因此选择增量同步在Rep…...

博客系统功能测试

博客系统网址&#xff1a;http://8.137.19.140:9090/blog_list.html 主要测试内容 功能测试、界面测试、性能测试、易用性测试、安全测试、兼容性测试、弱网测试、安装卸载测试、压力测试… 测试方法及目的 利用selenium和python编写测试脚本&#xff0c;对博客系统进行的相关…...

【深度学习新浪潮】什么是多模态大模型?

多模态大模型是人工智能领域的前沿技术方向,它融合了多种数据模态(如文本、图像、语音、视频、传感器数据等),并通过大规模参数模型实现跨模态的联合理解与生成。简单来说,这类模型就像人类一样,能同时“看”“听”“读”“说”,并将不同信息关联起来,完成复杂任务。 …...

机器学习前言2

1.机器学习 2.机器学习模型 3.模型评价方法 4.如何选择合适的模型 介绍 机器学习&#xff08;Machine Learning, ML&#xff09;是人工智能&#xff08;AI&#xff09;的核心分支&#xff0c;致力于通过数据和算法让计算机系统自动“学习”并改进性能&#xff0c;而无需显式编…...

【成品设计】基于Arduino的自动化农业灌溉系统

《基于STM32的单相瞬时值反馈逆变器》 硬件设计&#xff1a; ESP-C3最小系统板&#xff1a;主控芯片&#xff0c;内部集成wifi。土壤湿度传感器&#xff1a;采集土壤湿度。温度传感器&#xff1a;采集土壤温度。水泵模块&#xff1a;水泵继电器软管。按键3个&#xff1a;参数…...

前端页面 JavaScript数据交互

前言&#xff1a;学习JavaScript为前端设置动态效果&#xff0c;实现交互。JavaScript是一种广泛应用于网页开发的脚本语言&#xff0c;它能够使网页变得更加动态和交互性。作为一种客户端脚本语言&#xff0c;JavaScript可以被嵌入到HTML中&#xff0c;并且可以被所有现代的网…...

esp32课设记录(三)mqtt通信记录 附mqtt介绍

目录 安装mqttx&#xff08;云端部署&#xff09; 安装mosquitto&#xff08;本地部署&#xff09; 编程&#xff0c;连接wifi 编程&#xff0c;连接mqtt&#xff0c;实现数据接收 实际效果展示&#xff1a; 附录&#xff1a;mqtt介绍 工作流程简述&#xff1a; 工作流…...

string类(详解)

【本节目标】 1. 为什么要学习string类 2. 标准库中的string类 3. string类的模拟实现 4. 扩展阅读 1. 为什么学习string类&#xff1f; 1.1 C语言中的字符串 C 语言中&#xff0c;字符串是以 \0 结尾的一些字符的集合&#xff0c;为了操作方便&#xff0c; C 标准库中提供…...

MATLAB | R2025a 更新了哪些有趣的东西?

千呼万唤始出来&#xff0c;MATLAB R2025A 来见面&#xff0c;这次更新比往常晚了两个月&#xff0c;让我们看看更了哪些好玩的新东西叭&#xff1a;首先下载更新启动一气呵成&#xff0c;映入眼帘的是&#xff1a; 1 基本界面 基本界面变得和 MATLAB 网页版一模一样了&#…...

前缀和——和为K的子数组

作者感觉本题稍稍有点难度&#xff0c;看了题解也思考了有一会TWT 显然&#xff0c;暴力我们是不可取的&#xff0c;但这里我们可以采取一种新的遍历数组形式&#xff0c;从后向前&#xff0c;也就是以i位置为结尾的所有子数组&#xff0c;这个子数组只统计i位置之前的。 然后…...

React 第四十二节 Router 中useLoaderData的用途详解

一、前言 useLoaderData&#xff0c;用于在组件中获取路由预加载的数据。它通常与路由配置中的 loader 函数配合使用&#xff0c;用于在页面渲染前异步获取数据&#xff08;如 API 请求&#xff09;&#xff0c;并将数据直接注入组件&#xff0c;从而简化数据流管理。 二、us…...