Tomcat卷二---请求流程源码分析

x33g5p2x  于2022-02-07 转载在 其他  
字(20.3k)|赞(0)|评价(0)|浏览(455)

Tomcat 请求处理流程

请求流程

设计了这么多层次的容器,Tomcat是怎么确定每一个请求应该由哪个Wrapper容器里的 Servlet来处理的呢?

答案是,Tomcat是用Mapper组件来完成这个任务的。

Mapper组件的功能就是将用户请求的URL定位到一个Servlet,它的工作原理是:

Mapper组件里保存了Web应用的配置信息,其实就是容器组件与访问路径的映射关系, 比如Host容器里配置的域名、Context容器里的Web应用路径,以及Wrapper容器里 Servlet映射的路径,你可以想象这些配置信息就是一个多层次的Map。

当一个请求到来时,Mapper组件通过解析请求URL里的域名和路径,再到自己保存的 Map里去查找,就能定位到一个Servlet。请你注意,一个请求URL最后只会定位到一个 Wrapper容器,也就是一个Servlet。

下面的示意图中 , 就描述了 当用户请求链接 http://www.itcast.cn/bbs/findAll 之 后, 是如何找到最终处理业务逻辑的servlet 。

那上面这幅图只是描述了根据请求的URL如何查找到需要执行的Servlet , 那么下面我们 再来解析一下 , 从Tomcat的设计架构层面来分析Tomcat的请求处理

步骤如下:

  1. Connector组件Endpoint中的Acceptor监听客户端套接字连接并接收Socket。
  2. 将连接交给线程池Executor处理,开始执行请求响应任务。
  3. Processor组件读取消息报文,解析请求行、请求体、请求头,封装成Request对象。
  4. Mapper组件根据请求行的URL值和请求头的Host值匹配由哪个Host容器、Context容器、Wrapper容器处理请求。
  5. CoyoteAdaptor组件负责将Connector组件和Engine容器关联起来,把生成的 Request对象和响应对象Response传递到Engine容器中,调用 Pipeline。
  6. Engine容器的管道开始处理,管道中包含若干个Valve、每个Valve负责部分处理逻 辑。执行完Valve后会执行基础的 Valve–StandardEngineValve,负责调用Host容器的 Pipeline。
  7. Host容器的管道开始处理,流程类似,最后执行 Context容器的Pipeline。
  8. Context容器的管道开始处理,流程类似,最后执行 Wrapper容器的Pipeline。
  9. Wrapper容器的管道开始处理,流程类似,最后执行 Wrapper容器对应的Servlet对象 的 处理方法。

请求流程源码解析

在前面所讲解的Tomcat的整体架构中,我们发现Tomcat中的各个组件各司其职,组件 之间松耦合,确保了整体架构的可伸缩性和可拓展性,那么在组件内部,如何增强组件 的灵活性和拓展性呢? 在Tomcat中,每个Container组件采用责任链模式来完成具体的 请求处理。

在Tomcat中定义了Pipeline 和 Valve 两个接口,Pipeline 用于构建责任链, 后者代表责 任链上的每个处理器。Pipeline 中维护了一个基础的Valve,它始终位于Pipeline的末端 (最后执行),封装了具体的请求处理和输出响应的过程。当然,我们也可以调用 addValve()方法, 为Pipeline 添加其他的Valve, 后添加的Valve 位于基础的Valve之 前,并按照添加顺序执行。Pipiline通过获得首个Valve来启动整合链条的执行 。

源码研究

建议看源码流程前先去回顾一下责任链模式,因为tomcat的请求流程中主要使用了责任链模式

责任链模式

我们把请求过程的源码分为两部分来进行分析:
第一部分: 请求由Endpoint捕获,并转交给Processor处理.

1.Acceptor.run()

请求的流程由NioEndpoint中的Accepter类的run方法开始.

