实现自己的Tomcat、Servlet、多线程(线程池)处理请求

手写Tomcat,我们起名叫Minicat,完成以下功能,作为一个服务器软件提供服务,可以通过浏览器发送http请求,Minicat可以接收到请求进行处理,处理之后结果返回给客户端
  1. 提供服务,接收请求(Socket通信)
  2. 请求信息封装成Request对象(Respnse对象)
  3. 客户端请求资源,资源分为静态资源(html)和动态资源(Servlet)
  4. 资源返回给客户端浏览器
由简单到复杂,我们将其分为4个版本1.0,2.0,3.0,multithreading
  1. 1.0版本:浏览器请求http://localhost:8080,返回一个固定的字符串到页面"Hello Minicat!!!"
  2. 2.0版本:封装Request和Response对象,返回html静态资源文件
  3. 3.0版本:处理返回动态资源Servlet
  4. multithreading: 多线程版
源码(Gitee码云):https://gitee.com/yin_zhipeng/implement-_tomcat_of_myself.git
准备工作

1. 建立maven项目引入依赖
在这里插入图片描述

<build>
    <plugins>
        <!--指定编译级别-->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId><!--加个插件-->
            <version>3.1</version>
            <configuration>
                <source>8</source><!--JDK-->
                <target>8</target><!--编译-->
                <encoding>utf-8</encoding><!--编码-->
            </configuration>
        </plugin>
    </plugins>
</build>

一、Minicat1.0版本

实现浏览器请求http://localhost:8080,返回一个固定的字符串到页面"Hello Minicat!!!"

1. 提供服务,接收请求(Socket通信)

1. 首先玩Socket需要定义一个端口号,Tomcat是配在web.xml文件中,为了代码简洁我们直接定义主类里,后面自己实现Servlet的时候,会用web.xml解析Servlet

在这里插入图片描述

2. 有了端口号,想要程序启动,需要做一些初始化的程序,比如启动socket,我们将其封装到方法中

在这里插入图片描述

3. main函数测试

在这里插入图片描述

  1. 网页提示响应无效ERR_INVALID_HTTP_RESPONSE错误的HTTP响应
  2. http协议规定了,我们请求和响应的请求/响应头、请求/响应体
  3. 格式不正确的话,浏览器没法正常解析

2. 响应信息封装成Respnse对象(http)

1. 我们将响应头信息,封装成一个工具类(只简单提供响应码为200和404的情况)
  1. 我们先看下百度的响应头
    在这里插入图片描述
  2. 封装自己的,我们只封装必须的一些参数
    在这里插入图片描述
2. 修改响应内容,带上响应头

在这里插入图片描述

3. main测试

在这里插入图片描述

二、Minicat2.0版本

封装Request和Response对象,返回html静态资源文件
  1. 为了加以区分,我将各版本分开存放
    在这里插入图片描述

1. 获取请求信息

  1. 修改start()方法,根据InputStream获取信息
    在这里插入图片描述
  2. 测试
    在这里插入图片描述

2. 封装Request和Response

1. 封装Request获取请求方式和url,封装Response,根据url获取静态html文件,输出
  1. Request
    在这里插入图片描述
    在这里插入图片描述
  2. 封装Response对象之前,我们要响应静态资源,可以单独将处理静态资源的逻辑封装成工具类
    在这里插入图片描述
    在这里插入图片描述
  3. 封装Response对象
    在这里插入图片描述
    在这里插入图片描述
2. 编写index.html,用户请求后,将html输出
  1. 修改start()方法,调用我们封装好的工具类
    在这里插入图片描述
  2. 编写html,运行Minicat,保证html页面被编译
    在这里插入图片描述
    在这里插入图片描述

三、Minicat3.0版本

处理返回动态资源Servlet
  1. 为了加以区分,我将各版本分开存放
    在这里插入图片描述

1. 实现自己的Servlet

  1. Servlet接口,制定servlet基本规范
    在这里插入图片描述
  2. HttpServlet抽象类,对servlet做一定抽象封装
    在这里插入图片描述
  3. 自己写Servlet,处理业务
    在这里插入图片描述
    在这里插入图片描述

2. 加载解析Servlet配置(web.xml)

  1. web.xml
    在这里插入图片描述
  2. 添加依赖
    在这里插入图片描述
  3. 重写Minicat启动类,添加一个map存储url和Servlet类的映射,添加解析处理xml文件配置的方法
    在这里插入图片描述
    在这里插入图片描述

3. 接收处理请求,测试

  1. 改造start()方法,判断请求url,如果是Servlet映射,就是动态请求,否则就是请求静态资源
    在这里插入图片描述
  2. 启动Minicat测试
    在这里插入图片描述

四、解析问题,多线程改造

对于多线程不了解的同学可以粗略浏览下我们另外两篇文章
  1. 线程基本知识:https://blog.csdn.net/grd_java/article/details/109680187
  2. JUC锁,一些面试题和源码讲解:https://blog.csdn.net/grd_java/article/details/112979163
  3. 高并发多线程容器,线程池:https://blog.csdn.net/grd_java/article/details/113116244
  1. 为了加以区分,我将各版本分开存放
    在这里插入图片描述
    在这里插入图片描述

1. Minicat3.0的问题

我们希望,每个用户访问Minicat,是独立的,互不影响的,不能出现用户2等待用户1的情况
  1. 下面我们模拟两个用户同时访问服务器
  2. 用户A先请求/myServlet,但是处理时间有些长
  3. 用户B又来请求index.html,但是会因为用户A的请求没处理完,而等待
  1. 我们为Servlet添加一段代码Thread.sleep(100000);//休眠100000ms,模拟一个Servlet处理时间较长的情景
    在这里插入图片描述
  2. 我们请求/myServlet,因为线程休眠时间很长,所以我们在等待它运行完成
    在这里插入图片描述
  3. 我们再请求/index.html,此时访问静态资源,也需要等待前面的Servlet处理完成
    在这里插入图片描述
因为现在的Minicat,逻辑都是跑在主线程(main)中的,就是一个单线程,只能处理完一个,下一个才能继续处理
  1. 那么我们就让逻辑跑在多个线程中
  2. 也就是将start() 多线程化

2. 线程改造

1. 写一个线程类

在这里插入图片描述

2. 改造Minicat 的 start()方法

在这里插入图片描述

3. 测试

在这里插入图片描述

3. 使用线程池优化

每次来一个请求都创建一个线程出来,有点太过土豪,所以我们通过线程池管理线程,请求来了,从线程池拿线程,用完放回去,这样提高线程复用性
  1. 就像我们平常吃饭,每次用一次性筷子,太浪费木头了
  2. 一般家里的筷子都是用完洗,洗完放回收纳盒,下次接着用
1. 写一个方法,提供线程池
  1. 我用的线程池是ThreadPoolExecutor,我从以前写到文章截取这个线程池的解析
    在这里插入图片描述
  2. 提供一个方法,创建线程池ThreadPoolExecutor
    在这里插入图片描述
2. 使用线程池,改造start()方法

在这里插入图片描述

3. 测试

在这里插入图片描述

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

殷丿grd_志鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值