通过深入分析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);
Map<String, Object> attributesSnapshot = 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