首先一个浏览器的请求会由tomcat中的Endpoint中的Accepter所捕获并开启会话.

  1. protected class Acceptor extends AbstractEndpoint.Acceptor {
  2. @Override
  3. public void run() {
  4. int errorDelay = 0;
  5. while (running) {
  6. while (paused && running) {
  7. state = AcceptorState.PAUSED;
  8. try {
  9. Thread.sleep(50);
  10. } catch (InterruptedException e) {
  11. // Ignore
  12. }
  13. }
  14. if (!running) {
  15. break;
  16. }
  17. state = AcceptorState.RUNNING;
  18. try {
  19. //if we have reached max connections, wait
  20. countUpOrAwaitConnection();
  21. SocketChannel socket = null;
  22. try {
  23. //接受客户端请求
  24. socket = serverSock.accept();
  25. } catch (IOException ioe) {
  26. // We didn't get a socket
  27. countDownConnection();
  28. if (running) {
  29. // Introduce delay if necessary
  30. errorDelay = handleExceptionWithDelay(errorDelay);
  31. // re-throw
  32. throw ioe;
  33. } else {
  34. break;
  35. }
  36. }
  37. // Successful accept, reset the error delay
  38. errorDelay = 0;
  39. // Configure the socket
  40. if (running && !paused) {
  41. // setSocketOptions() will hand the socket off to
  42. // an appropriate processor if successful
  43. if (!setSocketOptions(socket)) {
  44. closeSocket(socket);
  45. }
  46. } else {
  47. closeSocket(socket);
  48. }
  49. } catch (Throwable t) {
  50. ExceptionUtils.handleThrowable(t);
  51. log.error(sm.getString("endpoint.accept.fail"), t);
  52. }
  53. }
  54. state = AcceptorState.ENDED;
  55. }

2.Poller.run()

当接收客户端请求时,NioEndpoint.Poller会获取事件并开始迭代执行.(一下省略部分代码)

  1. public void run() {
  2. while (true) {
  3. .......
  4. while (iterator != null && iterator.hasNext()) {
  5. SelectionKey sk = iterator.next();
  6. NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment();
  7. // Attachment may be null if another thread has called
  8. // cancelledKey()
  9. if (attachment == null) {
  10. iterator.remove();
  11. } else {
  12. iterator.remove();
  13. //开始正式执行请求流程
  14. processKey(sk, attachment);
  15. }
  16. }//while
  17. //process timeouts
  18. timeout(keyCount,hasEvents);
  19. }//while
  20. getStopLatch().countDown();
  21. }
2.1 Poller.processKey()

processKey方法继续调用其中的processSocket方法,并开始处理会话.

  1. protected void processKey(SelectionKey sk, NioSocketWrapper attachment) {
  2. try {
  3. if ( close ) {
  4. cancelledKey(sk);
  5. } else if ( sk.isValid() && attachment != null ) {
  6. if (sk.isReadable() || sk.isWritable() ) {
  7. if ( attachment.getSendfileData() != null ) {
  8. processSendfile(sk,attachment, false);
  9. } else {
  10. unreg(sk, attachment, sk.readyOps());
  11. boolean closeSocket = false;
  12. // Read goes before write
  13. if (sk.isReadable()) {
  14. //开始处理会话
  15. if (!processSocket(attachment, SocketEvent.OPEN_READ, true)) {
  16. closeSocket = true;
  17. }
  18. }
  19. if (!closeSocket && sk.isWritable()) {
  20. if (!processSocket(attachment, SocketEvent.OPEN_WRITE, true)) {
  21. closeSocket = true;
  22. }
  23. }
  24. if (closeSocket) {
  25. cancelledKey(sk);
  26. }
  27. }
  28. }
  29. } else {
  30. //invalid key
  31. cancelledKey(sk);
  32. }
  33. } catch ( CancelledKeyException ckx ) {
  34. cancelledKey(sk);
  35. } catch (Throwable t) {
  36. ExceptionUtils.handleThrowable(t);
  37. log.error("",t);
  38. }
  39. }
2.2 AbstractEndpoint.processSocket()

当跟踪进processSocket时会发现调用的是AbstractEndpoint的processSocket方法.

他会首先获取Socket的处理器,并获取线程池为处理Socket单独开启一个线程.

  1. public boolean processSocket(SocketWrapperBase<S> socketWrapper,
  2. SocketEvent event, boolean dispatch) {
  3. try {
  4. if (socketWrapper == null) {
  5. return false;
  6. }
  7. //获取socket的处理器
  8. SocketProcessorBase<S> sc = processorCache.pop();
  9. if (sc == null) {
  10. sc = createSocketProcessor(socketWrapper, event);
  11. } else {
  12. sc.reset(socketWrapper, event);
  13. }
  14. //获取到线程池
  15. Executor executor = getExecutor();
  16. if (dispatch && executor != null) {
  17. //由线程池调用一个线程来执行Socket处理器
  18. executor.execute(sc);
  19. } else {
  20. sc.run();
  21. }
  22. } catch (RejectedExecutionException ree) {
  23. getLog().warn(sm.getString("endpoint.executor.fail", socketWrapper) , ree);
  24. return false;
  25. } catch (Throwable t) {
  26. ExceptionUtils.handleThrowable(t);
  27. // This means we got an OOM or similar creating a thread, or that
  28. // the pool and its queue are full
  29. getLog().error(sm.getString("endpoint.process.fail"), t);
  30. return false;
  31. }
  32. return true;
  33. }

3. NioEndpoint.SocketProcessor.doRun()

经过跟踪会最终发现,sc.run()方法实际上是在调用NioEndpoint.SocketProcessor.doRun();

  1. protected void doRun() {
  2. NioChannel socket = socketWrapper.getSocket();
  3. SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
  4. ....
  5. if (handshake == 0) {
  6. SocketState state = SocketState.OPEN;
  7. // Process the request from this socket
  8. if (event == null) {
  9. //获取Handler处理器:Servlet(处理器),调度处理器的处理方法
  10. state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
  11. } else {
  12. state = getHandler().process(socketWrapper, event);
  13. }
  14. if (state == SocketState.CLOSED) {
  15. close(socket, key);
  16. }
  17. }
  18. ....
  19. }
  20. }

