手写Tomcat:实现基本功能
首先,Tomcat是一个软件,所有的项目都能在Tomcat上加载运行,Tomcat最核心的就是Servlet集合,本身就是HashMap。Tomcat需要支持Servlet,所以有servlet底层的资源:HttpServlet抽象类、HttpRequest和HttpResponse,否则我们无法新建Servlet。
这样我们就可以在webapps写项目了,一个项目有两大资源:servlet资源和静态资源,servlet本身是java类,我们让它调用doGet和doPost方法,必须继承HttpServlet,同时也需要@WebServlet注解,那么在Tomcat中就必须要有@WebServlet注解的实现,如果没有@WebServlet,我们就无法拿到相应的注解。这样我们就能成功搭建起Servlet资源。
如果servlet集合在Tomcat启动之前实现,也就是main()方法之前,需要使用static代码块去实现;如果servlet集合在Tomcat启动之后实现,也就是main()方法之后,再去加载servlet容器。
当Http请求打过来之后,先打到socket上,处理Http请求,其本身就是连接器,从请求上能获取到请求路径和请求方法。先获取到请求路径,判断servlet容器中是否含有相同路径,如果有,再获取请求方法,判断是doGet还是doPost。

一、Servlet资源准备
1、Servlet接口:
- Servlet接口的作用:实现Servlet生命周期,定义init()、service(request,response)和destroy()方法。
- 接口中的方法全都是抽象方法,只定义不实现,方法头默认为public abstract。
import com.qcby.Servlet.req.HttpServletRequest;
import com.qcby.Servlet.req.HttpServletResponse;public interface Servlet {void init();void service(HttpServletRequest request, HttpServletResponse response) throws Exception;void destroy();
}
2、GenericServlet抽象类
- GenericServlet抽象类实现Servlet接口中的init()方法和destroy()方法。
为什么GenericServlet类是抽象类?
我们知道当一个普通类继承一个接口时,需要对接口中的所有方法进行实现,但这里我们不实现Servlet接口中的service(request,response)方法,因此我们需要把GenericServlet类变成抽象类,因为抽象类不必实现接口中的全部方法。
public abstract class GenericServlet implements Servlet {public void init(){System.out.println("初始化成功");}public void destroy(){System.out.println("销毁成功");}
}
3、HttpServlet抽象类
- HttpServlet抽象类实现Servlet接口中的service(request,response)方法
为什么HttpServlet类也是抽象类?
之所以HttpServlet类也是抽象类,是因为普通类中必须对方法进行实现,而在HttpServlet类中,实现service(request,response)方法的逻辑为:如果接收到GET请求,那么执行doGet方法;如果接收到POST请求,那么执行doPost方法。在此我们只需要对doGet和doPost方法进行定义不需要实现,所以HttpServlet只有成为抽象类,才不必实现doGet和doPost方法。
import com.qcby.Servlet.req.HttpServletRequest;
import com.qcby.Servlet.req.HttpServletResponse;public abstract class HttpServlet extends GenericServlet {//实现Servlet生命周期的service方法public void service(HttpServletRequest request, HttpServletResponse response) throws Exception {//如果接收到GET请求,那么执行doGet方法if(request.getMethod().equals("GET")){doGet(request,response);}//如果接收到POST请求,那么执行doPost方法else if(request.getMethod().equals("POST")){doPost(request,response);}}protected abstract void doGet(HttpServletRequest request,HttpServletResponse response) throws Exception;protected abstract void doPost(HttpServletRequest request,HttpServletResponse response)throws Exception;
}
4、HttpRequest类
- HttpRequest类实现请求路径和请求方法的获取与输出。
public class HttpServletRequest {private String path;private String method;public String getPath(){return path;};public void setPath(String path){this.path = path;}public String getMethod(){return method;}public void setMethod(String method){this.method = method;}
}
5、HttpResponse类
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;public class HttpServletResponse {private OutputStream outputStream;public HttpServletResponse(OutputStream outputStream){this.outputStream = outputStream;}public void writeServlet(String context) throws IOException{outputStream.write(context.getBytes());}
}
二、注解
- @Retention():表示该注解的作用阶段。阶段分三种:源代码阶段、类对象阶段和运行时阶段。
- @Target():表示该注解的作用范围。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;//作用阶段
@Retention(RetentionPolicy.RUNTIME)//作用在运行阶段//作用范围:类、方法......
@Target(ElementType.TYPE)//作用在类上public @interface WebServlet {String urlMapping() default "";//自定义的servlet路径
}
三、工具类
1、SearchClassUtil类
SearchUtil类的功能:扫描com.qcby.webapps包下的文件,获取全路径名
import java.io.File;
import java.util.ArrayList;
import java.util.List;/*
* 扫描com.qcby.webapps包下的文件,获取全路径名
* */
public class SearchClassUtil {public static List<String> classPaths = new ArrayList<String>();public static List<String> searchClass(){//需要扫描的包名String basePack = "com.qcby.webapps";//将获取到的包名转换为路径String classPath = SearchClassUtil.class.getResource("/").getPath();basePack = basePack.replace(".", File.separator);String searchPath = classPath + basePack;doPath(new File(searchPath),classPath);//这个时候我们已经得到了指定包下所有的类的绝对路径了。我们现在利用这些绝对路径和java的反射机制得到他们的类对象return classPaths;}/*** 该方法会得到所有的类,将类的绝对路径写入到classPaths中* @param file*/private static void doPath(File file,String classpath) {if (file.isDirectory()) {//文件夹//文件夹我们就递归File[] files = file.listFiles();for (File f1 : files) {doPath(f1,classpath);}} else {//标准文件//标准文件我们就判断是否是class文件if (file.getName().endsWith(".class")) {String path = file.getPath().replace(classpath.replace("/","\\").replaceFirst("\\\\",""),"").replace("\\",".").replace(".class","");//如果是class文件我们就放入我们的集合中。classPaths.add(path);}}}public static void main(String[] args) {List<String> classes = SearchClassUtil.searchClass();for (String s: classes) {System.out.println(s);}}
}
2、ResponseUtil类
public class ResponseUtil {public static final String responseHeader200 = "HTTP/1.1 200 \r\n"+"Content-Type:text/html; charset=utf-8 \r\n"+"\r\n";public static String getResponseHeader404(){return "HTTP/1.1 404 \r\n"+"Content-Type:text/html; charset=utf-8 \r\n"+"\r\n" + "404";}public static String getResponseHeader200(String context){return "HTTP/1.1 200 \r\n"+"Content-Type:text/html; charset=utf-8 \r\n"+"\r\n" + context;}
}
四、Servlet类
1、LoginServlet类
import com.qcby.Servlet.HttpServlet;
import com.qcby.Servlet.req.HttpServletRequest;
import com.qcby.Servlet.req.HttpServletResponse;
import com.qcby.Util.ResponseUtil;
import com.qcby.Util.WebServlet;import java.io.IOException;@WebServlet(urlMapping = "/login")
public class LoginServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {System.out.println("我是LoginServlet下的doGet方法");response.writeServlet(ResponseUtil.getResponseHeader200("hello"));}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) {System.out.println("我是LoginServlet下的doPost方法");}
}
五、ServletConfigMapping类
ServletConfigMapping类是Servlet容器,是Tomcat中最核心的部分,其本身是一个HashMap,其功能为:将路径和对象写入Servlet容器中。
import com.qcby.Servlet.HttpServlet;
import com.qcby.Util.SearchClassUtil;
import com.qcby.Util.WebServlet;import java.util.HashMap;
import java.util.List;
import java.util.Map;public class ServletConfigMapping {//创建servlet容器public static Map<String, HttpServlet> servletMap = new HashMap<>();//将Path和对象写入servlet容器当中//采用static代码块 在启动tomcat之前实现static{List<String> classesPath = SearchClassUtil.searchClass();for(String path:classesPath){try{//加载类Class clazz = Class.forName(path);//获取注解WebServlet webServlet = (WebServlet) clazz.getDeclaredAnnotation(WebServlet.class);HttpServlet servlet = (HttpServlet) clazz.newInstance();servletMap.put(webServlet.urlMapping(),servlet);} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {e.printStackTrace();}}}
}
六、MyTomcat
import com.qcby.Servlet.HttpServlet;
import com.qcby.Servlet.req.HttpServletRequest;
import com.qcby.Servlet.req.HttpServletResponse;import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;public class MyTomcat {static HttpServletRequest request = new HttpServletRequest();public static void main(String[] args) throws Exception {//ServletConfigMapping.init(); // tomcat启动,但是还没有监听之前,将信息加载入servlet容器当中//1.创建serversocket对象,持续监听8080端口ServerSocket serverSocket = new ServerSocket(8888);while (true){//accept():阻塞监听 ,当代码执行到这一样,如果没有数据到来,那么循环阻塞在这里。如果有数据到来,就继续向下执行Socket socket = serverSocket.accept();InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream();HttpServletResponse response = new HttpServletResponse(outputStream);int count = 0;while (count == 0){count = inputStream.available();}byte[] bytes = new byte[count];inputStream.read(bytes);String Context = new String(bytes);System.out.println(Context);//解析数据if(Context.equals("")){System.out.println("你输入了一个空请求");}else {String firstLine = Context.split("\\n")[0];request.setMethod(firstLine.split("\\s")[0]);request.setPath(firstLine.split("\\s")[1]);}//如果我们访问的路径在servlet容器当中存在if(ServletConfigMapping.servletMap.containsKey(request.getPath())){HttpServlet servlet = ServletConfigMapping.servletMap.get(request.getPath());servlet.service(request,response);}}}
}
相关文章:
手写Tomcat:实现基本功能
首先,Tomcat是一个软件,所有的项目都能在Tomcat上加载运行,Tomcat最核心的就是Servlet集合,本身就是HashMap。Tomcat需要支持Servlet,所以有servlet底层的资源:HttpServlet抽象类、HttpRequest和HttpRespon…...
C#变量与变量作用域详解
一、变量基础 1. 声明与初始化 声明语法:<数据类型> <变量名>(如 int age; string name)初始化要求: 1、 类或结构体中的字段变量(全局变量)无需显式初始化,默认值…...
SV学习笔记——数组、队列
一、定宽数组 定宽数组是静态变量,编译时便已经确定其大小,其可以分为压缩定宽数组和非压缩定宽数组:压缩数组是定义在类型后面,名字前面;非压缩数组定义在名字后面。Bit [7:0][3:0] name; bit[7:0] name [3:0]; 1.1定宽数组声明 数组的声…...
API调试工具的无解困境:白名单、动态IP与平台设计问题
引言 你是否曾经在开发中遇到过这样的尴尬情形:你打开了平台的API调试工具,准备一番操作,结果却发现根本无法连接到平台?别急,问题出在调试工具本身。今天我们要吐槽的就是那些神奇的开放平台API调试工具,…...
Git清理本地残留的、但已经在服务器上被删除的分支
要筛选出已经被服务器删除的本地分支,并在本地删除这些分支,可以按照以下步骤进行操作: 步骤 1: 获取远程分支信息,确保本地的远程分支信息是最新的: git fetch -p步骤 2: 列出本地分支和远程分支: git …...
HTTPS实现内容加密的逻辑
加密过程 使用非对称加密,网站生成公钥和私钥浏览器获取到网站公钥(通过验证和解析CA证书),随即生成一串字符串,然后使用公钥加密,发送给网站。网站用私钥将加密内容解析,然后使用这串字符串对…...
使用vue3.0+electron搭建桌面应用并打包exe
使用vue3.0electron搭建桌面应用并打包exe_如何使用electron将vue3vite开发完的项目打包成exe应用程序-CSDN博客...
JSAR 基础 1.2.1 基础概念_空间小程序
JSAR 基础 1.2.1 基础概念_空间小程序 空间空间自由度可嵌入空间空间小程序 最新的技术进展表明,官网之前的文档准备废除了,基于xsml的开发将退出历史舞台,three.js和普通web结合的技术将成为主导。所以后续学习请移步three.js学习路径&#…...
mysql练习
创建数据库db_ck,再创建表t_hero,将四大名著中的主要人物都插入这个表中,将实现过程中sql提交上上来 1、创建数据库db_ck mysql> create database db_ck; 2、创建表t_hero mysql> use db_ck Database changed mysql> create table …...
2025年2月平价旗舰手机性能对比
1、荣耀Magic7 点评:缺席潜望式长焦,3X直立长焦体验还行。兼顾性能、游戏、屏幕、影像、续航、快充等诸多方面,且外围配置比较齐全。 2、vivo x200 点评:潜望式长焦相机,拍照效果好,30W无线充电着实鸡肋&a…...
基于Spring Boot的扶贫助农系统的设计与实现(LW+源码+讲解)
专注于大学生项目实战开发,讲解,毕业答疑辅导,欢迎高校老师/同行前辈交流合作✌。 技术范围:SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容:…...
物联网中如何增加其可扩展性 协议 网络 设备 还包括软件层面上的
物联网(IoT)系统的可扩展性是指系统能够随着设备数量、数据流量和业务需求的增长而灵活扩展的能力。为了增加物联网的可扩展性,需要从协议、网络、设备和软件等多个层面进行优化和设计。以下是一些具体的策略和方法: 1. 协议层面的可扩展性 1.1 采用轻量级协议 轻量级协议…...
基于DeepSeek与搜索引擎构建智能搜索摘要工具
基于DeepSeek与搜索引擎构建智能搜索摘要工具 1. 项目概述 本项目通过整合DuckDuckGo搜索引擎与DeepSeek大语言模型,实现了一个智能搜索摘要生成工具。系统可自动执行以下流程: 输入查询语句进行全网搜索获取并解析搜索结果调用AI模型生成结构化摘要输出带来源标注的专业级…...
SQL 简介
SQL 简介 引言 结构化查询语言(Structured Query Language,简称 SQL)是一种用于数据库管理和操作的标准查询语言。它广泛应用于各个领域的数据库管理系统(DBMS)中,用于存储、检索和管理数据。SQL 不仅是数…...
BLUEM2引擎源码2025最新版
BLUE 引擎解析:传奇私服圈中的热门引擎 一、BLUE 引擎简介 BLUE 引擎是传奇私服圈子中较为知名的一款游戏引擎,它在传统的传奇引擎基础上进行了优化和扩展,使得私服开发者可以更加方便地搭建和管理服务器。相比于早期的 GEE、LEG、Hero 等引…...
pytest结合allure
Allure 一、文档二、指令三、装饰器3.1 allure.step装饰器3.2 allure.description装饰器3.3 allure.title装饰器3.4 allure.link、allure.issue 和 allure.testcase装饰器3.5 allure.epic、allure.feature 和 allure.story装饰器3.6 allure.severity装饰器 一、文档 allure文档…...
【渗透测试】基于时间的盲注(Time-Based Blind SQL Injection)
发生ERROR日志告警 查看系统日志如下: java.lang.IllegalArgumentException: Illegal character in query at index 203: https://api.weixin.qq.com/sns/jscode2session?access_token90_Vap5zo5UTJS4jbuvneMkyS1LHwHAgrofaX8bnIfW8EHXA71IRZwsqzJam9bo1m3zRcSrb…...
Gateway:网关路由与登录鉴权
在微服务架构中,用户登录和身份校验的处理方式确实与单体应用有所不同。在单体架构中,一旦用户通过身份验证,其会话信息可以在整个应用范围内共享,所有模块都能访问到用户信息。然而,在微服务架构下,每个服…...
本地部署DeepSeek R1大数据模型知识库
DeepSeek-V3 的综合能力 DeepSeek-V3 在推理速度上相较历史模型有了大幅提升。在目前大模型主流榜单中,DeepSeek-V3 在开源模型中位列榜首,与世界上最先进OpenAI 闭源模型不分伯仲。 1、下载Ollama运行大数据库 Ollama支持 Llama 3.3, DeepSeek-R1, Phi-…...
使用 Python 开发的简单招聘信息采集系统
以下是一个使用 Python 开发的简单招聘信息采集系统,它包含用户登录、招聘信息收集和前后端交互的基本功能。我们将使用 Flask 作为后端框架,HTML 作为前端页面。 项目结构 recruitment_system/ ├── app.py ├── templates/ │ ├── login.html │ ├── index…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)
一、数据处理与分析实战 (一)实时滤波与参数调整 基础滤波操作 60Hz 工频滤波:勾选界面右侧 “60Hz” 复选框,可有效抑制电网干扰(适用于北美地区,欧洲用户可调整为 50Hz)。 平滑处理&…...
中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
Spring Boot面试题精选汇总
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉 📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息 文章目录 Spring Boot面试题精选汇总⚙️ **一、核心概…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
