摘自:https://www.tianxiaobo.com/2018/06/29/Spring-MVC-原理探秘-一个请求的旅行过程/
1.GenericServlet 只是一个抽象类提供一些基础的模板 具体实现由以下子类实现
2.HTTPServlet提供了对service的实现
javax.servlet.http.HttpServlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { if (req instanceof HttpServletRequest && res instanceof HttpServletResponse) { //转为HttpServletRequest HttpServletRequest request = (HttpServletRequest)req; //转为HttpServletResponse HttpServletResponse response = (HttpServletResponse)res; //<1>交给当前类的service方法处理 这里不是调用当前类的 而是调用子类FrameworkServlet的 重写了 this.service(request, response); } else { throw new ServletException("non-HTTP request or response"); } }
javax.servlet.http.HttpServlet#service(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
/** * 根据请求方式路由到对应的方法处理 * @param req * @param resp * @throws ServletException * @throws IOException */ protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取请求协议头的请求方式 如:Request Method: GET String method = req.getMethod(); long lastModified; if (method.equals("GET")) { //-1则表示缓存绝对更新了 默认子类没有实现 直接返回的-1 lastModified = this.getLastModified(req); if (lastModified == -1L) { //<3>根据协议版本 返回400 405空实现 由子类实现 this.doGet(req, resp); } else { /** * <2>如果上一次请求客户端Last-Modified 如:Last-Modified: Thu, 20 Feb 2014 09:02:52 GMT * 一般静态文件会默认带上 * 浏览器会将数据缓存本地 * 后续浏览器都会带上 每次跟服务器数据更新时间来做比较 如果没更新返回304 空响应 * 浏览器直接使用过本地数据 */ long ifModifiedSince = req.getDateHeader("If-Modified-Since"); //比较缓存是否过期 if (ifModifiedSince < lastModified) { this.maybeSetLastModified(resp, lastModified); //<3>根据协议版本 返回400 405空实现 由子类实现 this.doGet(req, resp); } else { //返回304 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); } }
3.路由的方法都在HettpServlet都是返回405或者400的空实现 由子类实现
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String protocol = req.getProtocol(); String msg = lStrings.getString("http.method_get_not_supported"); if (protocol.endsWith("1.1")) { resp.sendError(405, msg); } else { resp.sendError(400, msg); } }
org.springframework.web.servlet.FrameworkServlet#service
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //如果请求方式是PATCH 则直接调用 if (HttpMethod.PATCH.matches(request.getMethod())) { this.processRequest(request, response); } else { /** * 否则调用父类的路由方法 最终也是调用processRequest * <2>作用是是 比如父类的304缓存策略 以及路由的不同方法 处理方式 有所差异 如 option处理方式 */ super.service(request, response); } }
org.springframework.web.servlet.FrameworkServlet#service
->
org.springframework.web.servlet.FrameworkServlet#processRequest
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { long startTime = System.currentTimeMillis(); Throwable failureCause = null; /** * <3>获取当前线程 第一次国际化上下文 从里面会从2个ThreadLocal获取 */ LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); //构建单签线程当本次请求的国际化上下文 LocaleContext localeContext = this.buildLocaleContext(request); //<3>获取当前线程第一次请求的RequestAttribute 里面会从2个ThreadLocal获取 RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); //<4>构建当前线程的RequestAttribute ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes); /** *会从requsetAttribute里面获取获取不到初始化一个再set进去 key=WebAsyncUtils.WEB_ASYNC_MANAGER_ATTRIBUTE * 表示我们后去都可以根据reqeust.getAttribute(WebAsyncUtils.WEB_ASYNC_MANAGER_ATTRIBUTE)获取 * 用于给管理异步请求 */ WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor()); /** * <5>这里面会存入根据当前对象成语变量区分翻到哪个线程缓存里面threadContextInheritable 默认为false * 我们可以利用前面的BeanWapper进行修改 * 表示我们后续都可以根据LocaleContextHolder和RequestContextHolder获取 */ this.initContextHolders(request, localeContext, requestAttributes); try { //<6> this.doService(request, response); } catch (ServletException var17) { failureCause = var17; throw var17; } catch (IOException var18) { failureCause = var18; throw var18; } catch (Throwable var19) { failureCause = var19; throw new NestedServletException("Request processing failed", var19); } finally { /** * <7>默认previousLocaleContext previousAttributes 是null * 这里主要是还原 重置将第一次的set会线程池下次<3>处又可以继续获取到 */ this.resetContextHolders(request, previousLocaleContext, previousAttributes); if (requestAttributes != null) { requestAttributes.requestCompleted(); } if (this.logger.isDebugEnabled()) { if (failureCause != null) { this.logger.debug("Could not complete request", (Throwable)failureCause); } else if (asyncManager.isConcurrentHandlingStarted()) { this.logger.debug("Leaving response open for concurrent processing"); } else { this.logger.debug("Successfully completed request"); } } //spring事件机制 发布ServletRequestHandlerEvent消息,这个请求是否执行成功都会发布消息的 this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause); } }
原文:https://www.cnblogs.com/LQBlog/p/12202596.html