在之前我们了解到了DispatcherServlet是如何初始化的,接下来我们了解下他是如何处理请求的呢?
首先,我们了解下Tomcat启动后是如何处理HTTP请求的?
文档来源
HTTP协议是浏览器与服务器之间的数据传送协议。作为应用层协议,HTTP是基于TCP/IP协议来传递数据的(HTML文件、图片、查询结果等),HTTP协议不涉及数据包(Packet )传输,主要规定了客户端和服务器之间的通信格式。
从图上你可以看到,这个过程是:
Tomcat作为一个Servlet服务器,在这个过程中主要是接受连接、解析请求数据、处理请求和发送响应。
浏览器发给服务端的是一个Http格式的请求,Http服务器收到这个请求后,需要调用服务端程序来处理,所谓的服务端程序就是你写的Java类,一般来说不同的请求需要由不同的Java类来处理。
图1,表示HTTP服务器直接调用具体业务类,它们是紧耦合的。
图2,HTTP服务器不直接调用业务类,而是把请求交给容器来处理,容器通过servlet接口调用业务类。因此servlet接口和servlet容器的出现,达到了HTTP服务器与业务类解耦的目的。而servlet接口和servlet容器这一整套规范叫作servlet规范。Tomcat按照servlet规范的要求实现了servlet容器,同时它们也具有HTTP服务器的功能。
为了解耦,HTTP服务器不直接调用servlet,而是把请求交给servlet容器来处理。
当客户请求某个资源时,HTTP服务器会用一个servletRequest对象把客户的请求信息封装起来,然后调用servlet容器的service方法,Servlet容器拿到请求后,根据请求的URL和Servlet的映射关系,找到相应的servlet,如果servlet还没有被加载,就用反射机制创建这个servlet,并调用servlet的init方法来完成初始化,接着调用servlet的service方法来处理请求,把servletResponse对象返回给HTTP服务器,HTTP服务器会把响应发送给客户端。
我们知道如果要设计一个系统,首先是要了解需求,我们已经了解了Tomcat要实现两个核心功能︰
处理socket连接,负责网络字节流与Request和Response对象的转化。
加载和管理servlet ,以及具体处理Request请求。
因此Tomcat设计了两个核心组件连接器(connector )和容器( container )来分别做这两件事情。连接器负责对外交流,容器负责内部处理。
步骤如下:
通过上面Tomcat处理流程分析,可以了解到,请求经过Tomcat一些列组件处理,再调用我们的servlet进行逻辑处理的。
之前分析了DispatcherServlet中初始化init的流程,当xServlet在处理请求时,会进入service方法。
DispatcherServlet中service进入的是父类FrameworkServlet中的service。
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 1. 获取请求方式 HttpMethod httpMethod = HttpMethod.resolve(request.getMethod()); // 2. 请求方式不为null,并且不是PATCH 请求,调用父类的HttpServlet的service方法 if (httpMethod != HttpMethod.PATCH && httpMethod != null) { super.service(request, response); } else { // 3. 处理请求 this.processRequest(request, response); } }
这里测试的是GET请求,所以上述代码会进入HttpServlet.service方法,根据不同的请求方式执行不同的do方法,
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String method = req.getMethod(); long lastModified; // 1. 如果是GET if (method.equals("GET")) { // 2. 获取最后修改时间 lastModified = this.getLastModified(req); if (lastModified == -1L) { this.doGet(req, resp); } else { // 3. 最后修改时不是-1 // If-Modified-Since是标准的HTTP请求头标签,在发送HTTP请求时,把浏览器端缓存页面的最后修改时间一起发到服务器去,服务器会把这个时间与服务器上实际文件的最后修改时间进行比较。 // 如果时间一致,那么返回HTTP状态码304(不返回文件内容),客户端接到之后,就直接把本地缓存文件显示到浏览器中。 //如果时间不一致,就返回HTTP状态码200和新的文件内容,客户端接到之后,会丢弃旧文件,把新文件缓存起来,并显示到浏览器中。 long ifModifiedSince; try { ifModifiedSince = req.getDateHeader("If-Modified-Since"); } catch (IllegalArgumentException var9) { ifModifiedSince = -1L; } if (ifModifiedSince < lastModified / 1000L * 1000L) { this.maybeSetLastModified(resp, lastModified); this.doGet(req, resp); } else { resp.setStatus(304); } } } else if (method.equals("HEAD")) { lastModified = this.getLastModified(req); this.maybeSetLastModified(resp, lastModified); this.doHead(req, resp); } else if (method.equals("POST")) { this.doPost(req, resp); } else if (method.equals("PUT")) { this.doPut(req, resp); } else if (method.equals("DELETE")) { this.doDelete(req, resp); } else if (method.equals("OPTIONS")) { this.doOptions(req, resp); } else if (method.equals("TRACE")) { this.doTrace(req, resp); } else { String errMsg = lStrings.getString("http.method_not_implemented"); Object[] errArgs = new Object[]{method}; errMsg = MessageFormat.format(errMsg, errArgs); resp.sendError(501, errMsg); } }
上述进入service方法后,会根据不同的请求进入不同的Do方法,我们的GET请求会进入FrameworkServlet的doGet方法。
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.processRequest(request, response); }
可以看到我们常用的请求方式,都会直接调用processRequest方法,只有doOptions、doTrace会做特殊处理。
FrameworkServlet的processRequest方法会对请求进行前置处理。
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 系统时间 long startTime = System.currentTimeMillis(); Throwable failureCause = null; // Local本地化 =》 zh_CN LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); // 构建LocaleContext LocaleContext localeContext = this.buildLocaleContext(request); // 获取当前绑定到线程的RequestAttributes RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); // 构建ServletRequestAttributes ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes); // 获取异步管理器 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor()); // 初始化ContextHolder this.initContextHolders(request, localeContext, requestAttributes); try { // 调用doService this.doService(request, response); } catch (IOException | ServletException var16) { failureCause = var16; throw var16; } catch (Throwable var17) { failureCause = var17; throw new NestedServletException("Request processing failed", var17); } finally { // 重新设置ContextHolder this.resetContextHolders(request, previousLocaleContext, previousAttributes); if (requestAttributes != null) { requestAttributes.requestCompleted(); } // 记录日志 this.logResult(request, response, (Throwable)failureCause, asyncManager); // 发布事件 ContextHolder this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause); } }
在processRequest中会调用 this.doService方法,进入到DispatcherServlet。
DispatcherServlet.doService主要负责像request域对象中设置一些属性。
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { this.logRequest(request); Map<String, Object> attributesSnapshot = null; // request中存在属性javax.servlet.include.request_uri if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap(); Enumeration attrNames = request.getAttributeNames(); label116: while(true) { String attrName; do { if (!attrNames.hasMoreElements()) { break label116; } attrName = (String)attrNames.nextElement(); } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet")); attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } // 设置属性org.springframework.web.servlet.DispatcherServlet.CONTEXT // org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE // org.springframework.web.servlet.DispatcherServlet.LOCALE_RESOLVER request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource()); if (this.flashMapManager != null) { // FlashMap简单来说就是一个HashMap,用于数据保存 FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); if (inputFlashMap != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); } RequestPath previousRequestPath = null; if (this.parseRequestPath) { previousRequestPath = (RequestPath)request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE); ServletRequestPathUtils.parseAndCache(request); } try { // 执行调度!!! this.doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) { this.restoreAttributesAfterInclude(request, attributesSnapshot); } if (this.parseRequestPath) { ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request); } } }
经过之前的一系列处理,终于进入DispatcherServlet的doDispatch开始对请求进行调度处理。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; // 执行链,包含当前拦截器、处理器(controller方法)、拦截器索引。 boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { try { ModelAndView mv = null; Object dispatchException = null; try { // 1. 检查请求是否是multipart(即文件上传) processedRequest = this.checkMultipart(request); multipartRequestParsed = processedRequest != request; // 2. 通过handermapping映射获取HandlerExecutionChain(处理链中包括了interceptor的前置和后置方法) mappedHandler = this.getHandler(processedRequest); if (mappedHandler == null) { this.noHandlerFound(processedRequest, response); return; } // 3. 根据处理器(handler及HandlerExecutionChain)获取处理器适配器(处理器适配器是为了提供统一接口进行后续处理,从而支持多种类型的处理器) HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler()); String method = request.getMethod(); boolean isGet = HttpMethod.GET.matches(method); if (isGet || HttpMethod.HEAD.matches(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) { return; } } // 4. 调用拦截器的PreHandle方法,循环拦截器。 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 5. 处理器适配器执行控制器方法。也就是controller中的方法,处理参数,类型转换等。 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } this.applyDefaultViewName(processedRequest, mv); // 6. 调用拦截器的PostHandle。 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception var20) { dispatchException = var20; } catch (Throwable var21) { dispatchException = new NestedServletException("Handler dispatch failed", var21); } // 7. 后续处理 this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException); } catch (Exception var22) { this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22); } catch (Throwable var23) { this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23)); } } finally { if (asyncManager.isConcurrentHandlingStarted()) { if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else if (multipartRequestParsed) { this.cleanupMultipart(processedRequest); } } }
处理器、拦截器处理完成后,最终进入到processDispatchResult进行后续处理。
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { boolean errorView = false; // 1. 如果有异常,processHandlerException处理异常 if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { this.logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException)exception).getModelAndView(); } else { Object handler = mappedHandler != null ? mappedHandler.getHandler() : null; mv = this.processHandlerException(request, response, handler, exception); errorView = mv != null; } } if (mv != null && !mv.wasCleared()) { this.render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else if (this.logger.isTraceEnabled()) { this.logger.trace("No view rendering, null ModelAndView returned."); } if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { if (mappedHandler != null) { // 3. afterCompletion mappedHandler.triggerAfterCompletion(request, response, (Exception)null); } } }
最终,执行一些finally方法,请求处理流程就结束了,具体某些处理细节,后续会再慢慢介绍。