Tomcat处理http请求之源码分析

打印 上一主题 下一主题

主题 907|帖子 907|积分 2721

本文将从请求获取与包装处理、请求传递给Container、Container处理请求流程,这3部分来讲述一次http穿梭之旅。
1 请求包装处理

tomcat组件Connector在启动的时候会监听端口。以JIoEndpoint为例,在其Acceptor类中:
  1. protected class Acceptor extends AbstractEndpoint.Acceptor {
  2.     @Override
  3.     public void run() {
  4.         while (running) {
  5.             ……
  6.             try {
  7.                 //当前连接数
  8.                 countUpOrAwaitConnection();
  9.                 Socket socket = null;
  10.                 try {
  11.                     //取出队列中的连接请求
  12.                     socket = serverSocketFactory.acceptSocket(serverSocket);
  13.                 } catch (IOException ioe) {
  14.                     countDownConnection();
  15.                 }
  16.                 if (running && !paused && setSocketOptions(socket)) {
  17.                     //处理请求
  18.                     if (!processSocket(socket)) {
  19.                         countDownConnection();
  20.                         closeSocket(socket);
  21.                     }
  22.                 } else {
  23.                     countDownConnection();
  24.                     // Close socket right away
  25.                     closeSocket(socket);
  26.                 }
  27.             }
  28.             ……
  29.         }
  30.     }
  31. }
复制代码
在上面的代码中,socket = serverSocketFactory.acceptSocket(serverSocket);与客户端建立连接,将连接的socket交给processSocket(socket)来处理。在processSocket中,对socket进行包装一下交给线程池来处理:
  1. protected boolean processSocket(Socket socket) {
  2.     try {
  3.         SocketWrapper<Socket> wrapper = new SocketWrapper<Socket>(socket);
  4.         wrapper.setKeepAliveLeft(getMaxKeepAliveRequests());
  5.         wrapper.setSecure(isSSLEnabled());
  6.         //交给线程池处理连接
  7.         getExecutor().execute(new SocketProcessor(wrapper));
  8.     }
  9.     ……
  10.     return true;
  11. }
复制代码
线程池处理的任务SocketProccessor,通过代码分析:
  1. protected class SocketProcessor implements Runnable {
  2.     protected SocketWrapper<Socket> socket = null;
  3.     protected SocketStatus status = null;
  4.     @Override
  5.     public void run() {
  6.         boolean launch = false;
  7.         synchronized (socket) {
  8.             SocketState state = SocketState.OPEN;
  9.             try {
  10.                 serverSocketFactory.handshake(socket.getSocket());
  11.             }
  12.             ……
  13.             if ((state != SocketState.CLOSED)) {
  14.                 //委派给Handler来处理
  15.                 if (status == null) {
  16.                     state = handler.process(socket, SocketStatus.OPEN_READ);
  17.                 } else {
  18.                     state = handler.process(socket,status);
  19.                 }
  20.             }}}
  21.             ……
  22. }
复制代码
即在SocketProcessor中,将Socket交给handler处理,这个handler就是在Http11Protocol的构造方法中赋值的Http11ConnectionHandler,在该类的父类process方法中通过请求的状态,来创建Http11Processor处理器进行相应的处理,切到Http11Proccessor的父类AbstractHttp11Proccessor中。
  1. public SocketState process(SocketWrapper socketWrapper) {
  2.     RequestInfo rp = request.getRequestProcessor();
  3.     rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
  4.     // Setting up the I/O
  5.     setSocketWrapper(socketWrapper);
  6.     getInputBuffer().init(socketWrapper, endpoint);
  7.     getOutputBuffer().init(socketWrapper, endpoint);
  8.     while (!getErrorState().isError() && keepAlive && !comet && !isAsync() &&
  9.             upgradeInbound == null &&
  10.             httpUpgradeHandler == null && !endpoint.isPaused()) {
  11.         ……
  12.         if (!getErrorState().isError()) {
  13.             // Setting up filters, and parse some request headers
  14.             rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
  15.             try {
  16.                 //请求预处理
  17.                 prepareRequest();
  18.             }
  19.             ……
  20.         }
  21.         ……
  22.         if (!getErrorState().isError()) {
  23.             try {
  24.                 rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
  25.                 //交由适配器处理
  26.                 adapter.service(request, response);
  27.                 if(keepAlive && !getErrorState().isError() && (
  28.                         response.getErrorException() != null ||
  29.                                 (!isAsync() &&
  30.                                 statusDropsConnection(response.getStatus())))) {
  31.                     setErrorState(ErrorState.CLOSE_CLEAN, null);
  32.                 }
  33.                 setCometTimeouts(socketWrapper);
  34.             }
  35.         }
  36.     }
  37.     ……
  38. }         
复制代码
可以看到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处理。
  1. public void service(org.apache.coyote.Request req,
  2.                         org.apache.coyote.Response res) {
  3.     ……
  4.     postParseSuccess = postParseRequest(req, request, res, response);
  5.     ……
  6.     connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
  7.     ……
  8. }
复制代码
在postParseRequest方法中代码片段:
  1. connector.getMapper().map(serverName, decodedURI, version,
  2.                                       request.getMappingData());
  3. request.setContext((Context) request.getMappingData().context);
  4. request.setWrapper((Wrapper) request.getMappingData().wrapper);
复制代码
request通过URI的信息找到属于自己的Context和Wrapper。而这个Mapper保存了所有的容器信息,不记得的同学可以回到Connector的startInternal方法中,最有一行代码是mapperListener.start(); 在MapperListener的start()方法中,
  1. public void startInternal() throws LifecycleException {
  2.     setState(LifecycleState.STARTING);
  3.     findDefaultHost();
  4.     Engine engine = (Engine) connector.getService().getContainer();
  5.     addListeners(engine);
  6.     Container[] conHosts = engine.findChildren();
  7.     for (Container conHost : conHosts) {
  8.         Host host = (Host) conHost;
  9.         if (!LifecycleState.NEW.equals(host.getState())) {
  10.             registerHost(host);
  11.         }
  12.     }
  13. }
复制代码
MapperListener.startInternal()方法将所有Container容器信息保存到了mapper中。那么,现在初始化把所有容器都添加进去了,如果容器变化了将会怎么样?这就是上面所说的监听器的作用,容器变化了,MapperListener作为监听者。他的生成图示:

通过Mapper找到了该请求对应的Context和Wrapper后,CoyoteAdapter将包装好的请求交给Container处理。
3 Container处理请求流程

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

最终StandardWrapperValve将请求交给Servlet处理完成。至此一次http请求处理完毕。
作者:京东物流 毕会杰
内容来源:京东云开发者社区

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

不到断气不罢休

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表