springmvc 执行流程
浏览器请求地址:localhost:8080/hello
1、请求经过前置控制器(DispatchServlet)
DispatchServlet 在服务启动的时候创建 (就是你的web.xml配置的)
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 配置初始配置化文件,前面contextConfigLocation看情况二选一 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:config/spring-mvc.xml</param-value>
</init-param>
<!-- 启动加载一次 -->
<load-on-startup>1</load-on-startup>
</servlet>
并进行一些初始化 (initHandlerMappings 、initHandlerAdapters、initViewResolvers这三个看着是不是很熟悉)
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
DispatchServlet其实就是对Servle进行的拓展:DispatcherServlet 继承FrameworkServlet,FrameworkServlet继承HttpServletBean,HttpServletBean 继承httpServlet。DispatcherServlet 中重写了FrameworkServlet的doService方法:
其中的doDispatch(request, response)方法就是springMVC的核心流程
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
//日志
// ... 填充属性
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
try {
// 这是就是springmvc的核心流程
doDispatch(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
2 DispatchServlet 将请求打到处理器映射器HandlerMapping,
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zUDZEcd1-1656647671845)(C:\Users\Administrator.IWDNDRD3NDNEC2F\AppData\Roaming\Typora\typora-user-images\image-20220701111831072.png)]
HandlerMapping的主要职责就是解析url,找到对应的控制器(controller),HandlerMapping就是一系列的map,初始化时存储url和controller的映射关系。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-giFdu1SV-1656647671847)(C:\Users\Administrator.IWDNDRD3NDNEC2F\AppData\Roaming\Typora\typora-user-images\image-20220701110944928.png)]
通常我们写的controller都在RequestMappingHandlerMapping中,其中有的三个map[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zUlD77Um-1656647671847)(C:\Users\Administrator.IWDNDRD3NDNEC2F\AppData\Roaming\Typora\typora-user-images\image-20220701111226122.png)]
urlmap存储的是url的关系
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6GVlBZmu-1656647671848)(C:\Users\Administrator.IWDNDRD3NDNEC2F\AppData\Roaming\Typora\typora-user-images\image-20220701111309183.png)]
handlerMethods 中是方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-azwR4Fdi-1656647671848)(C:\Users\Administrator.IWDNDRD3NDNEC2F\AppData\Roaming\Typora\typora-user-images\image-20220701111547427.png)]
HandlerMapping返回的是HandlerExecutionChain(包括处理器和拦截器)
3 DispatchServlet 拿到handel后,交给处理器适配器HandlerAdapter处理,适配器顾名思义采用的是适配器的模式,为什么需要适配器呢?适配器的处理对象是处理器,因为处理器种类有很多,需要适配器去适配,找到对应的适配器后即可通过反射的方式执行方法接口。
4 处理器处理完成后 返回给DispatchServlet 的ModelAndVIew,DispatchServlet 拿到ModelAndVIew交给视图解析器
5 渲染
源码:
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 {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 根据url 获取处理器(遍历mapping)
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 根据处理器获取适配器
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;
}
}
// 执行拦截器方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 反射调用方法 返回modelAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 处理视图 如果没有视图设置为空
applyDefaultViewName(request, mv);
// 执行每个拦截器的后置执行方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
// 异常处理和渲染页面。
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Error err) {
triggerAfterCompletionWithError(processedRequest, response, mappedHandler, 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);
}
}
}
}