在使用springmvc框架,会在web.xml文件配置一个DispatcherServlet,这正是web容器开始初始化,同时会在建立自己的上下文来持有SpringMVC的bean对象。

先从DispatcherServlet入手,从名字来看,它是一个Servlet。它的定义如下:

  1. public class DispatcherServlet extends FrameworkServlet {

它是继承FrameworkServlet,来看一下整个的继承关系。

从继承关系来看,DispatcherServlet继承FrameworkServlet和HttpServletBean而继承HttpServlet,通过使用Servlet API 来对HTTP请求进行响应,成为SpringMVC的前端处理器。

先看一个时序图

注:作为Servlet,DispatcherServlet的启动和Servlet的启动相关联的。在Servlet初始化过程中,Servlet的init方法会被调用,以进行初始化,然而DispatcherServlet的基类,所以从HttpServletBean中的初始化过程开始。

DispatcherServlet的工作分为2部分,一部分是初始化(也就是图的上半部分),有initServletBean()启动,通过initWebApplicationContext()方法最终调用DispatcherServlet中的initStrategies()方法。另一部分(也就是图的下半部分),是对HTTP请求进行响应,作为Servlet,Web容器会调用Servlet的doGet()和doPost()方法,在经过FrameworkServlet的processRequest()简单处理后,会调用DispatcherServlet的doService方法,在这个方法调用中封装了doDispatch(),继续调用processDispatchResult方法返回调用信息。

接下来看看初始化的源码的流程:

HttpServletBean.init方法

  1. /**
  2. * Map config parameters onto bean properties of this servlet, and
  3. * invoke subclass initialization.
  4. * @throws ServletException if bean properties are invalid (or required
  5. * properties are missing), or if subclass initialization fails.
  6. */
  7. @Override
  8. public final void init() throws ServletException {
  9. if (logger.isDebugEnabled()) {
  10. logger.debug("Initializing servlet '" + getServletName() + "'");
  11. }
  12.           //获取Servlet初始化参数
  13. // Set bean properties from init parameters.
  14. try {
  15. PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
  16. BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
  17. ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
  18. bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
  19. initBeanWrapper(bw);
  20. bw.setPropertyValues(pvs, true);
  21. }
  22. catch (BeansException ex) {
  23. logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
  24. throw ex;
  25. }
  26. //调用子类的方法
  27. // Let subclasses do whatever initialization they like.
  28. initServletBean();
  29.  
  30. if (logger.isDebugEnabled()) {
  31. logger.debug("Servlet '" + getServletName() + "' configured successfully");
  32. }
  33. }

  例如web.xml中配置参数:

  1. <servlet>
  2. <servlet-name>TestServlet</servlet-name>
  3. <servlet-class>com.lzyer.TestServlet</servlet-class>
  4. <!--配置参数,可以通过ServletConfig获取参数-->
  5. <init-param>
  6. <param-name>servlet-name</param-name>
  7. <param-value>TestServlet</param-value>
  8. </init-param>
  9. </servlet>
  10. <servlet-mapping>
  11. <servlet-name>TestServlet</servlet-name>
  12. <url-pattern>/TestServlet</url-pattern>
  13. </servlet-mapping>

  FrameworkServlet.initServletBean方法

  1. /**
  2. * Overridden method of {@link HttpServletBean}, invoked after any bean properties
  3. * have been set. Creates this servlet's WebApplicationContext.
  4. */
  5. @Override
  6. protected final void initServletBean() throws ServletException {
  7. getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
  8. if (this.logger.isInfoEnabled()) {
  9. this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
  10. }
  11. long startTime = System.currentTimeMillis();
  12.  
  13. try {
  14. //创建Web应用上下文
  15. this.webApplicationContext = initWebApplicationContext();
  16. initFrameworkServlet();
  17. }
  18. catch (ServletException ex) {
  19. this.logger.error("Context initialization failed", ex);
  20. throw ex;
  21. }
  22. catch (RuntimeException ex) {
  23. this.logger.error("Context initialization failed", ex);
  24. throw ex;
  25. }
  26.  
  27. if (this.logger.isInfoEnabled()) {
  28. long elapsedTime = System.currentTimeMillis() - startTime;
  29. this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
  30. elapsedTime + " ms");
  31. }
  32. }

  FrameworkServlet.initWebApplicationContext()

  1. /**
  2. * Initialize and publish the WebApplicationContext for this servlet.
  3. * <p>Delegates to {@link #createWebApplicationContext} for actual creation
  4. * of the context. Can be overridden in subclasses.
  5. * @return the WebApplicationContext instance
  6. * @see #FrameworkServlet(WebApplicationContext)
  7. * @see #setContextClass
  8. * @see #setContextConfigLocation
  9. */
  10. protected WebApplicationContext initWebApplicationContext() {
  11. WebApplicationContext rootContext =
  12. WebApplicationContextUtils.getWebApplicationContext(getServletContext());
  13. WebApplicationContext wac = null;
  14.  
  15. if (this.webApplicationContext != null) {
  16. // A context instance was injected at construction time -> use it
  17. wac = this.webApplicationContext;
  18. if (wac instanceof ConfigurableWebApplicationContext) {
  19. ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
  20. if (!cwac.isActive()) {
  21. // The context has not yet been refreshed -> provide services such as
  22. // setting the parent context, setting the application context id, etc
  23. if (cwac.getParent() == null) {
  24. // The context instance was injected without an explicit parent -> set
  25. // the root application context (if any; may be null) as the parent
  26. cwac.setParent(rootContext);
  27. }
  28. configureAndRefreshWebApplicationContext(cwac);
  29. }
  30. }
  31. }
  32. if (wac == null) {
  33. // No context instance was injected at construction time -> see if one
  34. // has been registered in the servlet context. If one exists, it is assumed
  35. // that the parent context (if any) has already been set and that the
  36. // user has performed any initialization such as setting the context id
  37. wac = findWebApplicationContext();
  38. }
  39. if (wac == null) {
  40. // No context instance is defined for this servlet -> create a local one
  41. wac = createWebApplicationContext(rootContext);
  42. }
  43.  
  44. if (!this.refreshEventReceived) {
  45. // Either the context is not a ConfigurableApplicationContext with refresh
  46. // support or the context injected at construction time had already been
  47. // refreshed -> trigger initial onRefresh manually here.
  48. onRefresh(wac);
  49. }
  50.  
  51. if (this.publishContext) {
  52. // Publish the context as a servlet context attribute.
  53. String attrName = getServletContextAttributeName();
  54. getServletContext().setAttribute(attrName, wac);
  55. if (this.logger.isDebugEnabled()) {
  56. this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
  57. "' as ServletContext attribute with name [" + attrName + "]");
  58. }
  59. }
  60.  
  61. return wac;
  62. }

  先看WebApplicationContextUtils.getWebApplicationContext(getServletContext()),,主要是从ServletContext获取WebApplicationContext

  1. public static WebApplicationContext getWebApplicationContext(ServletContext sc, String attrName) {
  2. Assert.notNull(sc, "ServletContext must not be null");
    //从ServletContext中获取
  3. Object attr = sc.getAttribute(attrName);
  4. if (attr == null) {
  5. return null;
  6. }
  7. if (attr instanceof RuntimeException) {
  8. throw (RuntimeException) attr;
  9. }
  10. if (attr instanceof Error) {
  11. throw (Error) attr;
  12. }
  13. if (attr instanceof Exception) {
  14. throw new IllegalStateException((Exception) attr);
  15. }
  16. if (!(attr instanceof WebApplicationContext)) {
  17. throw new IllegalStateException("Context attribute is not of type WebApplicationContext: " + attr);
  18. }
  19. return (WebApplicationContext) attr;
  20. }

 findWebApplicationContext和上面一样从ContextServlet中查找,如果不存在就调用下面的createWebApplicationContext方法。

  1. protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
              //获取contextClass
  2. Class<?> contextClass = getContextClass();
  3. if (this.logger.isDebugEnabled()) {
  4. this.logger.debug("Servlet with name '" + getServletName() +
  5. "' will try to create custom WebApplicationContext context of class '" +
  6. contextClass.getName() + "'" + ", using parent context [" + parent + "]");
  7. }
  8. if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
  9. throw new ApplicationContextException(
  10. "Fatal initialization error in servlet with name '" + getServletName() +
  11. "': custom WebApplicationContext class [" + contextClass.getName() +
  12. "] is not of type ConfigurableWebApplicationContext");
  13. }
    //通过反射获取实例
  14. ConfigurableWebApplicationContext wac =
  15. (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
  16.  
  17. wac.setEnvironment(getEnvironment());
    //设置双亲上下文
  18. wac.setParent(parent);
  19. wac.setConfigLocation(getContextConfigLocation());
  20. //配置和刷新应用
  21. configureAndRefreshWebApplicationContext(wac);
  22.  
  23. return wac;
  24. }

  看一下getContextClass()到底是哪个类? XmlWebApplicationContext.class

最后configureAndRefreshWebApplicationContext调用refresh方法启动容器。

回到initWebApplicationContext方法中

  1. if (!this.refreshEventReceived) {
  2. // Either the context is not a ConfigurableApplicationContext with refresh
  3. // support or the context injected at construction time had already been
  4. // refreshed -> trigger initial onRefresh manually here.
  5. onRefresh(wac);
  6. }

  这个会触发SpringMVC初始化策略

  1. /**
  2. * This implementation calls {@link #initStrategies}.
  3. */
  4. @Override
  5. protected void onRefresh(ApplicationContext context) {
  6. initStrategies(context);
  7. }
  8.  
  9. /**
  10. * Initialize the strategy objects that this servlet uses.
  11. * <p>May be overridden in subclasses in order to initialize further strategy objects.
  12. */
  13. protected void initStrategies(ApplicationContext context) {
  14. initMultipartResolver(context);
  15. initLocaleResolver(context);
  16. initThemeResolver(context);
    //映射关系
  17. initHandlerMappings(context);
  18. initHandlerAdapters(context);
  19. initHandlerExceptionResolvers(context);
  20. initRequestToViewNameTranslator(context);
  21. initViewResolvers(context);
  22. initFlashMapManager(context);
  23. }

  到此,SpringMVC的初始化的流程大概就是这样,下篇就是SpringMVC请求流程。

