前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringMVC源码分析

SpringMVC源码分析

作者头像
huofo
发布2022-03-17 14:26:34
3130
发布2022-03-17 14:26:34
举报
文章被收录于专栏:huofo's bloghuofo's blog

目录

一,DispatcherServlet继承结构

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

2.1 Handler方法执行的时机

打断点:

观察调用栈:

doDispathch⽅法中的1064⾏代码完成handler⽅法的调⽤

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

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

  1. 调用getHandler()获取到能够处理当前请求的执行链 HandlerExecutionChain(Handler + 拦截器)
  2. 调用getHandlerAdapter()获取能够执行Handler的适配器
  3. 适配器调用Handler执行ha.handle(),总会返回一个ModelAndView对象
  4. 调用processDispatchResult()方法完成视图跳转
代码语言:javascript
复制
//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()方法分析

代码语言:javascript
复制
	@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()方法——适配器获取分析

代码语言:javascript
复制
	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 九大组件

代码语言:javascript
复制
//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 九大组件初始化细节:

代码语言:javascript
复制
//org.springframework.web.servlet.DispatcherServlet

//主要完成组件的初始化
@Override
protected void onRefresh(ApplicationContext context) {
	//初始化策略
	initStrategies(context);
}
代码语言:javascript
复制
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方法细节刨析:

代码语言:javascript
复制
//org.springframework.web.servlet.DispatcherServlet#doDispatch

// 4 实际处理器处理请求,返回结果视图对象
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

七,processDispatchResult方法

代码语言:javascript
复制
//跳转视图页面,渲染视图
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

render方法完成渲染

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-12-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一,DispatcherServlet继承结构
  • 二、SpringMvc请求处理的大致流程
    • 2.1 Handler方法执行的时机
      • 2.2 页面渲染时机(打断点并观察调用栈)
        • 3.3 doDispatch()方法核心步骤 (Springmvc处理请求的大致流程):
        • 三,getHandler()方法分析
        • 四,getHandlerAdapter()方法——适配器获取分析
        • 五,SpringMVC九大组件初始化
          • 5.1 九大组件
            • 5.2 九大组件初始化细节:
              • 5.2.1 initHandlerMappings(context)
              • ***注意 多文件上传的组件(MultipartResolver)必须按照id注册对象:
          • 六,Handler方法细节刨析:
          • 七,processDispatchResult方法
            • render方法完成渲染
            相关产品与服务
            容器服务
            腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档