概况
三层架构分别代表
- View,用于接受用户提交请求的代码
- Service,系统的业务逻辑主要在这里编写
- Dao,直接操作数据库在这里编写
MVC分别代表:
- M指Model模型。承载数据,并对用户提交请求进行计算的模块,分为数据承载bean和业务处理bean。在三层架构中包含了Service和Dao两层
- V指View视图。为用户提供使用界面,与用户进行直接交互。在三层架构中属于View层的页面相关的部分
- C指Controller控制器。用于将用户请求转发给相应的Model处理,并处理Model的计算结果向用户提供相应相应。在三层架构中属于View层中Controller相关部分
入口介绍
MVC主要是通过DispatcherServlet实现的,他继承了HttpServlet类,沿用了原生的java servlet编程,在HttpServlet上面包装了若干层,主要处理几种逻辑
- 将POST,GET的概念转移到了路径映射中,方便统一处理
- 自定义增加了拦截器链,不满足条件直接返回
- 将消息按照content-type转换,是json或者html格式,文件上传下载,有统一的处理,可以自定义增加处理方式
- 最后处理视图,如果返回的是页面,扩展了视图模板(restful编程就不需要这一层,直接使用@RestController)
DispatcherServlet核心处理方法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 {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//判断请求是否是 multipart post (常见的有 post 表单提交的数据)
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
//通过request获取handler,包括 intercepter 信息
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
//获取 handler 适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (logger.isDebugEnabled()) {
logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
}
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
//调用 intercepter.perHandler()方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
//调用controller方法发挥 ModelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//当 ModelAndView 中不包含视图时获取默认视图
applyDefaultViewName(processedRequest, mv);
//调用 intercepter.perHandler()方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception ex) {
dispatchException = ex;
} catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
//视图渲染并将渲染后的视图文件(html)或者 json 等写入Response body 返回给浏览器
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
} catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
} catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
路径映射
在doDispatch方法中,调用getHandler方法获取request的映射路径,DispatcherServlet中默认的handlerMappings有五种,他们属于AbstractHandlerMapping的子类
- SimpleUrlHandlerMapping。该bean在WebMvcAutoConfiguration的内部配置类 FaviconConfiguration中声明。它匹配的URL路径是**/favicon.ico,作用是响应浏览器获取收藏夹中的icon文件
- RequestMappingHandlerMapping。该bean在WebMvcAutoConfiguration的内部配置类 EnableWebMvcConfiguration中声明。它和XML的注解驱动一样,匹配在Controller中@RequestMapping注解指定的URL
- WelcomePageHandlerMapping。该bean在WebMvcAutoConfiguration的内部配置类 WebMvcAutoConfigurationAdapter中声明。给URL路径是/或者/index映射到欢迎页面
- BeanNameUrlHandlerMapping。bean的名称(也就是beanID)作为URL,由匹配该URL的Controller处理业务。Controller必须继承AbstractController几乎不会使用
- 第二个SimpleUrlHandlerMapping。该bean在WebMvcAutoConfiguration的内部配置类 EnableWebMvcConfiguration的父类WebMvcConfigurationSupport中声明,它是专门用于映射资源文件的handlerMapping
然后从项目启动时,初始化好的缓存中根据请求路径和请求方式获取HandlerMethod,方便执行具体的controller方法。
拦截器
拦截器和动态代理不同,他不是动态生成字节码,通过改变类来处理,他没有使用反射,在生成HandlerMethod实例的时候,根据路径匹配,将拦截器放入的对应的实例中,在使用的时候只需要显示的调用就行了
//invoke代码前,执行拦截器,不满足条件立即返回,后续不会对消息这些做处理,所以拦截器返回的如果要做处理,只能使用传统方法通过response中直接写入值
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//invoke代码后,之后拦截器的后续操作
mappedHandler.applyPostHandle(processedRequest, response, mv);
消息转换
消息转换是在执行invoke之前的request的转换和invoke之后的response的转换,下面是执行的堆栈信息,主要讲response消息的转换
- DispatcherServlet->doDispatch方法的代码
//准备开始执行HandlerMethod,它里面有很多信息
ha.handle(processedRequest, response, mappedHandler.getHandler());
- AbstractHandlerMethodAdapter->handle方法的代码
//他是一个抽象方法
handleInternal(request, response, (HandlerMethod) handler);
- RequestMappingHandlerAdapter->handleInternal方法的代码
//里面有一些逻辑代码,核心是开始执行HandlerMethod
invokeHandlerMethod(request, response, handlerMethod);
- RequestMappingHandlerAdapter->invokeHandlerMethod方法的代码
//前面有一些设置,初始化,这里只执行
invocableMethod.invokeAndHandle(webRequest, mavContainer);
- ServletInvocableHandlerMethod->invokeAndHandle方法的代码
//第一句就很暴力,直接执行controler中的值,返回Object对象
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
//这里是对返回值进行处理
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
- HandlerMethodReturnValueHandlerComposite->handleReturnValue方法的代码
//选择返回值的处理器
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
//进行处理
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
- RequestResponseBodyMethodProcessor->handleReturnValue方法的代码
//开始准备写入response
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
- AbstractMessageConverterMethodProcessor->writeWithMessageConverters方法的代码
//这里就是获得所有的messageConverters,按照顺序来处理,根据一些content-type这些值,来选择处理的messageConverters
for (HttpMessageConverter<?> converter : this.messageConverters) {
//省略
}
- AbstractHttpMessageConverter->writeInternal方法
这是一个抽象类,抽象方法,这个抽象类是不是很熟悉,对吧,如果添加消息转换器,都会继承这个父类,然后复写writeInternal转换器
在springboot中一般都是这样添加消息转换器的
@Bean
public HttpMessageConverters customConverters() {
//省略
//这一句最终会放在前面第八步中的this.messageConverters,最前面
return new HttpMessageConverters(fastJson);
}