SpringMVC源码解析-DispatcherServlet启动流程和初始化的更多相关文章

  1. Flume-ng源码解析之启动流程

    今天我们通过阅读Flume-NG的源码来看看Flume的整个启动流程,废话不多说,翠花,上源码!! 1 主类也是启动类 在这里我贴出Application中跟启动有关的方法,其他你们可以自己看源码,毕 ...

  2. SpringMVC源码分析和启动流程

    https://yq.aliyun.com/articles/707995 在Spring的web容器启动时会去读取web.xml文件,相关启动顺序为:<context-param> -- ...

  3. springMVC源码解析--ViewResolver视图解析器执行(三)

    之前两篇博客springMVC源码分析--ViewResolver视图解析器(一)和springMVC源码解析--ViewResolverComposite视图解析器集合(二)中我们已经简单介绍了一些 ...

  4. SpringMVC源码剖析1——执行流程

    SpringMVC源码剖析1——执行流程 00.SpringMVC执行流程file:///C:/Users/WANGGA~1/AppData/Local/Temp/enhtmlclip/Image.p ...

  5. SpringMVC源码解析- HandlerAdapter - ModelFactory(转)

    ModelFactory主要是两个职责: 1. 初始化model 2. 处理器执行后将modle中相应参数设置到SessionAttributes中 我们来看看具体的处理逻辑(直接充当分析目录): 1 ...

  6. SpringMVC源码解析- HandlerAdapter - ModelFactory

    ModelFactory主要是两个职责: 1. 初始化model 2. 处理器执行后将modle中相应参数设置到SessionAttributes中 我们来看看具体的处理逻辑(直接充当分析目录): 1 ...

  7. Netty源码解析—客户端启动

    Netty源码解析-客户端启动 Bootstrap示例 public final class EchoClient { static final boolean SSL = System.getPro ...

  8. Sentinel源码解析一(流程总览)

    引言 Sentinel作为ali开源的一款轻量级流控框架,主要以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度来帮助用户保护服务的稳定性.相比于Hystrix,Sentinel的设计更加简 ...

  9. [源码解析] PyTorch分布式(6) -------- DistributedDataParallel -- 初始化&store

    [源码解析] PyTorch分布式(6) ---DistributedDataParallel -- 初始化&store 目录 [源码解析] PyTorch分布式(6) ---Distribu ...

随机推荐

  1. Python函数变量和返回值

    Python函数的全局变量和局部变量 1.不同的编程语言,程序可以分为函数和过程两大类,函数具有具体返回值,而过程则不具有具体的返回值,python只具有函数,因为对于它的一般函数,其返回值为所具体返 ...

  2. C#使用EF连接PGSql数据库

    前言 由于项目需要,使用到了PGSql数据库,说实话这是第一次接触并且听说PGSql(PostgreSQL)关系型数据库,之前一直使用的都是SqlServer,一头雾水的各种找资源,终于将PGSql与 ...

  3. Laxcus大数据管理系统2.0(12)- 第十章 运行

    第十章 运行 本章将介绍一些Laxcus集群基本运行.使用情况,结合图片和表格表示.地点是我们的大数据实验室,使用我们的实验集群.数据来自于我们的合作伙伴,软件平台混合了Windows和Fedora  ...

  4. C复合文字

    C99之前,可以传递数组,但是没有所谓的数组常量可供传递,于是新增了复合文字. 普通数组声明方法: int d[2]={10,20}; 复合文字声明: 与数组名相同,常量同时代表元素的地址. (int ...

  5. Hadoop第一课:Hadoop集群环境搭建

    一. 检查列表 1.1.网络访问 设置电脑IP以及可以访问网络设置:进入etc/sysconfig/network-scripts/,使用命令“ls -all” 查看文件.会看到ifcfg-lo文件然 ...

  6. Python3 Tkinter-Frame

    1.创建 from tkinter import * root=Tk() for fm in ['red','blue','yellow','green','white','black']: Fram ...

  7. 软件管理——rpm&dpkg、yum&apt-get

    一般来说著名的linux系统基本上分两大类: 1. RedHat系列:Redhat.Centos.Fedora等 2. Debian系列:Debian.Ubuntu等 一.RedHat 系列     ...

  8. Bus of Characters(栈和队列)

    In the Bus of Characters there are nn rows of seat, each having 22 seats. The width of both seats in ...

  9. Web界面和Winform界面生成,代码生成工具

    在上面一篇随笔<代码生成工具之界面快速生成>介绍了代码生成工具Database2Sharp的界面生成操作,其中介绍了Web界面(包括列表界面.内容显示.内容编辑界面的生成,另外还介绍了Wi ...

  10. AWVS使用基础教程

    什么是AWVS Acunetix Web Vulnerability Scanner(简称AWVS)是一款知名的网络漏洞扫描工具,它通过网络爬虫测试你的网站安全,检测流行安全漏洞,现已更新到10.(下 ...