【JAVA基础】实现Tomcat基本功能
文章目录
- TCP/IP协议
- Socket编程
- Servlet
- Tomcat
在搜索了两三天之后,也是大概弄懂了Tomcat是个什么东西,我们在说Tomcat之前,先来了解一下下面这三个东西:
TCP/IP协议
TCP/IP 是互联网通信的基础协议。TCP(传输控制协议)负责可靠的数据传输,IP(互联网协议)负责数据包的路由和地址定位。所有的网络通信,包括服务器和客户端之间的通信,都依赖于 TCP/IP 协议。包括五层结构,自上而下分别为:应用层、传输层、网络层、数据链路层、物理层
- 应用层:发送端想要发送数据,需要应用层准备好要发送的数据,直接与用户进行对接,之后交给传输层
- 传输层:传输层的主要作用是为发送端和接收端提供可靠的服务,举个例子,就像我们寄送快递时候的物流公司,确保我们的商品不受损坏
- 网络层:网络层负责选择数据传输的路线,应该走哪个路由器等等
- 数据链路层:选择好传输路径之后,由数据链路层将数据从一个路由器发送到另外一个路由器
- 物理层:可以理解为网线等等数据需要走的路线
Socket编程
百度百科上面对Socket的解释是:**套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议栈进行交互的接口。**我是这么理解的:Socket编程其实是应用程序进行数据传输的一种方式,它是TCP/IP的一种具体实现,计算机通过Socket协议区分数据应该输送到哪个具体的应用程序,Socket用于监听TCP/IP连接(例如:浏览器中的HTTP请求)
Servlet
Servlet包含于Tomcat中,实质上是一个Java类,是一种运行在支持Java应用服务器上的Web组件,它的作用是响应Socket监听到的HTTP请求,并做出相应处理。其中会包含一个HttpServlet类,是Servlet API的核心类,其自定义的Servlet都是该类的子类。
Tomcat
介绍完上面内容后,我们来看什么是Tomcat:Tomcat是一个基于 Socket 通信的 Java 应用服务器,专门用来运行 Java Servlet,也就是说Tomcat其实是Servlet的容器,它基于Socket通信来获取浏览器中的请求,并做出相应处理,将处理结果交给Servlet,让其做出响应,并将结果再反馈给客户端浏览器。下面是Tomcat运行的基本流程:

