《HowTomcatWork》笔记总结(一)(上)

简介: 《HowTomcatWork》笔记总结(一)(上)

前言


这一篇是howTomcatWork的书籍笔记内容。下面是根据书中的内容做的一部分个人笔记。


书籍地址:


链接:pan.baidu.com/s/1jazo55sA…提取码:lp96 --来自百度网盘超级会员V6的分享


个人评价


没啥好说的,tomcat作者写的书,看了下海淘居然要500多确实吓到了。虽然代码使用的是tomcat5的版本,但是可以基本理解tomcat的内部工作机制。也可以看到作者是如何用一个十多行的肉鸡服务器代码不断升级成为现在的tomcat的模样。

本文是个人根据看书记录的一些笔记,中间逻辑不一定连贯,因为有些内容过于基础没有记录的价值,所以挑了一些个人关注的点。


一个最简单的Servlet是如何工作的


  1. 创建Request 对象,并且解析HTTP的请求信息,通过Request对象封装了这些信息的具体细节

具体接口:

javax.servlet.ServletRequest javax.servlet.http.ServletRequest

  1. 创建Response对象,封装了客户需需要的真正数据,封装了响应体的相关信息

javax.servlet.ServletResponsejavax.servlet.http.ServletResponse

  1. servlet的service 方法,根据此方法对于请求头进行解析,同时创建response将数据回传给客户端


tomcat的基本结构



Tomcat把服务器在大体上可以拆分为两部分,一部分叫做容器,另一部分叫做连接器


连接器


作用:接收到每一个 HTTP 请求构造一个 ==request== 和 ==response== 对象


容器


作用:接受连接器的请求根据service方法进行响应给对应的客户端

Tomcat 4 和 和  5的主要区别

  • Tomcat 5 支持 Servlet 2.4 和 JSP 2.0 规范,而 Tomcat 4 支持 Servlet 2.3 和 JSP 1.2。
  • 比起 Tomcat 4,Tomcat 5 有一些更有效率的默认连接器。
  • Tomcat 5 共享一个后台处理线程,而 Tomcat 4 的组件都有属于自己的后台处理线程。 因此,就这一点而言,Tomcat 5 消耗较少的资源。
  • Tomcat 5 并不需要一个映射组件(mapper component)用于查找子组件,因此简化了代码。


构建一个最简单的web程序



构建对象


下方的代码简单阅读即可,无需自己动手实验


HttpServer


用于构建一个服务器,同时建立serverSocket套接字等待链接

  • 调用httprequest.parse()方法

代码如下:


public class HttpServer {
    /**
     * 关闭容器的请求路径
     */
    private static final String SHUTDOWN = "/SHUTDOWN";
    /**
     * 静态资源根路径
     */
    public static final String WEBROOT = System.getProperty("user.dir") + File.separator + "webroot";
    /**
     * 是否关闭标识
     */
    private boolean SHUTDOWN_FLAG = false;
    public static void main(String[] args) {
        new HttpServer().await();
    }
    /**
     * 具体的server 方法,等待socket请求
     */
    public void await() {
        // 默认为8080端口
        int port = 8080;
        String host = "127.0.0.1";
        ServerSocket serverSocket = null;
        try {
            // 创建套接字
            serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }
        while (!SHUTDOWN_FLAG) {
            try {
                // 等待套接字
                Socket accept = serverSocket.accept();
                HttpRequest httpRequest = new HttpRequest(accept.getInputStream());
                // 处理请求数据
                httpRequest.parse();
                // 创建响应对象,处理响应信息
                HttpResponse httpResponse = new HttpResponse(accept.getOutputStream());
                // 设置静态资源
                httpResponse.setRequest(httpRequest);
                httpResponse.setResource();
                // 关闭的套接字
                accept.close();
                // 判断请求Url是否为 /shutdown
                SHUTDOWN_FLAG = httpRequest.getUri().equalsIgnoreCase(SHUTDOWN);
            } catch (IOException e) {
                e.printStackTrace();
                continue;
            }
        }
    }
}
复制代码


HttpRequest


以httpserver 的请求inputstream, 解析请求内容,分解请求uri

使用parse()方法解析请求信息,设置到stringbuffer里面

使用parseUri(str)截取请求信息的请求uri,设置到属性里面


public class HttpRequest {
    /**
     * 缓冲区的大小为 1M
     */
    private static final int BUFFER_COUNT = 1024;
    /**
     * 请求路径
     */
    private String uri;
    /**
     * 请求流
     */
    private InputStream inputStream;
    public HttpRequest(InputStream inputStream) {
        this.inputStream = inputStream;
    }
    /**
     * 解析inputstream 对于内容进行解析
     */
    public void parse() {
        // 字符串缓冲池
        StringBuffer stringBuffer = new StringBuffer(BUFFER_COUNT);
        byte[] byteBuffer = new byte[BUFFER_COUNT];
        if (inputStream == null) {
            System.err.println("未找到套接字");
            return;
        }
        int read = 0;
        try {
            // 读取数据到byte数组
            read = inputStream.read(byteBuffer);
        } catch (IOException e) {
            e.printStackTrace();
            System.exit(-1);
        }
        //读取byte数组的数据进入到stringbuffer
        for (int i = 0; i < read; i++) {
            stringBuffer.append((char)byteBuffer[i]);
        }
        // 打印stringbuffer
        System.err.println(stringBuffer.toString());
        // 获取uri
        uri = parseUri(stringBuffer.toString());
    }
    /**
     * 解析请求,获取请求Uri
     * @param requestString 需要处理的uri
     */
    public String parseUri(String requestString){
        // 建立index1 和 2
        int index1, index2;
        // 获取到第一个空行
        index1 = requestString.indexOf(' ');
        if(index1 != -1){
            // 从index1 开始找
            index2 = requestString.indexOf(' ', index1 + 1);
            if(index2 > index1){
                // 获取请求路径
                return requestString.substring(index1 + 1, index2);
            }
        }
        return null;
    }
    public String getUri() {
        return uri;
    }
}
复制代码


