本文将从请求获取和包装处理的请求传递给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作为监听者。他的生成图:
Coyoteadapter通过Mapper找到该请求对应的Context和Wrapper后,Coyoteadapter将包装好的请求交给Container。
3 Container处理请求流程从以下代码片段来看,我们很容易跟踪整个Container的调用链: 用时序图画出来的是:
最后,StandardWrapervalve将请求交给Servlet完成。到目前为止,http请求已经完成。
作者:京东物流 毕会杰
内容来源:京东云开发者社区