当前位置: 首页 > 图灵资讯 > 技术篇> Tomcat处理http请求之源码分析 | 京东云技术团队

Tomcat处理http请求之源码分析 | 京东云技术团队

来源:图灵教育
时间:2023-05-29 13:56:43

本文将从请求获取和包装处理的请求传递给container、container处理请求流程,这三部分讲述了http穿梭之旅。

1 请求包装处理

tomcat组件Conector启动时会监控端口。以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)来处理。在processocket中,将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;}

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

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);                }            }}}            ……}

也就是说,在socketprocesor中,将socket交给handler处理,这是在http11protocol结构方法中赋值的http11conectonhandler,在这种父类process方法中,通过要求的状态,创建http11procesor处理器进行相应的处理,父类AbstractHttp11Processor切入Http11Procesor。

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 && !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() !getErrorState().isError() && (                        response.getErrorException() != null ||                                (!isAsync() &&                                statusDropsConnection(response.getStatus()))) {                    setErrorState(ErrorState.CLOSE_CLEAN, null);                }                setCometTimeouts(socketWrapper);            }         }    }    ……}

可见Request和Response的生成,从Socket中获取请求数据,keep-alive处理、数据包装等信息,最后给coyoteadapterserservice方法

2 请求传递给Container

在Coyoteadapter的service方法中,主要有两个任务:

•第一个是org.apache.coyote.Request和\org.apache.coyote.Response从Httpservletrequest继承org.apache.catalina.connector.Request和org.apache.catalina.connector.Response转换,Wrapper定位为Context。

•二是将请求交给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);    ……}

代码片段在postparsequest方法中:

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

request通过URI信息找到自己的Context和Wraper。这个Mapper保存了所有的容器信息,不记得的同学可以回到conector的startinternal方法,最重要的代码是mapperlisterner.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作为监听者。他的生成图:

Tomcat处理http请求之源码分析 | 京东云技术团队_apache

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

3 Container处理请求流程

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

Tomcat处理http请求之源码分析 | 京东云技术团队_HTTP_02

最后,StandardWrapervalve将请求交给Servlet完成。到目前为止,http请求已经完成。

作者:京东物流 毕会杰

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