首页 > 编程语言 >Tomcat处理http请求之源码分析

Tomcat处理http请求之源码分析

时间:2023-05-29 10:33:24浏览次数:38  
标签:http socket Tomcat request 源码 && apache org 请求

本文将从请求获取与包装处理、请求传递给Container、Container处理请求流程,这3部分来讲述一次http穿梭之旅。

1 请求包装处理

tomcat组件Connector在启动的时候会监听端口。以JIoEndpoint为例,在其Acceptor类中:

protected class Acceptor extends AbstractEndpoint.Acceptor {
    @Override
    public void run() {
        while (running) {
            ……
            try {
                //当前连接数
                countUpOrAwaitConnection();
                Socket socket = null;
                try {
                    //取出队列中的连接请求
                    socket = serverSocketFactory.acceptSocket(serverSocket);
                } catch (IOException ioe) {
                    countDownConnection();
                }
                if (running && !paused && setSocketOptions(socket)) {
                    //处理请求
                    if (!processSocket(socket)) {
                        countDownConnection();
                        closeSocket(socket);
                    }
                } else {
                    countDownConnection();
                    // Close socket right away
                    closeSocket(socket);
                }
            } 
            ……
        }
    }
}

在上面的代码中,socket = serverSocketFactory.acceptSocket(serverSocket);与客户端建立连接,将连接的socket交给processSocket(socket)来处理。在processSocket中,对socket进行包装一下交给线程池来处理:

protected boolean processSocket(Socket socket) {
    try {
        SocketWrapper<Socket> wrapper = new SocketWrapper<Socket>(socket);
        wrapper.setKeepAliveLeft(getMaxKeepAliveRequests());
        wrapper.setSecure(isSSLEnabled());
        //交给线程池处理连接
        getExecutor().execute(new SocketProcessor(wrapper));
    } 
    ……
    return true;
}

线程池处理的任务SocketProccessor,通过代码分析:

protected class SocketProcessor implements Runnable {
 
    protected SocketWrapper<Socket> socket = null;
    protected SocketStatus status = null;
 
    @Override
    public void run() {
        boolean launch = false;
        synchronized (socket) {
            SocketState state = SocketState.OPEN;
            try {
                serverSocketFactory.handshake(socket.getSocket());
            } 
            ……
            if ((state != SocketState.CLOSED)) {
                //委派给Handler来处理
                if (status == null) {
                    state = handler.process(socket, SocketStatus.OPEN_READ);
                } else {
                    state = handler.process(socket,status);
                }
            }}}
            ……
}

即在SocketProcessor中,将Socket交给handler处理,这个handler就是在Http11Protocol的构造方法中赋值的Http11ConnectionHandler,在该类的父类process方法中通过请求的状态,来创建Http11Processor处理器进行相应的处理,切到Http11Proccessor的父类AbstractHttp11Proccessor中。

public SocketState process(SocketWrapper socketWrapper) {
    RequestInfo rp = request.getRequestProcessor();
    rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
 
    // Setting up the I/O
    setSocketWrapper(socketWrapper);
    getInputBuffer().init(socketWrapper, endpoint);
    getOutputBuffer().init(socketWrapper, endpoint);
 
    while (!getErrorState().isError() && keepAlive && !comet && !isAsync() &&
            upgradeInbound == null &&
            httpUpgradeHandler == null && !endpoint.isPaused()) {
        ……
        if (!getErrorState().isError()) {
            // Setting up filters, and parse some request headers
            rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
            try {
                //请求预处理
                prepareRequest();
            } 
            ……
        }
        ……
        if (!getErrorState().isError()) {
            try {
                rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
                //交由适配器处理
                adapter.service(request, response);
 
                if(keepAlive && !getErrorState().isError() && (
                        response.getErrorException() != null ||
                                (!isAsync() &&
                                statusDropsConnection(response.getStatus())))) {
                    setErrorState(ErrorState.CLOSE_CLEAN, null);
                }
                setCometTimeouts(socketWrapper);
            } 
        }
    }
    ……
}          

可以看到Request和Response的生成,从Socket中获取请求数据,keep-alive处理,数据包装等等信息,最后交给了CoyoteAdapter的service方法

2 请求传递给Container

在CoyoteAdapter的service方法中,主要有2个任务:

•第一个是org.apache.coyote.Request和
org.apache.coyote.Response到继承自HttpServletRequest的org.apache.catalina.connector.Request和org.apache.catalina.connector.Response转换,和Context,Wrapper定位。

•第二个是将请求交给StandardEngineValve处理。

public void service(org.apache.coyote.Request req,
                        org.apache.coyote.Response res) {
    ……
    postParseSuccess = postParseRequest(req, request, res, response);
    ……
    connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
    ……
}

在postParseRequest方法中代码片段:

connector.getMapper().map(serverName, decodedURI, version,
                                      request.getMappingData());
request.setContext((Context) request.getMappingData().context);
request.setWrapper((Wrapper) request.getMappingData().wrapper);

request通过URI的信息找到属于自己的Context和Wrapper。而这个Mapper保存了所有的容器信息,不记得的同学可以回到Connector的startInternal方法中,最有一行代码是mapperListener.start(); 在MapperListener的start()方法中,

