写在前边

本文分为两大板块

  • 监听器ContextLoaderListener源码深入分析

  • DispatchServlet开端化源码分析

正管文学习自Ali大拿RunforLove,很完美的上课小说,原来的文章:[RunforLove]
(http://www.cnblogs.com/RunForLove/p/5688731.html)

SpringMVC运营进度详细解释(阿里卡塔 尔(英语:State of Qatar),springmvcali

  通过对SpringMVC运营进程的深远钻探,期待明白Java
Web容器运营进度;掌握SpringMVC运维进程;精晓SpringMVC的配备文件如何安顿,为啥要如此安插;驾驭SpringMVC是怎么样职业的;精通Spring源码的安插性和增加阅读源码的技术。

目录

1.Web容器最初化进度

2.SpringMVC中web.xml配置

3.认识ServletContextListener

4.认识ContextLoaderListener

5.DispatcherServlet初始化(HttpServletBean • FrameworkServlet •
DispatcherServlet

6.ContextLoaderListener与DispatcherServlet关系

7.DispatcherServlet的设计

8.DispatcherServlet行事原理

 

风流浪漫、Web容器最早化进程

上海体育场地突显了web容器伊始化的进度,其合意大利语档给出了这么的陈述:

  When a web application is deployed into a container, the following
steps must be performed, in this order, before the web application
begins processing client requests.

二、SpringMVC中web.xml的配置

上航海用教室是截取的web.xml中的配置,在<listener>标签中定义了spring容器加载器;在<servlet>标签中定义了spring前端调控器。

上海体育场所是源码中接口ServletContextListener的定义,能够见到在其注释中指明:servlet和Filter开首化前和销毁后,都会给落到实处了servletContextListener接口的监听器发出相应的布告。

上边是类ContextLoadListener的概念,它完成了上边的servletContextListener。这里运用了代理形式,轻便的代办了ContextLoader类。ContextLoadListener类用来成立Spring
application context,何况将application
context注册到servletContext里面去。

重新整合方面包车型客车WEB容器运转的进度,以至接口ServletContextListener和类ContextLoadListener。大家精通:

  在 Servlet
API中有三个ServletContextListener接口,它亦可监听ServletContext对象的生命周期,实际上就是监听Web应用的生命周期。当Servlet容器运行或停止Web应用时,会触发ServletContextEvent事件,该事件由ServletContextListener来管理。在ServletContextListener接口中定义了拍卖ServletContextEvent 事件的五个主意contextInitialized()和contextDestroyed()。

  ContextLoaderListener监听器的效劳正是运维Web容器时,自动装配ApplicationContext的布置音信。因为它达成了ServletContextListener那几个接口,在web.xml配置了这些监听器,运行容器时,就能够暗中认可实践它达成的不二等秘书诀。由于在ContextLoaderListener中涉及了ContextLoader那些类,所以整个加载配置进程由ContextLoader来造成。

上边是initWebApplicationContext的经过,方法名称正是其意义。方法中率先制造了WebApplicationContext,配置何况刷新实例化整个SpringApplicationContext中的Bean。由此,倘若大家的Bean配置出错的话,在容器运行的时候,会抛极度出来的。

  综上,ContextLoaderListener类起着举足轻重的功力。它读取web.xml中配备的context-param中的配置文件,提前在web容器起首化前策动事情对应的Application
context;将开创好的Application
context放置于ServletContext中,为springMVC部分的伊始化做好希图。

三、DispatchServlet初始化

  在SpringMVC架构中,DispatchServlet担任伏乞分发,起到调节器的功能。上面详细来解释表明:

DispatchServlet名如其义,它的面目上是三个Servlet。从地点图能够见见,下层的子类不断的对HttpServlet父类实行艺术增添。

上海教室是抽象类HttpServletBean的兑现,大家领略HttpServlet有两大主导措施:init()和service()方法。HttpServletBean重写了init()方法,在此部分,大家能够见到其促成思路:公共的有些统一来完成,变化的有的统一来抽象,交给其子类来实现,故用了abstract
class来修饰类名。此外,HttpServletBean提供了四个HttpServlet的空洞达成,使的Servlet不再关注init-param部分的赋值,让servlet更关怀于自家Bean初始化的贯彻。

**上图是FrameworkServlet的官方概念, 它提供了组合web
javabean和spring application
context的组成方案。那么它是何许得以完毕的吧?在源码中大家得以看来通过履行initWebApplicationContext()方法和initFrameworkServlet()方法完毕。**

**DispatchServlet是HTTP需要的宗旨调解微处理器,它将web央求转载给controller层管理,它提供了快速的照射和至极管理机制。DispatchServlet转载倡议的骨干代码在doService()方法中落到实处,详细代码参照图上。**

上海体育场面是DispatchServlet类和ContextLoaderListener类的关联图。首先,用ContextLoaderListener早先化上下文,接着使用DispatchServlet来开始化WebMVC的上下文。

上海体育地方是DispatchServlet的做事流程图,作为HTTP乞请的中控器,它在SpringMVC中起着分发诉求的功效。上面计算了DispatchServlet设计的风流倜傥部分风味总计。

四、哀告流程

图片 1

 

通过对SpringMVC运行进程的深刻钻研,期待精晓Java
Web容器运营进程;明白SpringMVC运转进度;精通Spr…

容器运维时施行的依次

web.xml中定义的大部东西是随着容器的开发银行而进行的,比方servlet,filter,listener,contextParam,具体的实行种种为
contextParam->listener->filter->servlet

极力推荐的spring源码解读!!!

通过对SpringMVC运行进程的递进商讨,期待精晓Java
Web容器运维进度;领会SpringMVC运转进程;驾驭SpringMVC的配备文件如何布置,为何要如此安插;明白SpringMVC是怎么样工作的;精通Spring源码的宏图和增长阅读源码的技艺。

目录
1.Web容器初阶化进程
2.SpringMVC中web.xml配置
3.认识ServletContextListener
4.认识ContextLoaderListener
5.DispatcherServlet初始化(HttpServletBean • FrameworkServlet •
DispatcherServlet
6.ContextLoaderListener与DispatcherServlet关系
7.DispatcherServlet的设计
8.DispatcherServlet办事规律

生龙活虎、Web容器开始化进程

图片 2

上海教室展现了web容器起始化的历程,其合英文书档案给出了那样的叙述:
  When a web application is deployed into a container, the following
steps must be performed, in this order, before the web application
begins processing client requests.

Instantiate an instance of each event listener identified by a
<listener> element in the deployment descriptor.

For instantiated listener instances that implement
ServletContextListener, call the contextInitialized() method.

Instantiate an instance of each filter identified by a <filter>
element in the deployment descriptor and call each filter instance’s
init() method.

Instantiate an instance of each servlet identified by a
<servlet> element that includes a <load-on-startup> element
in the order defined by the load-on-startup element values, and call
each servlet instance’s init() method.

二、SpringMVC中web.xml的配置

图片 3

上图是截取的web.xml中的配置,在<listener>标签中定义了spring容器加载器;在<servlet>标签中定义了spring前端调整器。

图片 4

上海教室是源码中接口ServletContextListener的概念,能够观察在其注释中指明:servlet和Filter初步化前和销毁后,都会给落到实处了servletContextListener接口的监听器发出相应的通报。

图片 5

上边是类ContextLoadListener的概念,它完结了地点的servletContextListener。这里运用了代办情势,轻易的代理了ContextLoader类。ContextLoadListener类用来制造Spring
application context,而且将application
context注册到servletContext里面去。

图片 6

重组方面的WEB容器运转的进度,以致接口ServletContextListener和类ContextLoadListener。大家知道:
  在 Servlet
API中有一个ServletContextListener接口,它能够监听ServletContext对象的生命周期,实际上就是监听Web应用的生命周期。当Servlet容器运营或截至Web应用时,会触发ServletContext伊芙nt事件,该事件由ServletContextListener来管理。在ServletContextListener接口中定义了拍卖ServletContext伊芙nt
事件的四个点子contextInitialized()和contextDestroyed()。

  ContextLoaderListener监听器的功力正是运转Web容器时,自动装配ApplicationContext的陈设新闻。因为它实现了ServletContextListener那一个接口,在web.xml配置了那么些监听器,运维容器时,就能够暗中同意试行它完毕的法门。由于在ContextLoaderListener中涉及了ContextLoader那一个类,所以整个加载配置进程由ContextLoader来产生。

图片 7

地方是initWebApplicationContext的进度,方法名称便是其意义。方法中首先创设了WebApplicationContext,配置并且刷新实例化整个SpringApplicationContext中的Bean。由此,如若大家的Bean配置出错的话,在容器运营的时候,会抛卓殊出来的。
  综上,ContextLoaderListener类起着至关心珍视要的法力。它读取web.xml中布局的context-param中的配置文件,提前在web容器开首化前思索职业对应的Application
context;将成立好的Application
context放置于ServletContext中,为springMVC部分的开首化做好计划。

三、DispatchServlet初始化
  在SpringMVC架构中,DispatchServlet负担央求分发,起到调节器的功力。下边详细来讲明表明:

图片 8

DispatchServlet名如其义,它的本色上是三个Servlet。从下边图能够看看,下层的子类不断的对HttpServlet父类进行情势扩大。

图片 9

上海体育场合是抽象类HttpServletBean的达成,大家精晓HttpServlet有两大大旨措施:init()和service()方法。HttpServletBean重写了init()方法,在这里有的,大家得以看出其落到实处思路:公共的一些统一来完成,变化的部分统一来抽象,交给其子类来落实,故用了abstract
class来修饰类名。别的,HttpServletBean提供了一个HttpServlet的抽象完毕,使的Servlet不再关怀init-param部分的赋值,让servlet更关切于本身Bean开端化的完结。

图片 10

图片 11

上海体育地方是FrameworkServlet的合法概念, 它提供了咬合web javabean和spring
application
context的三结合方案。那么它是什么样贯彻的吗?在源码中大家得以看出通过奉行initWebApplicationContext()方法和initFrameworkServlet()方法达成。

图片 12

图片 13

DispatchServlet是HTTP乞请的主旨调解微处理机,它将web央求转载给controller层管理,它提供了飞跃的璀璨和特别管理机制。DispatchServlet转载倡议的中央代码在doService()方法中贯彻,详细代码参照图上。

图片 14

上海教室是DispatchServlet类和ContextLoaderListener类的涉嫌图。首先,用ContextLoaderListener起头化上下文,接着使用DispatchServlet来起头化WebMVC的上下文。

图片 15

上海体育场面是DispatchServlet的干活流程图,作为HTTP央浼的中控器,它在SpringMVC中起着分发央浼的功能。上边总计了DispatchServlet设计的局地本性计算。

图片 16

四、乞求流程

图片 17

监听器ContextLoaderListener源码深入分析

咱俩在写SpringMVC项目时都需求在web.xml配置三个listener,大家就从这些listenser早先,看看里面毕竟产生了怎么样。

<listener>
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>

正如为大家布署的监听器ContextLoaderListener的继续关系图。

ContextLoaderListener世袭关系图

能够见到ContextLoaderListener世袭了ContextLoader并落到实处了ServletContextListener接口。

各样达成ServletContextListener的监听器都一定要兑现如下三个法子(contextInitialized()和contextDestroyed()),效能我们从名字上就能够看出来,分别是容器运转时做一些起初化专门的学业和容器关闭时做一些清理专业。

如下为ContextLoaderListener.java代码。

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
  public void contextInitialized(ServletContextEvent event) {
    //初始化Root WebApplicationContext
        initWebApplicationContext(event.getServletContext());
    }
  public void contextDestroyed(ServletContextEvent event) {
        closeWebApplicationContext(event.getServletContext());
        ContextCleanupListener.cleanupAttributes(event.getServletContext());
    }
}

此地initWebApplicationContext()方法调用的是父类的ContextLoad.initWebApplicationContext()

//ContextLoad.initWebApplicationContext()
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
  ...
  try {
    if (this.context == null) {
      //this.conext即为Root WebApplicationContext
      //如果没有配置WebApplicationContext的实现类,将使用默认的XmlWebApplicationContext实现类创建WebApplicationContext对象
      //传入servletContext目的是为了读取配置文件中的context_class参数
      this.context = createWebApplicationContext(servletContext);
    }
    if (this.context instanceof ConfigurableWebApplicationContext) {
      ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
      if (!cwac.isActive()) {
        if (cwac.getParent() == null) {
          //设置Root WebApplicationContext的parent,作用个人猜想可能是跟分布式应用有关,
          //分布式应用每个分应用都有一个Root WebApplicationContext,现在如果这么多Root WebApplicationContext
          //需要共享数据的话就需要一个共同的parent来保存共享的数据了
          //在单应用中parent为null
          ApplicationContext parent = loadParentContext(servletContext);
          cwac.setParent(parent);
        }
        //将Root WebApplicationContext与ServletContext建立关联,读取applicationContext.xml文件并配置Root WebApplicationContext
        configureAndRefreshWebApplicationContext(cwac, servletContext);
      }
    }
    //ServletContext与Root WebApplicationContext建立关联
    servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
    ...
    return this.context;
  }
}

代码中现身了如下目的WebApplicationContext,ConfigurableWebApplicationContext ,
ApplicationContext甚至 ServletContext。

  1. 先来讲前双方WebApplicationContext,ConfigurableWebApplicationContext之间的关系:

ConfigurableWebApplicationContext增加了WebApplicationContext,它同意通过配置化的措施实例化WebApplicationContext。同期定义了多少个根本的艺术。

  • setServletContext(): 为Spring设置Web应用的上下文,以便双方结合。

  • setConfigLocations(): 设置Spring配置文件地方。

  1. 继之是ServletContext 和 WebApplicationContext之间的关系。

ServletContextAndWebApplicationContext

  1. 终极为了求证上述的Root WebApplicationContext 和 ApplicationContext
    parent的关联,笔者在Spring官英特网找到了如此一张图。

上下文关系

大致表明各种 WebApplicationContext 的效应:

  • WebApplicationContext: 与 dispatchServlet
    直接有关,通过xxx-servlet.xml文件配置,是 dispatchServlet
    的上下文,富含了各个调整器(Controllers),视图剖判器(ViewResolver)以至映射器(HandlerMapping)。

  • Root WebApplicationContext:
    单应用下为一个,遍布式应用会存在三个。通过applicationContext.xml配置。包涵各类事情逻辑以至对数据库实行的操作。

  • parent: 布满式应用中才会有,为三个共享 Root WebApplicationContext
    而生。

至此,大家监听器ContextLoaderListener的做事就做到了,大家总括如下:

  1. 始建Root WebApplicationContext并透过ServletContext完毕安排。
  2. 比如是分布式应用将Root WebApplicationContext与parent建构关联。
  3. 做到ServletContext与Root WebApplicationContext之间的并行关系。

DispatchServlet的起始化

关于 dispatchServlet 的接续关系如图所示:

dispatchServlet世袭关系

能够看见,HttpServletBean 和 FramworkServlet 是
dispatchServlet的父类,而且她们都是 HttpServlet的子类。
要想开始化 DispatchServlet,必须先创设出后生可畏多元父类对象。

在一个servlet能选择需要并爆发响应早前,它要求先成功开端化工作(调用init()方法)。大家在web.xml中只安排了三个servlet(即
dispatchServlet),它随着容器的开行而运维,大家再度重申前边提到过实行种种。
contextParam->listener->filter->servlet

能够见见,servlet在listener之后实施,所以在调用 servlet.init()
方法以前,Root WebApplicationContext已经做到开端化,而 dispatchServlet
起头化的职业正是 实现 WebApplicationContext的开端化。

dispatchServlet 中的init()方法,继承自父类 HttpSrevletBean 中定义的
init()方法。

正如是 HttpSrevletBean 中的 init()方法,整个 DispatchServlet
的伊始化也经过开端。

  1. 继承自HttpServletBean的init()方法

public final void init() throws ServletException {
  ...
  try {
    //读取xxx-servlet.xml
      PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
    //创建BeanWrapper对象
      BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
      ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
      bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
      initBeanWrapper(bw);
    //通过BeanWrapper设置DispatchServlet的属性
      bw.setPropertyValues(pvs, true);
  }

  //使子类各自完成初始化
  initServletBean();
  ...
}

瞩目末了有四个initServletBean()方法,这几个 initServletBean() 方法在
HttpSrevletBean 中单独声多美滋(Dumex卡塔尔(Dumex卡塔 尔(阿拉伯语:قطر‎下,具体的完毕交由子类 FramworkServlet
去得以实现,而作者辈的 DispatchServlet 中的 initServletBean()也等于世袭自
FramworkServlet的 initServletBean()方法。

  1. 继承自FramworkServlet的initServletBean()方法

protected final void initServletBean() throws ServletException {
  ...
      long startTime = System.currentTimeMillis();

      try {
    //初始化webApplicationContext
          this.webApplicationContext = initWebApplicationContext();
          initFrameworkServlet();
      }
      ...
}

持续深远initWebApplicationContext()方法内部

protected WebApplicationContext initWebApplicationContext() {
  //获取Root WebApplicationContext
  WebApplicationContext rootContext =
              WebApplicationContextUtils.getWebApplicationContext(getServletContext());
  //定义WebApplicationContext对象
      WebApplicationContext wac = null;

  //DispatchServlet有个以WebApplicationContext为参数的构造函数,如果使用以WebApplicationContext为参数的构造函数,则执行这段代码。
      if (this.webApplicationContext != null) {
          wac = this.webApplicationContext;
          if (wac instanceof ConfigurableWebApplicationContext) {
              ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
              if (!cwac.isActive()) {
                  if (cwac.getParent() == null) {
                      cwac.setParent(rootContext);
                  }
                  configureAndRefreshWebApplicationContext(cwac);
              }
          }
      }
      if (wac == null) {
    //以contextAttribute属性(FramworkServlet的String类型属性)为Key,从ServletContext中找WebApplicationContext
    //一般不会设置contextAttribute属性,也就是说查找结果一般为null
          wac = findWebApplicationContext();
      }
      if (wac == null) {
          //创建WebApplicationContext
    //后面会深入观察
          wac = createWebApplicationContext(rootContext);
      }

      if (!this.refreshEventReceived) {
          onRefresh(wac);
      }

      if (this.publishContext) {
          // Publish the context as a servlet context attribute.
          String attrName = getServletContextAttributeName();
          getServletContext().setAttribute(attrName, wac);
      }

      return wac;
}

继续浓郁调查createWebApplicationContext(rootContext)

protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
  //找到WebApplicationContext的实现类,默认为XmlWebApplicationContext
  Class<?> contextClass = getContextClass();
      ...

      ConfigurableWebApplicationContext wac =
              (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
  //对wac进行属性设置
      wac.setEnvironment(getEnvironment());
      wac.setParent(parent);
  //getContextConfigLocation()返回"xxx-servlet.xml"
      wac.setConfigLocation(getContextConfigLocation());
  //后面会深入观察
      configureAndRefreshWebApplicationContext(wac);

      return wac;
}

世袭深远侦查configureAndRefreshWebApplicationContext(wac)

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
  ...
  //关联servletContext
      wac.setServletContext(getServletContext());
      wac.setServletConfig(getServletConfig());
      wac.setNamespace(getNamespace());
      wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

      ConfigurableEnvironment env = wac.getEnvironment();
      if (env instanceof ConfigurableWebEnvironment) {
          ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
      }

      postProcessWebApplicationContext(wac);
      applyInitializers(wac);
  //刷新WebApplicationContext
      wac.refresh();
}

总的说来,当refresh()方法实行实现之后,会触发
世袭自FramworkServlet.onApplication伊芙nt() 函数,该函数会实践内部的
onRefresh()方法。该措施交由子类 DispatchServlet 去落实。如下是
DispatchServlet部分代码。

protected void onRefresh(ApplicationContext context) {
      initStrategies(context);
  }
//通过反射机制查找并装配用户自定义的组件,如果找不到则使用默认的组件进行装配
//默认的装配组件在org.springframework.web.servlet.DispatchServlet,properties文件中定义
  protected void initStrategies(ApplicationContext context) {
  //初始化文件上传解析器
      initMultipartResolver(context);
  //初始化本地化解析器
      initLocaleResolver(context);
  //初始化主体解析器
      initThemeResolver(context);
  //初始化映射
      initHandlerMappings(context);
  //初始化映射适配器
      initHandlerAdapters(context);
  //初始化异常处理器
      initHandlerExceptionResolvers(context);
  //初始化视图名称翻译器
      initRequestToViewNameTranslator(context);
  //初始化视图解析器
      initViewResolvers(context);
  //初始化管理FlashMap的接口,FlashMap用于存储一个请求的输出,当进入另一个请求时作为
  //请求的输入,通常用于重定向场景
      initFlashMapManager(context);
  }

迄今停止,servlet全体早先化达成,就等着第四个央求的光顾了,总括为一句话就是:

  • 由此调用init()方法初步化 WebApplicationContext,并通过安顿文件配置
    WebApplicationContext
  • 初阶化各样拆解解析器

相关文章