本文将从请求获取与包装处理、请求传递给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请求处理完毕。
作者:京东物流 毕会杰
内容来源:京东云开发者社区
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |