文档章节

【spring】- springmvc 工作原理

ZeroneLove
 ZeroneLove
发布于 02/24 07:44
字数 985
阅读 38
收藏 7

核心:前端控制器:DispatcherServlet

功能:MVC设计模式中的Controller角色,掌控全局


类图


原理

本质是将DispatcherServlet及关联的Spring上下文环境的初始化工作织入Servlet的生命周期内,将外部WEB请求转换为Spring Bean能处理的形式,然后将处理后的结果借助于符合J2EE规范组件,呈现给客户端。

步骤

  1. HttpServletBean: init(),内部调用initServletBean完成Servlet的初始化

  2. FrameworkServlet 重写 initServletBean()方法,方法内部调用 initWebApplicationContext()方法完成与DispatcherServlet关联的web应用上下文的初始化工作,应用环境的基础环境的初始化工作由子类DispatcherServlet的onRefresh方法完成。

  3. DispatcherServlet.onRefresh方法内部调用:initStrategies方法完成Springmvc需要的各种组件的初始化工作,至此springmvc可提供完整的外部应用访问功能。

protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

springmvc 默认配置文件:DispatcherServlet.properties


Springmvc 客户端请求处理过程

核心方法:doService,本质是对Serlvet接口的service方法的最终实现。

doService:完成应用请求的数据封装封装,内部调用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 {
		//判断外部请求是否是多部分请求(一般用于文件上传)
			processedRequest = checkMultipart(request);  
			multipartRequestParsed = processedRequest != request;

			// 根据请求请求获取请求处理器:注意这里会返回对应的处理器以及潜在的拦截器
			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()) {
					String requestUri = urlPathHelper.getRequestUri(request);
					logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
				}
				if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
					return;
				}
			}

			//前置拦截器拦截请求
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}

			try {
				// 处理器适配器将请求传递给控制器处理,获取ModelView对象
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
			}
			finally {
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
			}
								
			//设置视图名
			applyDefaultViewName(request, mv);

			//后置拦截器拦截请求
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}
		catch (Exception ex) {
			dispatchException = ex;
		}

		//处理控制器返回的结果ModelAndView,主要是讲model的数据填充view,渲染后将数据返回给客户端显示
		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
			mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
			return;
		}
		// Clean up any resources used by a multipart request.
		if (multipartRequestParsed) {
			cleanupMultipart(processedRequest);
		}
	}
}

springmvc 请求响应:

主要是将MappingHandler返回的ModelAndView种的Model数据填充到view,并借助于servlet容器(例如tomcat)呈现给客户端。

AbstractView. render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response):

//具体执行代码
renderMergedOutputModel(mergedModel, request, response);

案例分析:内部资源视图(例JSP) InternalResourceView. renderMergedOutputModel

protected void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		//封装客户端可视的请求资源数据
		HttpServletRequest requestToExpose = getRequestToExpose(request);
		exposeModelAsRequestAttributes(model, requestToExpose);

		//客户端请求添加辅助信息
		exposeHelpers(requestToExpose);

		// 获取请求转发路径
		String dispatcherPath = prepareForRendering(requestToExpose, response);

		//获取目标资源的请求调度器
		RequestDispatcher rd = getRequestDispatcher(requestToExpose, dispatcherPath);
		if (rd == null) {
			throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
					"]: Check that the corresponding file exists within your web application archive!");
		}

		//如果一个URL的内部请求则进行响应资源追加,例如网页内的图片链接等
		if (useInclude(requestToExpose, response)) {
			response.setContentType(getContentType());
			if (logger.isDebugEnabled()) {
				logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}
			rd.include(requestToExpose, response);
		}
		else {
			// Note: The forwarded resource is supposed to determine the content type itself.
			if (logger.isDebugEnabled()) {
				logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");
			}

			//repuest请求转发,说明springmvc采用的转发而不是重定向的方式
			rd.forward(requestToExpose, response);
		}
	}

© 著作权归作者所有

ZeroneLove
粉丝 6
博文 164
码字总数 133695
作品 0
深圳
高级程序员
私信 提问
Spring Boot实战与原理分析

Spring Boot实战与原理分析 1:Spring Boot概述与课程概要介绍 2:Spring4 快速入门 3:Spring4 扩展分析(一) 4:Spring4 扩展分析(二) 5:Spring Boot 快速入门 6:Spring Boot 配置分析...

刘宗泽
2018/06/26
0
0
关于 Struts2 和 SpringMVC 区别?

又是一个常问的面试题,真是面试一次长一次见识。 那我们先就从原理出发: springMVC 原理(见下图): SpringMVC 流程 1、 用户发送请求至前端控制器 DispatcherServlet。 2、 DispatcherSe...

举个_栗子
2017/11/03
75
0
Java面试分享(题目+答案)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/t4i2b10X4c22nF6A/article/details/84535277 1.说下Struts的设计模式 2.拦截器和过滤器的区别? 3.struts2框架...

JAVA高级架构v
2018/11/25
0
0
spring boot配置文件相关

1.spring boot配置文件的格式 properties格式 yaml格式 yaml格式的配置文件在spring中会存在一个缺陷,@PropertySource注解不支持读取yaml配置文件,仅支持properties配置文件。不过这个问题...

lara_
07/03
31
0
仿照源码,手写一个自定义 Spring MVC 框架

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 https://blog.csdn.net/GitChat/article/details/97947618 前言 上节课我们学习了 Spring M...

GitChat技术杂谈
07/31
0
0

没有更多内容

加载失败,请刷新页面

加载更多

vue 2打包注意点

使用npm run build打包之后往往直接本地运行,路径类似这样:http://127.0.0.1:5500/xa/dist/index.html 或者http://127.0.0.1:5500/dist/index.html。然后页面打开是空白的,打开控制台查看...

牧云橙
26分钟前
4
0
归并排序

1.原理图 2.代码 public static void merge(int []a,int left,int mid,int right){ int []tmp=new int[a.length];//辅助数组 int p1=left,p2=mid+1,k=left;//p1、p2是检测......

wen123
29分钟前
4
0
css实现透明的两种方法

一、opacity:0~1 值越高,透明度越低: div{opacity:0.5 } 选择器匹配到的节点们,包括节点们的孩子节点,都会实现%50透明,另 0.5 可直接写成 .5 二、rgba(0~255,0~255,0~255,0~1) r...

Bing309
32分钟前
4
0
Tomcat 配置访问路径

此处只是部署完成后idea打开的默认路径,并非项目部署路径, 此处才是项目实际部署路径,可以有多个项目部署路径,idea可以配置默认打开一个

Aeroever
35分钟前
4
0
将ApiBoot Logging采集的日志上报到Admin

通过ApiBoot Logging可以将每一条请求的详细信息获取到,在分布式部署方式中,一个请求可能会经过多个服务,如果是每个服务都独立保存请求日志信息,我们没有办法做到统一的控制,而且还会存...

恒宇少年
36分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部