一,DispatcherServlet继承结构
二、SpringMvc请求处理的大致流程
2.1 Handler方法执行的时机
打断点:
观察调用栈:
doDispathch⽅法中的1064⾏代码完成handler⽅法的调⽤2.2 页面渲染时机(打断点并观察调用栈)
2.3 doDispatch()方法核心步骤 (Springmvc处理请求的大致流程):
- 调用getHandler()获取到能够处理当前请求的执行链 HandlerExecutionChain(Handler + 拦截器)
- 调用getHandlerAdapter()获取能够执行Handler的适配器
- 适配器调用Handler执行ha.handle(),总会返回一个ModelAndView对象
- 调用processDispatchResult()方法完成视图跳转
//org.springframework.web.servlet.DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
//执行器链,包含了handler和一些拦截器
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
//异步管理器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
//1\. 检查是否是文件上传的请求
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
/*
2\. 取得处理当前请求的Controller,这里也称为Handler,即处理器。这里并不是直接返回controller,
而是返回HandlerExecutionChain 请求处理链对象 该对象封装了Handler和Inteceptor
*/
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
// 如果handler为空, 则返回404
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
// 3\. 获取处理请求的处理器适配器 HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
// 处理last-modeified 请求头
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;
}
// Actually invoke the handler.
// 4 实际处理器处理请求,返回结果视图对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//结果视图对象的处理
applyDefaultViewName(processedRequest, mv);
//==============拦截器的第二个拦截时机
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);
}
//跳转视图页面,渲染视图
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
//最终会调用HandlerInterceptor的afterCompletion方法
//========拦截器的第三个拦截时机————视图页面渲染完成之后拦截
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
//最终会调用HandlerInterceptor的afterCompletion方法
//========拦截器的第三个拦截时机————视图页面渲染完成之后拦截
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);
}
}
}
}
三,getHandler()方法分析
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
//handlerMappings是一个 ArrayList ———— List<HandlerMapping> handlerMappings
//而HandlerMapping 则存储了url和handler的映射关系
if (this.handlerMappings != null) {
/**
* 遍历 handlerMappings :
* 1\. BeanNameUrlHandlerMapping ,早期的一种使用方式
* 2\. RequestMappingHandlerMapping,我们的请求所使用的
*/
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
HandlerExecutionChain 包含了 DemoController.handle01 以及 0个 interceptors
Q:HandlerMapping里面的映射关系是在何时进行初始化的?
A:在容器启动时时,IOC容器在扫描@Controller对象时会扫描@RequestMapping注解,然后就可以建立url和handler方法的映射关系
四,getHandlerAdapter()方法——适配器获取分析
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
//List<HandlerAdapter> handlerAdapters
if (this.handlerAdapters != null) {
/*
遍历 handlerAdapters:
遍历各个HandlerAdapter,看哪个Adapter⽀持处理当前Handler:
handlerAdapters是一个List<HandlerAdapter>,HandlerAdapter是一个接口,里面有几个实现类:
1\. HttpRequestHandlerAdapter ——实现接口的方式
2\. SimpleControllerHandlerAdapter ——实现Controller接口的方式
3\. RequestMappingHandlerAdapter ——是不是HandlerMethod(RequestMappingHandlerMapping封装的)的实例
*/
for (HandlerAdapter adapter : this.handlerAdapters) {
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");
}
Q:handlerAdapters 中三个 实现类是如何初始化的?
A:这些组件简单的说也是容器启动时初始化的。
五,SpringMVC九大组件初始化
5.1 九大组件
//org.springframework.web.servlet.DispatcherServlet
//多部件解析器,文件上传之类的
@Nullable
private MultipartResolver multipartResolver;
//区域化 国际化解析器
@Nullable
private LocaleResolver localeResolver;
//主题解析器
@Nullable
private ThemeResolver themeResolver;
//处理器映射器组件
@Nullable
private List<HandlerMapping> handlerMappings;
//处理器适配器组件
@Nullable
private List<HandlerAdapter> handlerAdapters;
//异常解析器
@Nullable
private List<HandlerExceptionResolver> handlerExceptionResolvers;
//默认视图名转换器组件
@Nullable
private RequestToViewNameTranslator viewNameTranslator;
//flash属性管理组件
@Nullable
private FlashMapManager flashMapManager;
//视图解析器
@Nullable
private List<ViewResolver> viewResolvers;
上述九大组件都是定义了接口,接口其实是定义了规范。
5.2 九大组件初始化细节:
//org.springframework.web.servlet.DispatcherServlet
//主要完成组件的初始化
@Override
protected void onRefresh(ApplicationContext context) {
//初始化策略
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
// 多文件上传的组件
initMultipartResolver(context);
// 初始化本地语语言环境
initLocaleResolver(context);
// 初始化模板处理器
initThemeResolver(context);
// 初始化HandlerMapping
initHandlerMappings(context);
// 初始化参数适配器
initHandlerAdapters(context);
// 初始化异常拦截器
initHandlerExceptionResolvers(context);
// 初始化视图预处理器
initRequestToViewNameTranslator(context);
// 初始化视图转换器
initViewResolvers(context);
// 初始化FlashMap 管理器
initFlashMapManager(context);
}
onRefresh方法何时被调用?
在此方法中打一个断点,然后Debug模式启动,然后观察调用栈。
可以看到,最初是由refresh方法调用的——finishRefresh(),由finishRefresh()发布事件,然后触发事件监听,最终到了onRefresh方法。
重点来看:
5.2.1 initHandlerMappings(context)
默认的配置:
initHandlerAdapters同理
注意 多文件上传的组件(MultipartResolver)必须按照id注册对象:
六,Handler方法细节剖析:
//org.springframework.web.servlet.DispatcherServlet#doDispatch
// 4 实际处理器处理请求,返回结果视图对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
七,processDispatchResult方法
//跳转视图页面,渲染视图
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
网友评论