一般我们会在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请求的相关推荐

  1. spring源码分析第四天------springmvc核心原理及源码分析

    spring源码分析第四天------springmvc核心原理及源码分析 1.基础知识普及 2. SpringMVC请求流程 3.SpringMVC代码流程 4.springMVC源码分析 4.1 ...

  2. spring源码分析第六天------spring经典面试问题

    spring源码分析第六天------spring经典面试问题 1.Spring5 新特性及应用举例 2.Spring 经典的面试问题 a.什么是 Spring 框架?Spring 框架有哪些主要模块 ...

  3. SpringMVC源码分析_1 SpringMVC容器启动和加载原理

                                                                    SpringMVC源码分析_1 SpringMVC启动和加载原理     ...

  4. Spring 源码分析 (一)——迈向 Spring 之路

    一切都是从 Bean 开始的 在 1996 年,Java 还只是一个新兴的.初出茅庐的编程语言.人们之所以关注她仅仅是因为,可以使用 Java 的 Applet 来开发 Web 应用.但这些开发者很快 ...

  5. Spring 源码分析(四) ——MVC(二)概述

    随时随地技术实战干货,获取项目源码.学习资料,请关注源代码社区公众号(ydmsq666) from:Spring 源码分析(四) --MVC(二)概述 - 水门-kay的个人页面 - OSCHINA ...

  6. Spring源码分析之Bean的创建过程详解

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...

  7. Spring 源码分析衍生篇十 :Last-Modified 缓存机制

    文章目录 一.前言 二.Last-Modify 三.实现方案 1. 实现 org.springframework.web.servlet.mvc.LastModified接口 1.1. 简单演示 1. ...

  8. Spring源码分析【1】-Tomcat的初始化

    org.apache.catalina.startup.ContextConfig.configureStart() org.apache.catalina.startup.ContextConfig ...

  9. spring源码分析之spring-core总结篇

    1.spring-core概览 spring-core是spring框架的基石,它为spring框架提供了基础的支持. spring-core从源码上看,分为6个package,分别是asm,cgli ...

最新文章

  1. 每天学一点Scala之 伴生类和伴生对象
  2. 中国大学MOOC 计算机组成原理第3章 测试
  3. python 除数总是提示为0_python负数求余不正确?——取模 VS 取余
  4. weblogic-开发模式转变为生产模式生产模式转变为开发模式
  5. 互联网产品一网易网站设计(思想)
  6. java解析xml文件
  7. python函数的传参要求_python函数传参问题,一直没弄明白
  8. 红米手机Pro超简单刷入开发版获得ROOT超级权限的步骤
  9. WPF 点击按钮打开新窗口
  10. 凯利公式和复利公式,与概率和时间为友
  11. java 生成ppt_Java 创建并应用幻灯片母版
  12. 商业研究(17):以小见大,看互联网经济(4个股权众筹平台,4个领域,10个项目,8个图)
  13. [Java] 身份证号码验证
  14. 如何降低疾病监测的漏诊比率?一种新的分类学习算法
  15. 普通IPC接入神目爱买系统操作说明(智能人脸抓拍盒利旧方案)
  16. 基于jsp+mysql+java+ssm高校学生成绩管理系统——计算机毕业设计
  17. 微信小程序-实现分享(带参数)
  18. 新型的领导者是一名推动者,而不是一名发号施令者
  19. (更新时间)2021年6月2日 商城高并发秒杀系统(.NET Core版) 20-性能优化-系统配置
  20. WikiText数据集_自然语言处理

热门文章

  1. java8(1)--- lambda
  2. python学习(day1)初识入门
  3. 微信收费事件背后被广泛忽略的技术细节
  4. OXite 微软一款基于asp.net mvc架构的blog内容管理系统
  5. 【SVN】SVN 的使用新手指南,具体到步骤详细介绍----TortoiseSVN
  6. JUnit5 @Tag注解示例
  7. Java 枚举(enum)
  8. sf | 空间矢量对象的“聚合”操作
  9. eplan备份时卡顿_EPLAN卡顿了怎么办?
  10. 金融数据分析与挖掘实战1.4.1-1.4.3