MVC 核心组件
MVC 是软件工程中一种架构模式,将软件系统分成三个基本部分,模型,视图,控制器,由施乐研究中心为 SmallTalk 发明的一种软件设计模式
DispatcherServlet
* 在实际使用中,Spring 会通过扫描组件的方式,将组件装配到 WebApplicationContext 中,
在请求到达 Servlet 后,最终会由 DispatcherServlet.doDispatch 处理
* 本质上 DispatcherServlet 会将请求委派给一些特殊的 Bean 来进行请求的处理和响应的渲染
* 当请求在 Servlet WebApplicationContext 中无法处理,便会委派给 Root WebApplicationContext
这一现象是 Spring REST Repository 的实现原理
* DispatcherServlet 可以对 Http 消息的头部进行修改吗?
不可以,Http 消息的头部应使用 Servlet API 进行设置
构造方法
// 使用 WebApplicationContext 加载特定的 Bean
public DispatcherServlet(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
this.setDispatchOptionsRequest(true);
}
render 方法
// render 方法用于进行国际化处理和视图的渲染
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();
// 进行国际化处理
response.setLocale(locale);
String viewName = mv.getViewName();
View view;
if (viewName != null) {
view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
if (view == null) {
String var10002 = mv.getViewName();
throw new ServletException("Could not resolve view with name '" + var10002 + "' in servlet with name '" + this.getServletName() + "'");
}
} else {
view = mv.getView();
if (view == null) {
throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'");
}
}
if (this.logger.isTraceEnabled()) {
this.logger.trace("Rendering view [" + view + "] ");
}
try {
if (mv.getStatus() != null) {
request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, mv.getStatus());
response.setStatus(mv.getStatus().value());
}
view.render(mv.getModelInternal(), request, response);
} catch (Exception var8) {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Error rendering view [" + view + "]", var8);
}
throw var8;
}
}
getHandler 方法
// getHandler 用于返回请求对应的处理器也就是 HandlerExecutionChain
// HandlerExecutionChain 包含拦截器 preHandle handle postHandle 的具体处理逻辑
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
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 {
// 处理 multipart 请求(如果有),例如文件上传
processedRequest = this.checkMultipart(request);
// 检查请求是否已被 multipart 解析
multipartRequestParsed = processedRequest != request;
// 调用 getHandler 方法并根据请求查找对应的处理器
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
// 如果没有返回 404
this.noHandlerFound(processedRequest, response);
return;
}
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
// 对 GET 请求和 HEAD 请求做特殊优化
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; // 资源未修改,直接返回 304 让浏览器使用缓存
}
}
// 对请求进行预处理
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 对请求进行处理,返回 ModelAndView 对象
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 ServletException("Handler dispatch failed: " + var21, var21);
}
// 调用 processDispatchResult 进行视图渲染
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
triggerAfterCompletion(processedRequest, response, mappedHandler, new ServletException("Handler processing failed: " + var23, var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
// HEAD 方法只返回响应状态行和响应头,通常用于 ETAG 或 Accept-Ranges
processDispatchResult 方法
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
boolean errorView = false;
if (exception != null) {
if (exception instanceof ModelAndViewDefiningException) {
ModelAndViewDefiningException mavDefiningException = (ModelAndViewDefiningException)exception;
this.logger.debug("ModelAndViewDefiningException encountered", exception);
mv = mavDefiningException.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) {
mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
}
}
}
ViewResolver
* ViewResolver 负责将 controller 的返回值交给对应的 View 处理,每一种模板引擎都需要有自己的 ViewResolver 实现
* 模板引擎的 ViewResolver 一般会继承 UrlBasedViewResolver,UrlBasedViewResolver 中定义了两种特殊的常量:
- REDIRECT_URL_PREFIX = "redirect:" 用于重定向
- FORWARD_URL_PREFIX = "forward:" 用于转发
HandlerMapping
* 应用程序中所有的 HandlerMapping 都存放在 DispatcherServlet 的 HandlerMappings 中
* HandlerExecutionChain
* Spring 的默认 HandlerMapping 实现是 RequestMappingHandlerMapping,该 HandlerMapping
用于处理 RequestMapping、GetMapping
ModelAndView
* 包含视图名和数据的对象,由 HandlerAdapter 返回,另外无论 Controller 返回了 String、
Model String、ModelAndView 最总都会被 ModelAndViewMethodReturnValueHandler 处理
成 ModelAndView
MVVC 模型-视图-视图模型是 MVC 软件架构的衍生,该架构的核心特点是模型和视图的双向绑定
写在最后
Spring MVC 的核心组件
* DispatcherServlet:前端控制器,拦截请求并分发给合适的控制器。
* Controller:接收请求并返回模型给视图解析器
* ViewResolver:视图解析器,解析模型并返回具体的视图对象给客户端。
* ModelAndView:包含模型和视图的复合对象。
* WebMvcConfigurer 拦截器,消息转换器,过滤器,跨域的核心注册中心