public void startInternal() throws LifecycleException {
 
    setState(LifecycleState.STARTING);
    findDefaultHost();
 
    Engine engine = (Engine) connector.getService().getContainer();
    addListeners(engine);
 
    Container[] conHosts = engine.findChildren();
    for (Container conHost : conHosts) {
        Host host = (Host) conHost;
        if (!LifecycleState.NEW.equals(host.getState())) {
            registerHost(host);
        }
    }
}

MapperListener.startInternal()方法将所有Container容器信息保存到了mapper中。那么,现在初始化把所有容器都添加进去了,如果容器变化了将会怎么样?这就是上面所说的监听器的作用,容器变化了,MapperListener作为监听者。他的生成图示:

通过Mapper找到了该请求对应的Context和Wrapper后,CoyoteAdapter将包装好的请求交给Container处理。

3 Container处理请求流程

从下面的代码片段,我们很容易追踪整个Container的调用链: 用时序图画出来则是:

最终StandardWrapperValve将请求交给Servlet处理完成。至此一次http请求处理完毕。

作者:京东物流 毕会杰

内容来源:京东云开发者社区

标签:http,socket,Tomcat,request,源码,&&,apache,org,请求
From: https://www.cnblogs.com/Jcloud/p/17439701.html

相关文章

  • Qt+QtWebApp开发笔记(四):http服务器使用Session和Cookie实现用户密码登录和注销功能
    前言  前面实现了基础的跳转,那么动态交互中登录是常用功能。  本篇实现一个动态交互的简单登录和注销功能,在Qt中使用Session和Cookie技术。 Demo  下载地址  链接:https://pan.baidu.com/s/1nkmsHgr-11Khe9k6Ntyf_g?pwd=1234 Html处理用户输入Sessi......
  • MyBatis源码之getMapper获取代理对象
    MyBatis源码之getMapper获取代理对象下面这句话意思非常明了,就是通过传入接口类型对象,获取接口代理对象。IUserDaouserDao1=sqlSession1.getMapper(IUserDao.class);具体的过程如下:一、首先,调用SqlSession的实现类DefaultSqlSession的getMapper方法,其实是在该方法内调用con......
  • webpack的工作流程(附带部分源码分析)
    @目录webpack的工作流程webpack的准备阶段本阶段流程和钩子modules和chunks的生成阶段module解析解析流程chunks生成文件生成阶段模板hash更新模板渲染chunk生成文件总结webpack的工作流程说明工作流程之前,先抛出两个结论:webpack的核心功能,是抽离成很多个内部插件来实现......
  • make项目的源码阅读
    这里下载https://ftp.gnu.org/gnu/make/make-4.4.tar.gz进行研读。目标研读的初始目的,是想看看make打印的构建命令在哪执行的。构建makemake项目本身的编译,可以用./configure&&make来完成。代码挖呀挖make中target抽象为structfile,并用链来组织,structfile{cons......
  • wireshark 结合 go 对每个请求进行 https tls tcp 内容解密
    众所周知,wireshark是一款流行的抓包软件,我们可以很方便地查看每个TCP包的具体信息。对于HTTP协议的数据,还可以查看每个协议层具体信息内容。但是对于HTTPS的数据,我们只能查看IP层以下的数据,TLS及以上的数据都是被加密过的,如下图所示。 在某些特殊的场景下,我们想查......
  • 常见项目——C语言实现2048小游戏(附源码和可执行文件)
    1.实现效果展示1.1界面图片说明:进入下面各页面后均可通过按键“q”来退出。1)菜单页2)开始游戏页3)游戏规则页4)按键说明页5)退出游戏页1.2视频展现戳此处查看视频演示1.3游戏源码及可执行文件(exe)下载支持作者,请关注公众号“优秀物联人”回复“2048小游戏”获取下......
  • 基于JAVA的springboot+vue摄影跟拍预定管理系统,附源码+数据库+论文+PPT
    1、项目介绍困扰管理层的许多问题当中,摄影跟拍预定管理一定是不敢忽视的一块。但是管理好摄影跟拍预定又面临很多麻烦需要解决,例如有几个方面:第一,往往用户人数都比较多,如何保证能够管理到每一用户;第二,如何在工作琐碎,记录繁多的情况下将摄影跟拍预定的当前情况反应给领导......
  • HTTP打卡
    01.http协议:1.协议=>超文本传输协议=>基于请求响应模式的,无状态,无连接的应用层协议,一般应运于web程序中.=>白话:制定客户端(前端)与服务器(后端)通讯的规则1.请求响应模式 客户端-请求->服务器 <......
  • HTTP协议
    HTTP/HTTPS简介HTTP协议是HyperTextTransferProtocol(超文本传输协议)的缩写,是用于从万维网(WWW:WorldWideWeb)服务器传输超文本到本地浏览器的传输协议。HTTP是一个基于TCP/IP通信协议来传递数据(HTNL文件、图片文件、查询结果等),是一个应用层协议。HTTPS协议收HyperTextTr......
  • Tomcat请求处理流程与源码浅析
    系列文章目录和关于我一丶Connector在tomcat中,Connector负责开启socket并且监听客户端请求,返回响应数据。其中:Endpoint:tomcat中没有这个接口,只有AbstractEndpoint,它负责启动线程来监听服务器端口,并且在接受到数据后交给Processor处理Processor:Processor读取到客户端请求......