4. AbstractProtocol.ConnectionHandler.process

在doRun的方法中最后会交给AbstractProtocol.ConnectionHandler.process方法执行.

  1. @Override
  2. public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) {
  3. if (getLog().isDebugEnabled()) {
  4. getLog().debug(sm.getString("abstractConnectionHandler.process",
  5. wrapper.getSocket(), status));
  6. }
  7. if (wrapper == null) {
  8. // Nothing to do. Socket has been closed.
  9. return SocketState.CLOSED;
  10. }
  11. //获取Socket
  12. S socket = wrapper.getSocket();
  13. //交给Processor处理 -> 真正开始处理请求
  14. Processor processor = connections.get(socket);
  15. ....
  16. do {
  17. //开始解析请求
  18. state = processor.process(wrapper, status);
  19. .....
  20. }
  21. } while ( state == SocketState.UPGRADING);
  22. }

至此,请求由Endpoint组件正式转交给Processor进行处理.

主要内容为在请求转交给Coyote适配器后的流程分析,紧接上文中请求交由Processor处理.

5.AbstractProcessorLight.process()

当请求由Endpoint交由Processor处理时,首先经过的就是AbstractProcessorLight.process()

  1. public SocketState process(SocketWrapperBase<?> socketWrapper, SocketEvent status)
  2. throws IOException {
  3. SocketState state = SocketState.CLOSED;
  4. Iterator<DispatchType> dispatches = null;
  5. do {
  6. if (dispatches != null) {
  7. DispatchType nextDispatch = dispatches.next();
  8. if (getLog().isDebugEnabled()) {
  9. getLog().debug("Processing dispatch type: [" + nextDispatch + "]");
  10. }
  11. state = dispatch(nextDispatch.getSocketStatus());
  12. if (!dispatches.hasNext()) {
  13. state = checkForPipelinedData(state, socketWrapper);
  14. }
  15. } else if (status == SocketEvent.DISCONNECT) {
  16. } else if (isAsync() || isUpgrade() || state == SocketState.ASYNC_END) {
  17. state = dispatch(status);
  18. state = checkForPipelinedData(state, socketWrapper);
  19. } else if (status == SocketEvent.OPEN_WRITE) {
  20. // Extra write event likely after async, ignore
  21. state = SocketState.LONG;
  22. } else if (status == SocketEvent.OPEN_READ) {
  23. //调度Http11Processor.service方法
  24. state = service(socketWrapper);
  25. } else if (status == SocketEvent.CONNECT_FAIL) {
  26. logAccess(socketWrapper);
  27. } else {
  28. state = SocketState.CLOSED;
  29. }
  30. ....
  31. }
  32. } while (state == SocketState.ASYNC_END ||
  33. dispatches != null && state != SocketState.CLOSED);
  34. return state;
  35. }