下面写一下代码实现:
我们先定义Servlet类,定义其doGet()和doPost()方法以便于对浏览器请求做出响应,service()方法用于判断浏览器的请求类型,并调用对应的方法
// HttpServlet接口 定义了Servlet中的核心方法
@WebServlet(url = "/Http")
public interface HttpServlet {// 接口中定义servlet类中的核心方法void service(Request request);void doGet(Request request) ;void doPost(Request request) ;
}// servlet类 继承接口并对接口中的方法进行实现
@WebServlet(url = "/first")
public class MyFirstServlet implements HttpServlet{// 对传入的请求方法进行判断,属于那种请求,调用响应的doGet或者doPost方法public void service(Request request){if ("GET".equalsIgnoreCase(request.getMethod())) {doGet(request);} else if ("POST".equalsIgnoreCase(request.getMethod())) {doPost(request);}}public void doGet(Request request){System.out.println("hello get1");}public void doPost(Request request){System.out.println("hello post1");}
}@WebServlet(url = "/second")
public class MySecondServlet implements HttpServlet{// 对传入的请求方法进行判断,属于那种请求,调用响应的doGet或者doPost方法public void service(Request request){if ("GET".equalsIgnoreCase(request.getMethod())) {doGet(request);} else if ("POST".equalsIgnoreCase(request.getMethod())) {doPost(request);}}public void doGet(Request request){System.out.println("hello get2");}public void doPost(Request request){System.out.println("hello post2");}
}
定义完Servlet类后,我们来看Tomcat服务器中的核心功能,我们将它分为五步完成:
-
扫描Servlet包下面的类,并获取到所有的类的全类名
要想让Tomcat将获取到的请求数据传输给
Servlet类,那就必须先获取到Servlet类的类信息,那么我们对目录进行扫描,并定位到Servlet类所在的文件目录:// 定义一个集合用于存储访问地址以及类对象 static Map<String, Class<?>> servletMaps = new HashMap<>(); // 定义一个集合用于存储类名 static List<String> classPaths = new ArrayList<>();public static void main(String[] args) throws IOException {// 查找servlet类名并存储searchClass(); }// 用于拼接Servlet包所在根目录,并递归进行查找 private static List<String> searchClass(){String basePack = "servlet"; // 包目录String classPath = MyTomcat.class.getResource("/").getPath(); // 获取文件所在的根目录basePack = basePack.replace(".", File.separator); // 将包名中的 . 替换为路径中的 \// 拼接完整地址String searchPath = classPath + basePack;// 递归通过路径获取类名doPath(new File(searchPath), classPath);// 将最后的集合值返回给main()方法return classPaths; }// 递归获取Servlet文件名 private static void doPath(File file, String classpath) {// 递归条件if (file.isDirectory()) { // 判断是否是文件夹,如果是就继续递归File[] files = file.listFiles();for (File f1 : files) {doPath(f1, classpath);}} else { // 如果是文件,就对名字进行处理,然后存储到classPaths集合中if (file.getName().endsWith(".class")) {String path = file.getPath().replace(classpath.replace("/", "\\").replaceFirst("\\\\", ""), "").replace("\\", ".").replace(".class", "");classPaths.add(path);}} }上面的代码中,
searchClass()方法用于初始化Servlet包所在的根目录,并调用doPath()方法,对目录进行进一步查找,直到找到我们需要的Servlet类文件 -
根据第一步获取到的全类名生成类对象
创建想对应的类对象之后,我们将类对象以及他的类名,用Key-Value键值对的形式存储到servletMap集合中,方便之后的使用
-
获取类上面注解的访问地址
我们知道浏览器发送的请求是需要
Servlet处理的,但是每一个请求都需要调用到对应的Servlet类才可以,所以我们获取到Servlet类上面的注解,用于之后的对比。下面是对应的二三步代码:
// 对存储着Servlet类名的集合进行扫描,创建servlet对象 for (String className : classPaths) {try {// 创建对应的servlet类对象Class<?> clazz = Class.forName(className);// 获取servlet类上面的注解内容WebServlet webServlet = clazz.getDeclaredAnnotation(WebServlet.class);// 存储在集合中servletMaps.put(webServlet.url(), clazz);} catch (ClassNotFoundException e) {throw new RuntimeException(e);} } -
如果请求内容和
@WebServlet当中的注解是相同的,那么生成Servlet对象这一步在实现的时候其实有点曲折,第一次我直接在
Tomcat类中想要创建Servlet对象,但是发现Request中存储的请求内容我是没法直接获取到的;于是第二次我又直接在Server类中去创建Servlet对象,但是这里没法获取到Servlet类对象信息;直到这个时候我才反应过来应该在Tomcat中创建阻塞监听,这样才能获取到请求方法,并创建对应的Servlet对象。// 定义一个Request对象用于存储请求信息 static Request request = new Request();// Request类 用于存储请求方法和请求内容 public class Request {String Method;String Url;public void setMethod(String setMethod) {this.Method = setMethod;}public void setUrl(String setUrl) {this.Url = setUrl;}public String getMethod() {return Method;}public String getUrl() {return Url;} }public static void main(String[] args) throws IOException {// 启动tomcat服务器start(4700); }// 启动tomcat服务器,其中对端口进行监听,并获取到请求信息 public static void start(int port) throws IOException {ServerSocket serverSocket = new ServerSocket(port);System.out.println("MyTomcat 启动,监听端口:" + port);while(true) {Socket socket = serverSocket.accept(); // 阻塞监听// 打开输入流,解析客户端发来的内容InputStream inputStream = socket.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); //将 01010这样的bit信息 转换为 字符数据String line = reader.readLine(); // 读取第一行,它包含了请求方法和请求路径等信息if (line != null && !line.isEmpty()){String requestContent = line.split(" ")[1]; // String requestMethod = line.split(" ")[0];request.setUrl(requestContent);request.setMethod(requestMethod);doRequest(request);}} }// 对Request类中存储的请求内容和方法进行处理和比对 public static void doRequest(Request request) {// 存储获取到的请求内容String requestUrl = request.getUrl();for (String servletKey : servletMaps.keySet()){// 判断获取到的请求信息是否和servlet类对象上面的注解名称一样,如果一样那么创建对应类信息if (servletKey.equals(requestUrl)){Class<?> servletClass = servletMaps.get(requestUrl);// System.out.println(servletClass); 做一个输出用于测试是否获取// 如果创建了对应的类对象,那么就开始创建对应的servlet对象,并调用其中的方法if (servletClass != null) {servletClass.newInstance(); // 创建servlet对象} else {System.out.println("404 Not Found: " + requestUrl);}}} }上面的
start()方法用于启动tomcat服务器,并监听端口,随时获取浏览器发送的请求,并对请求内容进行处理,将请求方法,和请求内容分别储存在Request类中的对象中,Request类用于存储浏览器中发来的请求,doRequest()方法对获取到的请求方法和请求内容进行处理和比对,并创建Servlet对象 -
根据浏览器请求调用Servlet类中的
doPost()和doGet()方法这一步我是搜了好多资料加上老师的提示才写出来的,最后这两步对于我这个初学者实在思考起来有点费劲,需要用到一些代理的知识,因为我们可以发现,在创建完
Servlet对象之后,我们没办法对这个对象进行存储,那么我们也就没法通过请求方法进行判断,调用servlet中对应的方法进行响应,我们只能是手动去调用方法。
那么我们可以使用代理,通过我们创建的HttpServlet接口来存储我们生成的Servlet对象,然后通过httpServlet对象调用service方法,来进行判断,并对请求做出响应。在这里,Tomcat相当于代理对象,Servlet相当于核心对象,通过Tomcat来代理调用到其中的doGet()和doPost()核心方法。为什么用代理?
我们可以发现创建的servlet类对象我们只能用Object类来接收,但是如果这样接收的话,我们也就无法调用到Servlet中的doGet等方法
所以我们让Servlet都继承同一个接口:HttpServlet,这样我们就有办法来存储这个创建的Servlet对象,并在其中判断我们传入的请求方法,进行判断,做出对应的响应。此时Tomcat属于一个代理类核心代码其实没多少,但是逻辑我感觉第一次实现的时候不是很好想:
try {// 通过接口来存储生成的Servlet对象HttpServlet httpServlet = (HttpServlet) servletClass.newInstance();// 假设 Servlet 类中有一个 service() 方法来处理请求,其中对doGet和doPost方法进行调用httpServlet.service(request); } catch (Exception e) {e.printStackTrace(); }
相关文章:
【JAVA基础】实现Tomcat基本功能
文章目录 TCP/IP协议Socket编程ServletTomcat 在搜索了两三天之后,也是大概弄懂了Tomcat是个什么东西,我们在说Tomcat之前,先来了解一下下面这三个东西: TCP/IP协议 TCP/IP 是互联网通信的基础协议。TCP(传输控制协议…...
风力发电叶片缺陷检测数据集
风力发电叶片缺陷检测数据集】nc: 4 names: [Burn Mark, Coating_defects, Crack, EROSION ] 名称:【烧伤痕迹, 涂层缺陷, 裂缝,侵蚀】共1095张,8:1:1比例划分,(train;876张,val:109张ÿ…...
数据类型自动转换的解决方案
数据类型自动转换的解决方案 java8、jdk8背景 为方便测试框架数据处理以及方便查看一些数据,弄了一个工具类,部分要点简要说明。 主要涉及到字符串与其他类型的相互转换,无其他类型之间的相互转换。 轻量测试框架实现与使用的总篇可见此文…...
大厂校招:唯品会Java面试题及参考答案
SortedSet 的原理 SortedSet 是一个有序的集合接口,它继承自 Set 接口。在 Java 中,常见的实现类有 TreeSet。 TreeSet 实现了 SortedSet 接口,它使用红黑树来维护集合中元素的有序性。红黑树是一种自平衡的二叉搜索树,具有以下特点: 每个节点要么是红色,要么是黑色。根节…...
Qt常用控件——QLCDNumber
文章目录 QLCDNumber核心属性倒计时小程序倒计时小程序相关问题 QLCDNumber核心属性 QLCDNumber是专门用来显示数字的控件,类似于这样: 属性说明intValue获取的数字值(int).value获取的数字值(double)和intValue是联动的例如value设为1.5,in…...
专业学习|GERT网络概览(学习资源、原理介绍、变体介绍)
一、GERT 网络概览 GERT(Graphical Evaluation Review Technique,图示评审技术)是一种结合流线图理论(Flow Graphical Theory)、矩母函数(Moment Generating Function)、计划评审技术(Program Evaluation Review Technique)解决随机网络问题的方法,描述各…...
搭建一个基于角色的权限验证框架
说明:基于角色的权限验证(Role-Based Access Control,RBAC)框架,是目前大多数服务端的登录校验框架。本文介绍如何快速搭建一个这样的框架,不用Shiro、Spring Security、Sa-Token这样的“大框架”实现。 R…...
下载chromedriver驱动
首先进入关于ChromeDriver最新下载地址:Chrome for Testing availability 进入之后找到与自己所匹配的,在浏览器中查看版本号,下载版本号需要一致。 下载即可,解压,找到 直接放在pycharm下即可 因为在环境变量中早已配…...
在STM32工程中使用Mavlink与飞控通信
本文讲述如何在STM32工程中使用Mavlink协议与飞控通信,特别适合自制飞控外设模块的项目。 需求来源: 1、增稳云台里的STM32单片机需要通过串口接收飞控传来的云台俯仰、横滚控制指令和相机拍照控制指令; 2、自制的有害气体采集器需要接收飞…...
【Elasticsearch】-7.17.24版本接入
官网 https://www.elastic.co/cn/downloads/elasticsearch 本项目基于windows环境下,其他环境操作类似 1、初始化配置 打开config/elasticsearch.yaml 添加如下配置 cluster.name: dams_clusternetwork.host: 127.0.0.1 http.port: 9200# 不开启geo数据库 inge…...
ShouldSniffAttr在自动化测试中具体是如何应用?
在自动化测试中,ShouldSniffAttr 这样的函数名通常暗示它是一个用于断言(assertions)的工具,用于检查某个元素或属性是否符合预期的条件。 虽然这不是一个标准的函数名,但我们可以根据命名推测其用途。 例如…...
前端vue3打印,多页打印,不使用插件(工作中让我写一个打印功能)
说下总体思路,创建一个组件,里面放多个span字段,然后根据父组件传入的参数,生成子组件,最好我们打印子组件的信息即可。通过我多次ai,探索最后成功了。 子组件代码 media print 这个我要讲一下ÿ…...
传感技术是如何实现实时监测和控制的呢
传感技术在力士乐拧紧系统中实现实时监测和控制的方式主要通过以下几个步骤进行: 一、传感器数据采集 1. 传感器种类: 力士乐拧紧系统中可能包含多种传感器,如力矩传感器、角度传感器和转速传感器等。这些传感器各自负责检测拧紧过程中的不…...
为什么mac打不开rar文件 苹果电脑打不开rar压缩文件怎么办
你是否遇到过这样的情况,下载了一个rar文件,想要查看里面的内容,却发现Mac电脑无法打开。rar文件是一种常见的压缩文件格式,它可以将多个文件或文件夹压缩成一个文件,节省空间和传输时间。如此高效实用的压缩文档&…...
linux下日志系统setvbuf接口及结构体 handle_file_t成员介绍
typedef struct handle_file_t {uint8_t *wkey;//用于存储写入文件时可能需要的加密密钥int cflag;//用于表示日志文件的某些配置标志,例如是否启用压缩、是否启用加密等char *file_path;//用于存储日志文件的路径FILE *…...
ESP8266+httpServer+GET+POST实现网页验证密码
1. 代码 #include "esp_http_server.h" #include "esp_log.h" #include "web_server.h"// 辅助宏,用于计算两个数中的较小值 #define MIN(a, b) ((a) < (b) ? (a) : (b))static const char *TAG "wifi web_server";c…...
git仓库修改ip,本地代码修改
只需求修改本地项目下面的.git文件夹下的config 替换ip即可...
轻便灵活,声学卓越,流动会场创新应用—轻空间
随着现代社会对高效、灵活场地需求的日益增加,传统建筑场馆的局限性逐渐显现。无论是大型会议、临时展览,还是文化活动,企业与组织往往需要一个既能快速搭建,又具备顶级声学效果的多功能场所。由轻空间打造的流动会场应运而生&…...
13 Midjourney从零到商用·进阶篇:灯光、角度与风格等精细控制方法
在前面我们了解了提示词的书写,那么如何利用提示词来精确控制生成画面的灯光、角度与风格 呢?在本篇文章中我么一起来探讨一下。 一、灯光 在摄影中,对灯光的要求都是非常高的。灯光能对人物、动物、物体、场景等进行修饰。每一种微小的的灯光…...
为什么要把raw转成yuv
将RAW图像数据转换为YUV格式在图像处理和视频编解码领域有多个重要的原因。以下是一些主要原因: 1. 标准化和兼容性 视频编解码标准:YUV格式是许多视频编解码标准(如H.264、H.265等)所使用的颜色空间。将RAW数据转换为YUV可以使…...
XML Group端口详解
在XML数据映射过程中,经常需要对数据进行分组聚合操作。例如,当处理包含多个物料明细的XML文件时,可能需要将相同物料号的明细归为一组,或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码,增加了开…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
【Go语言基础【12】】指针:声明、取地址、解引用
文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
