开发者社区 > 博文 > Tomcat处理http请求之源码分析
分享
  • 打开微信扫码分享

  • 点击前往QQ分享

  • 点击前往微博分享

  • 点击复制链接

Tomcat处理http请求之源码分析

  • bi****
  • 2023-05-26
  • IP归属:北京
  • 6320浏览

    本文将从请求获取与包装处理、请求传递给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);
                } 
            }
        }
        ……
    }          
    

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


    2 请求传递给Container

    CoyoteAdapterservice方法中,主要有2个任务:

    • 第一个是org.apache.coyote.Requestorg.apache.coyote.Response到继承自HttpServletRequestorg.apache.catalina.connector.Requestorg.apache.catalina.connector.Response转换,和ContextWrapper定位。
    • 第二个是将请求交给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的信息找到属于自己的ContextWrapper。而这个Mapper保存了所有的容器信息,不记得的同学可以回到ConnectorstartInternal方法中,最有一行代码是mapperListener.start();
    MapperListenerstart()方法中,

    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找到了该请求对应的ContextWrapper后,CoyoteAdapter将包装好的请求交给Container处理。

    3 Container处理请求流程

    从下面的代码片段,我们很容易追踪整个Container的调用链:

    用时序图画出来则是:



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


    文章数
    1
    阅读量
    158

    作者其他文章