6.Http11Processor的service方法

  1. @Override
  2. public SocketState service(SocketWrapperBase<?> socketWrapper)
  3. ....
  4. while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null &&
  5. sendfileState == SendfileState.DONE && !endpoint.isPaused()) {
  6. // Parsing the request header
  7. try {
  8. //解析socket请求数据中每一行,按照http协议解析请求头----只负责解析请求头
  9. if (!inputBuffer.parseRequestLine(keptAlive)) {
  10. if (inputBuffer.getParsingRequestLinePhase() == -1) {
  11. return SocketState.UPGRADING;
  12. } else if (handleIncompleteRequestLineRead()) {
  13. break;
  14. }
  15. }
  16. if (endpoint.isPaused()) {
  17. // 503 - Service unavailable
  18. response.setStatus(503);
  19. setErrorState(ErrorState.CLOSE_CLEAN, null);
  20. } else {
  21. keptAlive = true;
  22. // Set this every time in case limit has been changed via JMX
  23. request.getMimeHeaders().setLimit(endpoint.getMaxHeaderCount());
  24. if (!inputBuffer.parseHeaders()) {
  25. // We've read part of the request, don't recycle it
  26. // instead associate it with the socket
  27. openSocket = true;
  28. readComplete = false;
  29. break;
  30. }
  31. if (!disableUploadTimeout) {
  32. socketWrapper.setReadTimeout(connectionUploadTimeout);
  33. }
  34. }
  35. } catch (IOException e) {
  36. if (log.isDebugEnabled()) {
  37. log.debug(sm.getString("http11processor.header.parse"), e);
  38. }
  39. setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
  40. break;
  41. } catch (Throwable t) {
  42. ....
  43. }
  44. // 400 - Bad Request
  45. response.setStatus(400);
  46. setErrorState(ErrorState.CLOSE_CLEAN, t);
  47. }
  48. // Has an upgrade been requested?
  49. Enumeration<String> connectionValues = request.getMimeHeaders().values("Connection");
  50. boolean foundUpgrade = false;
  51. while (connectionValues.hasMoreElements() && !foundUpgrade) {
  52. foundUpgrade = connectionValues.nextElement().toLowerCase(
  53. Locale.ENGLISH).contains("upgrade");
  54. }
  55. if (foundUpgrade) {
  56. // Check the protocol
  57. String requestedProtocol = request.getHeader("Upgrade");
  58. UpgradeProtocol upgradeProtocol = httpUpgradeProtocols.get(requestedProtocol);
  59. if (upgradeProtocol != null) {
  60. if (upgradeProtocol.accept(request)) {
  61. // TODO Figure out how to handle request bodies at this
  62. // point.
  63. response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
  64. response.setHeader("Connection", "Upgrade");
  65. response.setHeader("Upgrade", requestedProtocol);
  66. action(ActionCode.CLOSE, null);
  67. getAdapter().log(request, response, 0);
  68. InternalHttpUpgradeHandler upgradeHandler =
  69. upgradeProtocol.getInternalUpgradeHandler(
  70. getAdapter(), cloneRequest(request));
  71. UpgradeToken upgradeToken = new UpgradeToken(upgradeHandler, null, null);
  72. action(ActionCode.UPGRADE, upgradeToken);
  73. return SocketState.UPGRADING;
  74. }
  75. }
  76. }
  77. if (getErrorState().isIoAllowed()) {
  78. // Setting up filters, and parse some request headers
  79. rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
  80. try {
  81. //After reading the request headers, we have to setup the request filters.
  82. prepareRequest();
  83. } catch (Throwable t) {
  84. ExceptionUtils.handleThrowable(t);
  85. if (log.isDebugEnabled()) {
  86. log.debug(sm.getString("http11processor.request.prepare"), t);
  87. }
  88. // 500 - Internal Server Error
  89. response.setStatus(500);
  90. setErrorState(ErrorState.CLOSE_CLEAN, t);
  91. }
  92. }
  93. ...
  94. // Process the request in the adapter
  95. if (getErrorState().isIoAllowed()) {
  96. try {
  97. rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
  98. //将上面socket请求封装而成的request和response对象,再交给适配器进行处理
  99. //获取Coyote适配器,并调用其service方法
  100. getAdapter().service(request, response);
  101. ...

7.CoyoteAdapter.service()

至此请求就即将被发送给Engine引擎.

在CoyoteAdapter中将Request和Response装换成Servlet容器中处理的Request和Response,然后从service中获取容器,再调用管道Pipeline的阀门Valve的invoke方法

在Coyote适配器中,会获取Engine容器的第一个Valve,即StandardEngineValve,并执行.

  1. @Override
  2. public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
  3. throws Exception {
  4. Request request = (Request) req.getNote(ADAPTER_NOTES);
  5. Response response = (Response) res.getNote(ADAPTER_NOTES);
  6. .......
  7. if (connector.getXpoweredBy()) {
  8. response.addHeader("X-Powered-By", POWERED_BY);
  9. }
  10. boolean async = false;
  11. boolean postParseSuccess = false;
  12. req.getRequestProcessor().setWorkerThreadName(THREAD_NAME.get());
  13. try {
  14. // Parse and set Catalina and configuration specific
  15. // request parameters
  16. //解析和设置 Catalina 和特定配置,包括session的查找
  17. //在这里将Request和Response装换成Servlet容器中处理的Request和Response
  18. postParseSuccess = postParseRequest(req, request, res, response);
  19. if (postParseSuccess) {
  20. //check valves if we support async
  21. request.setAsyncSupported(
  22. connector.getService().getContainer().getPipeline().isAsyncSupported());
  23. // Calling the container
  24. //获取Engine容器的第一个Valve,即StandardEngineValve,并执行.
  25. connector.getService().getContainer().getPipeline().getFirst().invoke(
  26. request, response);
  27. }
  28. .......

整个容器中执行的链路如图:

8.StandardEngineValve#invoke

因为这里默认只有一个标准的Engine value实现:

  1. @Override
  2. public final void invoke(Request request, Response response)
  3. throws IOException, ServletException {
  4. // Select the Host to be used for this Request
  5. Host host = request.getHost();
  6. if (host == null) {
  7. response.sendError
  8. (HttpServletResponse.SC_BAD_REQUEST,
  9. sm.getString("standardEngine.noHost",
  10. request.getServerName()));
  11. return;
  12. }
  13. if (request.isAsyncSupported()) {
  14. request.setAsyncSupported(host.getPipeline().isAsyncSupported());
  15. }
  16. // Ask this Host to process this request
  17. //这里调用Host管道中的每个pipeline
  18. host.getPipeline().getFirst().invoke(request, response);
  19. }
9.StandardHostValve#invoke

说明一下:在Host管道中,默认还会加入两个Value,一个是accessLogValue,一个是errorLogValue后者用来处理请求处理过程中发生的错误

接下来依次调用context,wrapper的valve并执行.

10.StandardContextValve#invoke

获取当前请求对应的wrapper

  1. // Select the Wrapper to be used for this Request
  2. Wrapper wrapper = request.getWrapper();

调用wrapper管道中所有value

  1. wrapper.getPipeline().getFirst().invoke(request, response);
10.StandardWrapperValve#invoke

重点代码一:分配一个servlet实例对象,来处理当前请求,这里的servlet其实就是我们自己定义的

  1. // Allocate a servlet instance to process this request
  2. try {
  3. if (!unavailable) {
  4. servlet = wrapper.allocate();
  5. }

这里的allocate就是从mapped中获取到当前请求映射的servlet,联系初始化时,扫描web.xml和相关注解

  1. // Create the filter chain for this request
  2. ApplicationFilterChain filterChain =
  3. ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);

给当前请求创建一个过滤器链

  1. /**
  2. * Construct a FilterChain implementation that will wrap the execution of
  3. * the specified servlet instance.
  4. *
  5. * @param request The servlet request we are processing
  6. * @param wrapper The wrapper managing the servlet instance
  7. * @param servlet The servlet instance to be wrapped
  8. *
  9. * @return The configured FilterChain instance or null if none is to be
  10. * executed.
  11. */
  12. public static ApplicationFilterChain createFilterChain(ServletRequest request,
  13. Wrapper wrapper, Servlet servlet) {
  14. // If there is no servlet to execute, return null
  15. if (servlet == null)
  16. return null;
  17. // Create and initialize a filter chain object
  18. ApplicationFilterChain filterChain = null;
  19. if (request instanceof Request) {
  20. Request req = (Request) request;
  21. if (Globals.IS_SECURITY_ENABLED) {
  22. // Security: Do not recycle
  23. filterChain = new ApplicationFilterChain();
  24. } else {
  25. filterChain = (ApplicationFilterChain) req.getFilterChain();
  26. if (filterChain == null) {
  27. filterChain = new ApplicationFilterChain();
  28. req.setFilterChain(filterChain);
  29. }
  30. }
  31. } else {
  32. // Request dispatcher in use
  33. filterChain = new ApplicationFilterChain();
  34. }
  35. filterChain.setServlet(servlet);
  36. filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());
  37. // Acquire the filter mappings for this Context
  38. StandardContext context = (StandardContext) wrapper.getParent();
  39. //wrapper的父容器context中的过滤器集合
  40. FilterMap filterMaps[] = context.findFilterMaps();
  41. // If there are no filter mappings, we are done
  42. if ((filterMaps == null) || (filterMaps.length == 0))
  43. return (filterChain);
  44. // Acquire the information we will need to match filter mappings
  45. DispatcherType dispatcher =
  46. (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);
  47. String requestPath = null;
  48. Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
  49. if (attribute != null){
  50. requestPath = attribute.toString();
  51. }
  52. String servletName = wrapper.getName();
  53. // Add the relevant path-mapped filters to this filter chain
  54. for (int i = 0; i < filterMaps.length; i++) {
  55. if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
  56. continue;
  57. }
  58. if (!matchFiltersURL(filterMaps[i], requestPath))
  59. continue;
  60. ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
  61. context.findFilterConfig(filterMaps[i].getFilterName());
  62. if (filterConfig == null) {
  63. // FIXME - log configuration problem
  64. continue;
  65. }
  66. //将集合中符合要求当前请求的过滤器都加入过滤器链中
  67. filterChain.addFilter(filterConfig);
  68. }
  69. // Add filters that match on servlet name second
  70. for (int i = 0; i < filterMaps.length; i++) {
  71. if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
  72. continue;
  73. }
  74. if (!matchFiltersServlet(filterMaps[i], servletName))
  75. continue;
  76. ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
  77. context.findFilterConfig(filterMaps[i].getFilterName());
  78. if (filterConfig == null) {
  79. // FIXME - log configuration problem
  80. continue;
  81. }
  82. //将集合中符合要求当前请求的过滤器都加入过滤器链中
  83. filterChain.addFilter(filterConfig);
  84. }
  85. // Return the completed filter chain
  86. //返回构建好的过滤器链
  87. return filterChain;
  88. }

调用完创建过滤器的方法后,回到invoke方法中

正式对当前请求调用过滤器链

  1. filterChain.doFilter
  2. (request.getRequest(), response.getResponse());
11.ApplicationFilterChain#doFilter

重点代码:

  1. internalDoFilter(request,response);

开始真正执行过滤流程

12.ApplicationFilterChain#internalDoFilter
  1. private void internalDoFilter(ServletRequest request,
  2. ServletResponse response)
  3. throws IOException, ServletException {
  4. // Call the next filter if there is one
  5. if (pos < n) {
  6. ApplicationFilterConfig filterConfig = filters[pos++];
  7. try {
  8. Filter filter = filterConfig.getFilter();
  9. if (request.isAsyncSupported() && "false".equalsIgnoreCase(
  10. filterConfig.getFilterDef().getAsyncSupported())) {
  11. request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
  12. }
  13. if( Globals.IS_SECURITY_ENABLED ) {
  14. final ServletRequest req = request;
  15. final ServletResponse res = response;
  16. Principal principal =
  17. ((HttpServletRequest) req).getUserPrincipal();
  18. Object[] args = new Object[]{req, res, this};
  19. SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
  20. } else {
  21. //重点代码---第三个参数是当前过滤器链对象--ApplicationFilterChain
  22. filter.doFilter(request, response, this);
  23. }
  24. } catch (IOException | ServletException | RuntimeException e) {
  25. throw e;
  26. } catch (Throwable e) {
  27. e = ExceptionUtils.unwrapInvocationTargetException(e);
  28. ExceptionUtils.handleThrowable(e);
  29. throw new ServletException(sm.getString("filterChain.filter"), e);
  30. }
  31. return;
  32. }
  33. // We fell off the end of the chain -- call the servlet instance
  34. try {
  35. if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
  36. lastServicedRequest.set(request);
  37. lastServicedResponse.set(response);
  38. }
  39. if (request.isAsyncSupported() && !servletSupportsAsync) {
  40. request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
  41. Boolean.FALSE);
  42. }
  43. // Use potentially wrapped request from this point
  44. if ((request instanceof HttpServletRequest) &&
  45. (response instanceof HttpServletResponse) &&
  46. Globals.IS_SECURITY_ENABLED ) {
  47. final ServletRequest req = request;
  48. final ServletResponse res = response;
  49. Principal principal =
  50. ((HttpServletRequest) req).getUserPrincipal();
  51. Object[] args = new Object[]{req, res};
  52. SecurityUtil.doAsPrivilege("service",
  53. servlet,
  54. classTypeUsedInService,
  55. args,
  56. principal);
  57. } else {
  58. //过滤器链调用完毕,真正调用servlet的方法
  59. servlet.service(request, response);
  60. }
  61. } catch (IOException | ServletException | RuntimeException e) {
  62. throw e;
  63. } catch (Throwable e) {
  64. e = ExceptionUtils.unwrapInvocationTargetException(e);
  65. ExceptionUtils.handleThrowable(e);
  66. throw new ServletException(sm.getString("filterChain.servlet"), e);
  67. } finally {
  68. if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
  69. lastServicedRequest.set(null);
  70. lastServicedResponse.set(null);
  71. }
  72. }
  73. }

