本文将从申请获取与包装解决、申请传递给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申请处理完毕。
作者:京东物流 毕会杰
内容起源:京东云开发者社区