SpringMVC处理请求整个链路原理

prot

ected final void processRequest(HttpServletRequest request, HttpServletResponse response){ // 处理多言语问题 LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext(); LocaleContext localeContext = buildLocaleContext(request); // 创建RequestAttributes对象,整个请求通用,封装了请求和响应对象 RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes(); // 里面设置属性都是调用request对象设置属性,所以,整个请求需要获取request对象使用RequestContextHolder就能获取 ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes); // 获取异步请求管理器 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); // 添加一个拦截器,负责处理requestAttributes asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor()); // 初始化RequestContextHolder,将requestAttributes保存到RequestContextHolder中 initContextHolders(request, localeContext, requestAttributes);{ if (requestAttributes != null) { RequestContextHolder.setRequestAttributes(requestAttributes, this.threadContextInheritable); } } // 处理请求 doService(request, response);{ // 把当前web容器和其他组件放入请求域中 request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext()); request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource()); // flush管理器,用于重定向存储数据的管理器 FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response); 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); protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { // 获取异步管理器 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); // 校验是不是文件上传请求,如果是,返回新的request对象 HttpServletRequest processedRequest = checkMultipart(request);{ if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) { // 使用文件解析器解析请求,返回新的request对象 return this.multipartResolver.resolveMultipart(request); } } // 找到的handler和拦截器封装成HandlerExecutionChain对象 HandlerExecutionChain mappedHandler = getHandler(processedRequest);{ // 从所有的HandlerMapping中找 if (this.handlerMappings != null) { for (HandlerMapping mapping : this.handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request);{ // 获取对应的handler,具体的逻辑在对应的handlerMapping中,可以看HandlerMapping的获取Handler方法 Object handler = getHandlerInternal(request); // 将handler封装成HandlerExecutionChain HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);{ 创建HandlerExecutionChain对象返回 HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); // 将存在HandlerMapping中的拦截器附加到Handler中,形成拦截器链 for (HandlerInterceptor interceptor : this.adaptedInterceptors) { // 如果不是,直接添加 if (!(interceptor instanceof MappedInterceptor) { chain.addInterceptor(interceptor); return chain; } // 如果是自定义,设置了条件的拦截器,要特殊处理下 MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; // 该拦截器还要匹配拦截当前请求 if (mappedInterceptor.matches(request)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } return chain; } } if (handler != null) { return handler; } } } } // 未找到Handler,直接响应404 if (mappedHandler == null) { noHandlerFound(processedRequest, response);{ response.sendError(HttpServletResponse.SC_NOT_FOUND); } return; } // 查找handlerAdapter,HandlerAdapter才是真正执行业务逻辑的类 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());{ // 遍历所有的HandlerAdapter if (this.handlerAdapters != null) { for (HandlerAdapter adapter : this.handlerAdapters) { if (adapter.supports(handler){ // 能处理请求的HandlerAdapter return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); return handler instanceof HandlerFunction; return (handler instanceof HttpRequestHandler); return (handler instanceof Controller); return (handler instanceof Servlet); }) { return adapter; } } } } // 执行handler的前置方法 if (!mappedHandler.applyPreHandle(processedRequest, response){ // 遍历所有的拦截器, for (int i = 0; i < this.interceptorList.size(); i++) { HandlerInterceptor interceptor = this.interceptorList.get(i); // 执行拦截器的前置方法 if (!interceptor.preHandle(request, response, this.handler)) { // 如果前置方法返回false // 直接执行请求处理结束的方法 triggerAfterCompletion(request, response, null); // 请求结束 return false; } this.interceptorIndex = i; } // 当返回true表示所有的拦截器前置方法都返回了ture return true; }) { // 如果前置方法返回false,当前请求结束 return; } // 执行目标方法,无论如何都会返回一个ModelAndView对象 mv = ha.handle(processedRequest, response, mappedHandler.getHandler());{ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal{ // 校验请求是否可以处理 checkRequest(request);{ String method = request.getMethod(); // 如果设置了限制的请求方式,但是当前请求不符合规则 if (this.supportedMethods != null && !this.supportedMethods.contains(method)) { throw new HttpRequestMethodNotSupportedException(method, this.supportedMethods); } // 如果设置了请求必须要有session if (this.requireSession && request.getSession(false) == null) { throw new HttpSessionRequiredException("Pre-existing session required but none found"); } } // 如果同一个session需要同步执行,则需要对session加锁 if (this.synchronizeOnSession) { HttpSession session = request.getSession(false); if (session != null) { // 使用session最为锁对象 Object mutex = WebUtils.getSessionMutex(session); synchronized (mutex) { // 加锁执行方法 ModelAndView mav = invokeHandlerMethod(request, response, handlerMethod); } } }else{ // 不需要同步就直接执行目标方法,详请看笔记执行目标方法原理 ModelAndView mav = invokeHandlerMethod(request, response, handlerMethod); } // 如果当前请求不包含Cache-Control请求头, if (!response.containsHeader(HEADER_CACHE_CONTROL)) { // 如果handlerMethod存在一些Session缓存,就需要缓存一些会话信息 if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) { applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);{ // 例如设置过期时间 if cacheSeconds>0 response.setDateHeader(HEADER_EXPIRES, System.currentTimeMillis() + seconds * 1000L); else response.setHeader(HEADER_PRAGMA, "no-cache"); } } else { // 预处理设置响应头 prepareResponse(response);{ // 根据不同条件设置 applyCacheControl(response, this.cacheControl); applyCacheSeconds(response, this.cacheSeconds); response.addHeader("Vary", value); } } } return mav; } } // 如果请求被异步启动了,就不处理了 if (asyncManager.isConcurrentHandlingStarted()) { return; } // 获取视图名,如果没有设置视图名,返回一个默认的视图名,就是url对应的字符串当做视图 applyDefaultViewName(processedRequest, mv);{ // 如果没有异常,并且modeAndView中没有设置视图 // 在Controller的方法中,没有添加ResponseBody注解,也没有添加String返回值,也没有使用Response响应 // 此时springmvc默认会返回一个空的modeAndView,符合这个条件 // 例如: @GetMapping("haha") public void haha(HttpServletRequest req) { req.setAttribute("luck", "luck");} // 视图名会被解析成haha,因为不管有没有返回值,都会返回一个ModelAndView // 大胆猜测,如果我的方法返回void,然后将设置属性到request,或者model中,然后SpringMVC会自动跳转到路径对应的jsp页面 // 也就是haha.jsp中,这个时候,在jsp中${luck}是可以获取到值的 if (mv != null && !mv.hasView()) { // 获取一个默认的视图名,就是url对应的字符串当做视图 String defaultViewName = getDefaultViewName(request); // 将这个当做是视图名,到时候找对应文件渲染 if (defaultViewName != null) { mv.setViewName(defaultViewName); } } } // 执行所有的拦截器后置处理 mappedHandler.applyPostHandle(processedRequest, response, mv); catch (Exception ex) Exception dispatchException = ex; catch (Throwable err) Exception dispatchException = new NestedServletException("Handler dispatch failed", err);; // 处理相应结果,视图渲染,包括正常渲染和异常渲染 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);{ boolean errorView = false; // 判断是否有异常,如果有异常,就要构造异常的modeAndView,如果没有异常,那就直接渲染 if (exception != null) { // 返回异常为ModelAndViewDefiningException,返回此异常的ModeAndView if (exception instanceof ModelAndViewDefiningException) { mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } // 如果是其他类型的异常 else { // 获取处理请求的handler Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); // 构建一个异常的ModeAndView,处理异常 mv = processHandlerException(request, response, handler, exception);{ request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); // 如果存在异常解析器 if (this.handlerExceptionResolvers != null) { // 遍历所有的异常解析器解析异常 for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) { // 使用异常解析器解析异常,详情见异常解析器处理加载处理原理 ModelAndView exMv = resolver.resolveException(request, response, handler, ex); if (exMv != null) { break; } } } // 解析到异常的ModelAndView对象 if (exMv != null) { // 如果这个ModelAndView是一个空的对象,也就是不包含响应视图等等,返回空 // exMv.isEmpty 源码 return (this.view == null && CollectionUtils.isEmpty(this.model)); // 表示当前view为空,并且Model modelMap也为空 if (exMv.isEmpty()) { request.setAttribute(EXCEPTION_ATTRIBUTE, ex); return null; } // 如果View为空的情况下,但是Model modelMap不为空的情况下,会使用路径作为默认的视图界面 // 因为model中有数据,可以直接将model中的数据传递都页面中,详情见上面的applyDefaultViewName(processedRequest, mv);方法 // 例如: @GetMapping("haha") public void haha(HttpServletRequest req) { req.setAttribute("luck", "luck");} // 视图名会被解析成haha,因为不管有没有返回值,都会返回一个ModelAndView // 大胆猜测,如果我的方法返回void,然后将设置属性到request,或者model中,然后SpringMVC会自动跳转到路径对应的jsp页面 // 也就是haha.jsp中,这个时候,在jsp中${luck}是可以获取到值的 // 例如: @ExceptionHandler(NullPointerException.class) public void e(Model model) {model.addAttribute("luck", "luck");} if (!exMv.hasView()) { // 获取默认的View的视图名 String defaultViewName = getDefaultViewName(request); // 如果设置了视图名,那么就要按正常的视图渲染流程 if (defaultViewName != null) { exMv.setViewName(defaultViewName); } } // 将一个异常相关的属性数据存入request域中 WebUtils.exposeErrorRequestAttributes(request, ex, getServletName()); return exMv; } } // 异常视图标志 errorView = (mv != null); } } // modeAndView的wasCleared默认为false,除非手动调用了mv.clear if (mv != null && !mv.wasCleared()) { // 会进入视图渲染,详情见视图渲染原理 render(mv, request, response); // 如果处理了异常的情况下,请求放在请求域中的异常数据都清除 if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } // 如果是异步请求,直接结束,不执行下面的拦截器后置方法 if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { return; } // 找到了handler,执行拦截器的后置方法 if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, null); } } // 整个请求结束,无论如何到需要执行拦截器的afterCompletion方法 catch (Exception ex) triggerAfterCompletion(processedRequest, response, mappedHandler, ex); catch (Throwable err) triggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException("Handler processing failed", err)); // doDispatch执行结束,如果是文件上传,需要删除临时文件 finally if (multipartRequestParsed) cleanupMultipart(processedRequest);{ if (this.multipartResolver != null) { // 调用文件解析器,清理文件,因为文件上传之前,会创建临时文件在磁盘中,请求处理完成要删除 this.multipartResolver.cleanupMultipart(multipartRequest); } } } } // 重置requestAttributes resetContextHolders(request, previousLocaleContext, previousAttributes); if (requestAttributes != null) { requestAttributes.requestCompleted(); } // 发布事件 publishRequestHandledEvent(request, response, startTime, failureCause); }