Spring源码分析之SpringMVC的DispatcherServlet是如何处理Http请求的
一般我们会在web.xml文件中配置DispatcherServlet,比如如下配置方式:
<servlet><servlet-name>dispatcherServlet</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:dispatcher-servlet.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>dispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
上述代码配置了所有路径的http请求都会交给DispatcherServlet来处理
那么我们来看下DispatcherServlet的具体代码:
@SuppressWarnings("serial")
public class DispatcherServlet extends FrameworkServlet {public DispatcherServlet(WebApplicationContext webApplicationContext) {super(webApplicationContext);setDispatchOptionsRequest(true);}@Overrideprotected void onRefresh(ApplicationContext context) {initStrategies(context);}/*** Initialize the strategy objects that this servlet uses.* <p>May be overridden in subclasses in order to initialize further strategy objects.*/protected void initStrategies(ApplicationContext context) {initMultipartResolver(context);initLocaleResolver(context);initThemeResolver(context);initHandlerMappings(context);initHandlerAdapters(context);initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);initViewResolvers(context);initFlashMapManager(context);}@Overrideprotected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {}protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {}
可以看到这个类继承了FrameworkServlet类,再来看下这个类的代码:
@SuppressWarnings("serial")
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {@Overrideprotected final void initServletBean() throws ServletException {}protected WebApplicationContext initWebApplicationContext() {if (!this.refreshEventReceived) {// Either the context is not a ConfigurableApplicationContext with refresh// support or the context injected at construction time had already been// refreshed -> trigger initial onRefresh manually here.onRefresh(wac);}}@Overridepublic void destroy() {getServletContext().log("Destroying Spring FrameworkServlet '" + getServletName() + "'");// Only call close() on WebApplicationContext if locally managed...if (this.webApplicationContext instanceof ConfigurableApplicationContext && !this.webApplicationContextInjected) {((ConfigurableApplicationContext) this.webApplicationContext).close();}}/*** Override the parent class implementation in order to intercept PATCH requests.*/@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());if (HttpMethod.PATCH == httpMethod || httpMethod == null) {processRequest(request, response);}else {super.service(request, response);}}@Overrideprotected final void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}@Overrideprotected final void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);}protected final void processRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {}}
可以看到这个类继承了HttpServletBean类,而HttpServletBean类又继承了HttpServlet类,其中HttpServlet类的init,destroy,service三个方法负责管理Servlet的生命周期。
init方法:负责初始化Servlet对象
destroy方法:负责销毁Servlet对象
service方法:负责处理http请求
由于HttpServletBean实现了HttpServlet的init方法,可以看到该方法的代码如下:
public final void init() throws ServletException {if (logger.isDebugEnabled()) {logger.debug("Initializing servlet '" + getServletName() + "'");}// Set bean properties from init parameters.// 获取servlet初始化的参数,对Bean属性进行配置try {PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));initBeanWrapper(bw);bw.setPropertyValues(pvs, true);}catch (BeansException ex) {logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);throw ex;}// Let subclasses do whatever initialization they like.// 调用子类的initServletBean进行具体的初始化initServletBean();if (logger.isDebugEnabled()) {logger.debug("Servlet '" + getServletName() + "' configured successfully");}}
这里会读取配置在ServletContext中的Bean属性参数,这里可以看到对PropertyValues和BeanWrapper的使用,这里就完成了对Servlet的初始化
接着调用了initServletBean方法来初始化DispatcherServlet持有的IOC容器,当然底层其实是调用initWebApplicationContext方法来初始化,其代码如下:
protected WebApplicationContext initWebApplicationContext() {// 得到根上下文,这个根上下文是保存在ServletContext中的,使用这个根上下文作为当前MVC上下文的双亲上下文,当前的上下文就是wac// cwac.setParent(rootContext)就是设置当前上下文的根上下文WebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext());WebApplicationContext wac = null;if (wac == null) {// No context instance is defined for this servlet -> create a local onewac = createWebApplicationContext(rootContext);}if (!this.refreshEventReceived) {// Either the context is not a ConfigurableApplicationContext with refresh// support or the context injected at construction time had already been// refreshed -> trigger initial onRefresh manually here.onRefresh(wac);}}
可以看到createWebApplicationContext方法就是在创建并初始化IOC容器,代码如下:
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {//设置IOC容器的各个参数wac.setEnvironment(getEnvironment());wac.setParent(parent);wac.setConfigLocation(getContextConfigLocation());configureAndRefreshWebApplicationContext(wac);return wac;}
这里设置了当前IOC容器上下文的双亲上下文,双亲上下文是如下方法获取到的:
WebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext());
这样当从IOC容器中getBean的时候会先从其双亲上下文中获取bean
configureAndRefreshWebApplicationContext方法里面调用了wac.refresh(),也就是refresh方法来真正启动对IOC容器的初始化,这里就跟IOC容器的初始化保持一致了
到这里,对DispatcherServlet所持有的IOC容器的初始化就完成了,初始化完成后,DispatcherServlet就持有一个以自己的Servlet名称命名的IOC容器了,这个IOC容器是一个WebApplicationContext对象。
我们还可以看到initWebApplicationContext方法中还调用了onrefresh方法,该方法是由DispatcherServlet来实现的,并最终调用了DispatcherServlet的如下方法来进行初始化:
protected void initStrategies(ApplicationContext context) {initMultipartResolver(context);initLocaleResolver(context);initThemeResolver(context);initHandlerMappings(context);initHandlerAdapters(context);initHandlerExceptionResolvers(context);initRequestToViewNameTranslator(context);initViewResolvers(context);initFlashMapManager(context);}
在这个方法里,DispatcherServlet对MVC模块的其他部分进行了初始化,比如handlerMapping,ViewResolver等,它是启动整个Spring MVC框架的初始化
比如,支持国际化的LocalResolver,支持request映射的HandlerMapping,以及视图生成的ViewResolver等的初始化
这里的initHandlerMapping是为HTTP请求找到相应的Controller控制器。
DispatcherServlet的整个初始化过程就到这里结束了,下面说下DispatcherServlet是如何处理http请求的
首先http请求是由doService来处理的,那么我们可以看下HttpServlet类的该方法:
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String method = req.getMethod();long errMsg;if(method.equals("GET")) {errMsg = this.getLastModified(req);if(errMsg == -1L) {this.doGet(req, resp);} else {long ifModifiedSince = req.getDateHeader("If-Modified-Since");if(ifModifiedSince < errMsg) {this.maybeSetLastModified(resp, errMsg);this.doGet(req, resp);} else {resp.setStatus(304);}}} else if(method.equals("HEAD")) {errMsg = this.getLastModified(req);this.maybeSetLastModified(resp, errMsg);this.doHead(req, resp);} else if(method.equals("POST")) {this.doPost(req, resp);} else if(method.equals("PUT")) {this.doPut(req, resp);} else if(method.equals("DELETE")) {this.doDelete(req, resp);} else if(method.equals("OPTIONS")) {this.doOptions(req, resp);} else if(method.equals("TRACE")) {this.doTrace(req, resp);} else {String errMsg1 = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[]{method};errMsg1 = MessageFormat.format(errMsg1, errArgs);resp.sendError(501, errMsg1);}}
这个方法里面会根据不同的请求类型,来调用不同的处理方法,比如会调用doGet或者doPost方法来分别处理get请求和post请求,跟踪这些方法,可以发现,最终是调用了DispatcherServlet的doService方法,代码如下:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {try {this.doDispatch(request, response);} finally {if(!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot1 != null) {this.restoreAttributesAfterInclude(request, attributesSnapshot1);}}}
可以看到该方法调用了doDispatch来进行处理,doDispatch是MVC模式的主要部分
Spring源码分析之SpringMVC的DispatcherServlet是如何处理Http请求的相关推荐
- spring源码分析第四天------springmvc核心原理及源码分析
spring源码分析第四天------springmvc核心原理及源码分析 1.基础知识普及 2. SpringMVC请求流程 3.SpringMVC代码流程 4.springMVC源码分析 4.1 ...
- spring源码分析第六天------spring经典面试问题
spring源码分析第六天------spring经典面试问题 1.Spring5 新特性及应用举例 2.Spring 经典的面试问题 a.什么是 Spring 框架?Spring 框架有哪些主要模块 ...
- SpringMVC源码分析_1 SpringMVC容器启动和加载原理
SpringMVC源码分析_1 SpringMVC启动和加载原理 ...
- Spring 源码分析 (一)——迈向 Spring 之路
一切都是从 Bean 开始的 在 1996 年,Java 还只是一个新兴的.初出茅庐的编程语言.人们之所以关注她仅仅是因为,可以使用 Java 的 Applet 来开发 Web 应用.但这些开发者很快 ...
- Spring 源码分析(四) ——MVC(二)概述
随时随地技术实战干货,获取项目源码.学习资料,请关注源代码社区公众号(ydmsq666) from:Spring 源码分析(四) --MVC(二)概述 - 水门-kay的个人页面 - OSCHINA ...
- Spring源码分析之Bean的创建过程详解
前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...
- Spring 源码分析衍生篇十 :Last-Modified 缓存机制
文章目录 一.前言 二.Last-Modify 三.实现方案 1. 实现 org.springframework.web.servlet.mvc.LastModified接口 1.1. 简单演示 1. ...
- Spring源码分析【1】-Tomcat的初始化
org.apache.catalina.startup.ContextConfig.configureStart() org.apache.catalina.startup.ContextConfig ...
- spring源码分析之spring-core总结篇
1.spring-core概览 spring-core是spring框架的基石,它为spring框架提供了基础的支持. spring-core从源码上看,分为6个package,分别是asm,cgli ...
最新文章
- 每天学一点Scala之 伴生类和伴生对象
- 中国大学MOOC 计算机组成原理第3章 测试
- python 除数总是提示为0_python负数求余不正确?——取模 VS 取余
- weblogic-开发模式转变为生产模式生产模式转变为开发模式
- 互联网产品一网易网站设计(思想)
- java解析xml文件
- python函数的传参要求_python函数传参问题,一直没弄明白
- 红米手机Pro超简单刷入开发版获得ROOT超级权限的步骤
- WPF 点击按钮打开新窗口
- 凯利公式和复利公式,与概率和时间为友
- java 生成ppt_Java 创建并应用幻灯片母版
- 商业研究(17):以小见大,看互联网经济(4个股权众筹平台,4个领域,10个项目,8个图)
- [Java] 身份证号码验证
- 如何降低疾病监测的漏诊比率?一种新的分类学习算法
- 普通IPC接入神目爱买系统操作说明(智能人脸抓拍盒利旧方案)
- 基于jsp+mysql+java+ssm高校学生成绩管理系统——计算机毕业设计
- 微信小程序-实现分享(带参数)
- 新型的领导者是一名推动者,而不是一名发号施令者
- (更新时间)2021年6月2日 商城高并发秒杀系统(.NET Core版) 20-性能优化-系统配置
- WikiText数据集_自然语言处理
热门文章
- java8(1)--- lambda
- python学习(day1)初识入门
- 微信收费事件背后被广泛忽略的技术细节
- OXite 微软一款基于asp.net mvc架构的blog内容管理系统
- 【SVN】SVN 的使用新手指南,具体到步骤详细介绍----TortoiseSVN
- JUnit5 @Tag注解示例
- Java 枚举(enum)
- sf | 空间矢量对象的“聚合”操作
- eplan备份时卡顿_EPLAN卡顿了怎么办?
- 金融数据分析与挖掘实战1.4.1-1.4.3