HttpResonse


以 httpserver 的请求outputstream ,获取输入流,将数据返回给客户端

关键方法为setResouces,获取请求Uri,同时使用file 读取文件


public class HttpResponse {
    /**
     * 组合httprequest
     * 根据request返回对应到信息
     */
    private HttpRequest request;
    /**
     * 输出流
     */
    private OutputStream outputStream;
    /**
     * 缓冲区大小
     */
    private static final int BUFFER_COUNT = 1024;
    public HttpResponse(OutputStream outputStream) {
        this.outputStream = outputStream;
    }
    /**
     * 设置静态资源
     */
    public void setResource() throws IOException {
        String errMsg = "404 msg";
        // 字节缓存区
        byte[] bytes = new byte[BUFFER_COUNT];
        // 读取静态资源
        File file = new File(HttpServer.WEBROOT, request.getUri());
        if (file.exists()) {
            // 文件流
            try {
                FileInputStream fileInputStream = new FileInputStream(file);
                // 读取字节
                int ch = fileInputStream.read(bytes, 0, BUFFER_COUNT);
                // 输出
                while (ch != -1) {
                    // 写入流
                    outputStream.write(bytes, 0, ch);
                    // 重复读取数据到缓冲区
                    ch = fileInputStream.read(bytes, 0, BUFFER_COUNT);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (outputStream != null) {
                    outputStream.close();
                }
            }
        } else {
            try {
                outputStream.write(errMsg.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (outputStream != null) {
                    outputStream.close();
                }
            }
        }
    }
    /**
     * 设置request
     *
     * @param httpRequest
     */
    public void setRequest(HttpRequest httpRequest) {
        this.request = httpRequest;
    }
}
复制代码



相关文章
|
3天前
|
搜索推荐 编译器 Linux
一个可用于企业开发及通用跨平台的Makefile文件
一款适用于企业级开发的通用跨平台Makefile,支持C/C++混合编译、多目标输出(可执行文件、静态/动态库)、Release/Debug版本管理。配置简洁,仅需修改带`MF_CONFIGURE_`前缀的变量,支持脚本化配置与子Makefile管理,具备完善日志、错误提示和跨平台兼容性,附详细文档与示例,便于学习与集成。
271 116
|
18天前
|
域名解析 人工智能
【实操攻略】手把手教学,免费领取.CN域名
即日起至2025年12月31日,购买万小智AI建站或云·企业官网,每单可免费领1个.CN域名首年!跟我了解领取攻略吧~
|
12天前
|
安全 Java Android开发
深度解析 Android 崩溃捕获原理及从崩溃到归因的闭环实践
崩溃堆栈全是 a.b.c?Native 错误查不到行号?本文详解 Android 崩溃采集全链路原理,教你如何把“天书”变“说明书”。RUM SDK 已支持一键接入。
662 219
|
5天前
|
数据采集 人工智能 自然语言处理
Meta SAM3开源:让图像分割,听懂你的话
Meta发布并开源SAM 3,首个支持文本或视觉提示的统一图像视频分割模型,可精准分割“红色条纹伞”等开放词汇概念,覆盖400万独特概念,性能达人类水平75%–80%,推动视觉分割新突破。
344 34
Meta SAM3开源:让图像分割,听懂你的话
|
10天前
|
人工智能 移动开发 自然语言处理
2025最新HTML静态网页制作工具推荐:10款免费在线生成器小白也能5分钟上手
晓猛团队精选2025年10款真正免费、无需编程的在线HTML建站工具,涵盖AI生成、拖拽编辑、设计稿转代码等多种类型,均支持浏览器直接使用、快速出图与文件导出,特别适合零基础用户快速搭建个人网站、落地页或企业官网。
1547 157
|
存储 人工智能 监控
从代码生成到自主决策:打造一个Coding驱动的“自我编程”Agent
本文介绍了一种基于LLM的“自我编程”Agent系统,通过代码驱动实现复杂逻辑。该Agent以Python为执行引擎,结合Py4j实现Java与Python交互,支持多工具调用、记忆分层与上下文工程,具备感知、认知、表达、自我评估等能力模块,目标是打造可进化的“1.5线”智能助手。
897 61
|
7天前
|
编解码 Linux 数据安全/隐私保护
教程分享免费视频压缩软件,免费视频压缩,视频压缩免费,附压缩方法及学习教程
教程分享免费视频压缩软件,免费视频压缩,视频压缩免费,附压缩方法及学习教程
295 140