通过深入分析Spring MVC的源码,我们可以更好地理解其工作原理和内部机制。这有助于我们更好地使用该框架进行Web应用程序的开发,并解决实际开发中遇到的问题。同时,对于学习和研究Spring MVC框架的人来说,阅读源码并进行分析也是一种重要的学习和提升手段。
Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。是目前主流的实现MVC设计模式的框架,提供前端路由映射、视图解析等功能.
MVC是Model-View-Controller的缩写,是一种常用的软件设计模式。在这种设计模式中,模型层(Model)负责处理业务逻辑和数据,视图层(View)负责呈现用户界面,而控制器层(Controller)负责处理用户交互。
MVC把三层架构中的UI层再度进行了分化,分成了控制器、视图、实体三个部分,控制器完成页面逻辑,通过实体来与界面层完成通话;而Controller层直接与三层架构中的业务逻辑层进行对话。三层架构和MVC可以共存。 三层是基于业务逻辑来分的,而MVC是基于页面来分的。
特点:
MVC重要特点就是两种分离:
视图和数据模型的分离:使用不同的视图对相同的数据进行展示;分离可视和不可视的组件,能够对模型进行独立测试。因为分离了可视组件减少了外部依赖利于测试。(数据库也是一种外部组件)
视图和表现逻辑(Controller)的分离:Controller是一个表现逻辑的组件,并非一个业务逻辑组件。MVC可以作为表现模式也可以作为建构模式,意味这Controller也可以是业务逻辑。分离逻辑和具体展示,能够对逻辑进行独立测试。
优点:耦合性低;重用性高;生命周期成本低;部署块;可维护性高;有利软件工程化管理。
MVC框架详解可以看这位大佬的博文https://zhuanlan.zhihu.com/p/417635345
前端控制器(也称中央控制器),是整体流程控制的中心,由其调用其它组件处理用户的请求,有效的降低了组件间的耦合性
处理器映射器,负责根据用户请求找到对应具体的Handler处理器和拦截器,并将结果组装成一个HandlerExecutionChain返回
处理器适配器,通过它对处理器进行执行,基于适配器模式开发,如果使用@RequestMapping注解标识方法,那么执行的就是方法对象
如果处理器类上或方法上使用了@ResponseBody注解,那么就没有以下两步
视图解析器,将处理结果生成View视图,给方法返回的视图地址解析添加前后缀,返回完整的视图地址
视图,最终产出结果,常用视图如jsp、html ,视图最终渲染由前端控制器完成
首先,当一个请求进入controller前会先被DispatcherServlet拦截,进入doService方法,下面是整个doService方法的代码:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { this.logRequest(request); MapattributesSnapshot = null; if (WebUtils.isIncludeRequest(request)) { attributesSnapshot = new HashMap(); Enumeration> attrNames = request.getAttributeNames(); label95: while(true) { String attrName; do { if (!attrNames.hasMoreElements()) { break label95; } attrName = (String)attrNames.nextElement(); } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet")); attributesSnapshot.put(attrName, request.getAttribute(attrName)); } } 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 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); } try { this.doDispatch(request, response); } finally { if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) { this.restoreAttributesAfterInclude(request, attributesSnapshot); } } }
进入doService方法后,首先执行this.logRequest方法,记录请求的详细信息,包括请求的 URL、参数、头信息等。这些信息通常会被记录到日志文件中,以便于后续的分析和调试。
attributesSnapshot属性用于存储请求的属性快照。它的作用是在请求处理过程中,捕获请求的属性状态,以便在请求处理结束后进行清理或恢复。
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());
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);
FlashMapManager是Spring MVC中用于管理FlashMap的接口。FlashMap用于在重定向请求之间传递属性,通常用于在重定向后显示一次性消息或数据。FlashMapManager负责在请求之间存储和检索FlashMap,并在适当的时候清除FlashMap。具体实现可以根据需要选择,Spring提供了默认的实现,也可以自定义实现以满足特定需求。
下面是doDispatch方法的所有代码
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = this.checkMultipart(request); multipartRequestParsed = processedRequest != request; mappedHandler = this.getHandler(processedRequest); if (mappedHandler == null) { this.noHandlerFound(processedRequest, response); return; } HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler()); String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } this.applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception var20) { dispatchException = var20; } catch (Throwable var21) { dispatchException = new NestedServletException("Handler dispatch failed", var21); } 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); } } }
doDispatch方法逐行解析:
(1)将当前的HttpServletRequest对象赋值给processedRequest变量,这样可以在后续的代码中使用processedRequest来代表原始的请求对象。
(2)声明一个HandlerExecutionChain类型的变量mappedHandler,并将其初始化为null。这个变量用于存储处理请求的处理器(handler)以及相关的拦截器链。
(3)声明一个boolean类型的变量multipartRequestParsed,并将其初始化为false。这个变量通常用于跟踪是否已经解析了multipart请求。
(4)通过WebAsyncUtils工具类获取与当前请求相关的WebAsyncManager对象,用于处理异步请求的管理。
(5)声明一个类型为ModelAndView的变量mv,并将其初始化为null。ModelAndView是Spring MVC中用于将模型数据和视图名称封装在一起的类。
(6)声明一个类型为Exception的变量dispatchException,并将其初始化为null。这个变量通常用于存储在请求分派过程中发生的异常。
检查是否为multipart请求或对multipart请求进行解析。处理后的请求对象被赋值给processedRequest变量。
processedRequest = this.checkMultipart(request);
检查处理后的请求对象是否与原始请求对象相同
multipartRequestParsed = processedRequest != request;
(9.1)处理器为空报404找不到处理器异常直接返回,返回前会执行finally中的代码
getHandlerAdapter方法源码:
判断是够支持给定的处理器,如果找到一个适配器和处理器匹配,将返回这个适配器。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { Iterator var2 = this.handlerAdapters.iterator(); while(var2.hasNext()) { HandlerAdapter adapter = (HandlerAdapter)var2.next(); if (adapter.supports(handler)) { return adapter; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
applyPreHandle方法源码:
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = this.getInterceptors(); // 获取拦截器数组 if (!ObjectUtils.isEmpty(interceptors)) { // 如果拦截器数组不为空 for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) { // 遍历拦截器数组 HandlerInterceptor interceptor = interceptors[i]; // 获取当前拦截器 if (!interceptor.preHandle(request, response, this.handler)) { // 如果拦截器的preHandle方法返回false this.triggerAfterCompletion(request, response, (Exception)null); // 触发afterCompletion方法 return false; // 返回false } } } return true; }
将处理器执行链(包括拦截器与处理器)交给适配器,适配器调用handle方法执行处理器执行链以及
(13)在没有出现异常的情况下会执行以下代码:
该方法的作用:处理调度结果。它首先检查是否有异常,如果有异常则处理异常;然后根据处理结果进行渲染;最后触发请求完成后的处理。
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
超详细的!!!MVC架构模式说明 - 一只码农-小俊的文章 - 知乎
https://zhuanlan.zhihu.com/p/417635345
上一篇:SpringBoot之入门使用