这是过滤器的原理

下面看sevlet的调用,下面演示的是正常流程:

13.HttpServlet#service
  1. protected void service(HttpServletRequest req, HttpServletResponse resp)
  2. throws ServletException, IOException {
  3. String method = req.getMethod();
  4. if (method.equals(METHOD_GET)) {
  5. long lastModified = getLastModified(req);
  6. if (lastModified == -1) {
  7. // servlet doesn't support if-modified-since, no reason
  8. // to go through further expensive logic
  9. doGet(req, resp);
  10. } else {
  11. long ifModifiedSince;
  12. try {
  13. ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
  14. } catch (IllegalArgumentException iae) {
  15. // Invalid date header - proceed as if none was set
  16. ifModifiedSince = -1;
  17. }
  18. if (ifModifiedSince < (lastModified / 1000 * 1000)) {
  19. // If the servlet mod time is later, call doGet()
  20. // Round down to the nearest second for a proper compare
  21. // A ifModifiedSince of -1 will always be less
  22. maybeSetLastModified(resp, lastModified);
  23. doGet(req, resp);
  24. } else {
  25. resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
  26. }
  27. }
  28. } else if (method.equals(METHOD_HEAD)) {
  29. long lastModified = getLastModified(req);
  30. maybeSetLastModified(resp, lastModified);
  31. doHead(req, resp);
  32. } else if (method.equals(METHOD_POST)) {
  33. doPost(req, resp);
  34. } else if (method.equals(METHOD_PUT)) {
  35. doPut(req, resp);
  36. } else if (method.equals(METHOD_DELETE)) {
  37. doDelete(req, resp);
  38. } else if (method.equals(METHOD_OPTIONS)) {
  39. doOptions(req,resp);
  40. } else if (method.equals(METHOD_TRACE)) {
  41. doTrace(req,resp);
  42. } else {
  43. //
  44. // Note that this means NO servlet supports whatever
  45. // method was requested, anywhere on this server.
  46. //
  47. String errMsg = lStrings.getString("http.method_not_implemented");
  48. Object[] errArgs = new Object[1];
  49. errArgs[0] = method;
  50. errMsg = MessageFormat.format(errMsg, errArgs);
  51. resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
  52. }
  53. }

这里的doGet和doPost等方法的调用就是在我们自己的servlet中调用了,因为我们自己的servlet没有重写service方法,所以这里service是调用父类的,而重写的doGet等方法,是调用对应子类的实现

13.DefaultServlet#service

如果没有找到对应的请求映射servlet,会返回DefaultServlet

  1. @Override
  2. protected void service(HttpServletRequest req, HttpServletResponse resp)
  3. throws ServletException, IOException {
  4. if (req.getDispatcherType() == DispatcherType.ERROR) {
  5. doGet(req, resp);
  6. } else {
  7. super.service(req, resp);
  8. }
  9. }

最终走的是HttpSerlvet的最后一个else分支,因为DefaultServlet是HttpServlet的子类

  1. else {
  2. //
  3. // Note that this means NO servlet supports whatever
  4. // method was requested, anywhere on this server.
  5. //
  6. String errMsg = lStrings.getString("http.method_not_implemented");
  7. Object[] errArgs = new Object[1];
  8. errArgs[0] = method;
  9. errMsg = MessageFormat.format(errMsg, errArgs);
  10. resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
  11. }

到此请求流程代码分析完毕

相关文章