写点什么

太厉害了!这是我见过最好的 SpringMVC 源码分析

  • 2023-03-15
    湖南
  • 本文字数:4248 字

    阅读完需:约 14 分钟

一、DispatcherServlet 继承结构

二、SpringMvc 请求处理的大致流程

2.1 Handler 方法执行的时机

打断点:


观察调用栈:


doDispathch 方法中的 1064 行代码完成 handler 方法的调用

2.2 页面渲染时机(打断点并观察调用栈)

2.3 doDispatch()方法核心步骤 (Springmvc 处理请求的大致流程):

  1. 调用 getHandler()获取到能够处理当前请求的执行链 HandlerExecutionChain(Handler + 拦截器)

  2. 调用 getHandlerAdapter()获取能够执行 Handler 的适配器

  3. 适配器调用 Handler 执行 ha.handle(),总会返回一个 ModelAndView 对象

  4. 调用 processDispatchResult()方法完成视图跳转

//org.springframework.web.servlet.DispatcherServletprotected 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		//多部件解析器,文件上传之类的@Nullableprivate MultipartResolver multipartResolver;
//区域化 国际化解析器@Nullableprivate LocaleResolver localeResolver;
//主题解析器@Nullableprivate ThemeResolver themeResolver;
//处理器映射器组件@Nullableprivate List<HandlerMapping> handlerMappings;
//处理器适配器组件@Nullableprivate List<HandlerAdapter> handlerAdapters;
//异常解析器@Nullableprivate List<HandlerExceptionResolver> handlerExceptionResolvers;
//默认视图名转换器组件@Nullableprivate RequestToViewNameTranslator viewNameTranslator;
//flash属性管理组件@Nullableprivate FlashMapManager flashMapManager;
//视图解析器@Nullableprivate List<ViewResolver> viewResolvers;
复制代码

上述九大组件都是定义了接口,接口其实是定义了规范。

5.2 九大组件初始化细节:

//org.springframework.web.servlet.DispatcherServlet
//主要完成组件的初始化@Overrideprotected 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);
复制代码

render 方法完成渲染


作者:邓晓晖

地址:https://www.cnblogs.com/isdxh/p/14115123.html

用户头像

还未添加个人签名 2021-07-28 加入

公众号:该用户快成仙了

评论

发布
暂无评论
太厉害了!这是我见过最好的SpringMVC源码分析_Java_做梦都在改BUG_InfoQ写作社区