spring mvc 源码研究简单笔记–web容器启动加载WebApplicationContext和初始化DispatcherServlet

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】

ContextLoaderListener监听器,加载ROOT WebApplicationContext

1.在web.xml配置监听器

org.springframework.web.context.ContextLoaderListener

ContextLoaderListener监听器继承了ServletContextListener接口,ServletContextListener监听器提供了

web容器启动时,初始化ServletContext后的事件监听,和销毁ServletContext前的事件监听。

ContextLoaderListener在初始化ServletContext后进行了WebApplicationContext的初始化,在销毁ServletContext前进行了WebApplicationContext的销毁。

ContextLoaderListener初始化WebApplicationContext都做了什么工作?

1.WebApplicationContext实现类的查找

spring允许你配置WebApplicationContext实现类.

1)如果在web.xml中配置了ServletContext的初始化参数,其中名字为contextClass,则代表你配置了相应的WebApplicationContext容器实现类,例如:

contextClass org.springframework.web.context.support.XmlWebApplicationContext

2)如果没有在web.xml中配置WebApplicationContext实现类,则查找classPath下存在的默认配置文件ContextLoader.properties属性文件,这个文件在static

静态域中初始化,具体配置如下:

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

得到实现类的类名,并使用反射得到该类型,并实例化该对象,这样就得到WebApplicationContext实例。

这里默认使用XmlWebApplicationContext作为WebApplicationContext实例。

2.配置XmlWebApplicationContext

1.设置ServletContext

2.设置spring配置文件资源路径,在web.xml配置了,容器在刷新时会使用这些配置来加载bean及设置

contextConfigLocation /WEB-INF/applicationContext.xml,/WEB-INF/springmvc.xml;/WEB-INF/spring/\*

如果没有配置则使用/WEB-INF/applicationContext.xml

3.配置环境变量,除了标准的运行环境参数System.getEnv()和System.getProperties(),spring还设置了一个环境变量,

servletContextInitParams 值为当前的ServletContext

4.支持配置XmlWebApplicationContext在刷新前,实现接口ApplicationContextInitializer

实现initialize(XmlWebApplicationContext applicationContext)方法

需要在web.xml中配置

globalInitializerClasses com.zghw.springmvc.demo.MyApplicationContextInitializer contextInitializerClasses com.zghw.springmvc.demo.MyApplicationContextInitializer1

globalInitializerClasses代表所有的web application都会应用

contextInitializerClasses代表只有当前的web application会使用

如果存在把这些实现类作为一个集合,转化为class类型,并实例化对象,排序调用initialize方法。

5.刷新容器,wac.refresh();

主要的一步:把容器加入到ServletContext ,让容器依附于Web容器。放入容器的名称为org.springframework.web.context.WebApplicationContext.ROOT

然后把当前线程类加载器和WebApplicationContext绑定在一个map中,以便以后取用。

总结:

Web容器启动时,ContextLoaderListener实现了ServletContextListener接口,即在Servlet初始化阶段,会通知ContextLoaderListener监听器,初始化

Context容器,这里使用到了ServletContext的初始化参数。即在web.xml配置的context-param

1.首先查找配置的WebApplicationContext实例,通过默认配置或用户在web.xml配置的contextClass实现类,并实例化对象这里使用的是XmlWebApplicationContext。

2.获取容器加载的配置文件,contextConfigLocation

3.设置web的环境参数servletContextInitParams 值为当前的ServletContext

4.实现了ApplicationContextInitializer接口用来初始化容器设置,并配置在了globalInitializerClasses或contextInitializerClasses,转化为class类型,并实例化对象,排序调用initialize方法。

5.刷新容器,wac.refresh();IOC容器加载配置,解析BeanDefintion,初始化配置,运行部分处理器等等一系列工作。

6.让IOC容器放入ServletContext中,作为Root容器名称为:org.springframework.web.context.WebApplicationContext.ROOT

7.把当前线程的类加载和当前IOC容器WebApplicationContext绑定在一个map中,以便以后取用。

DispatcherServlet Web容器启动初始化

HttpServletBean抽象类继承HttpServlet,实现了EnvironmentCapable, EnvironmentAware
1.初始化方法
1.ServletConfig:把ServletCofig中的参数放入到PropertyValues这个属性管理对象中进行管理,并验证使用此Servlet必须要的参数。ServletCofig中如果没有必要的参数则抛出异常。这些必要的参数通过钩子方法让子类加入属性参数。
2.包装当前的Servlet实现类(DispatcherServlet)作为一个BeanWrapper.并赋予ResourceEditor编辑器,用来处理Servlet中的字符串属性转换为Resource对象,这个Resource
实现类是ServletContextResource它使用ServletContext来解析路径,使用了ServletContextResourceLoader资源加载器来加载。
3.设置钩子方法initBeanWrapper让子类为这个Servlet实例BeanWrapper设置配置,比如设置属性编辑器,类型转换器等。
4.设置Servlet实例BeanWrapper的属性即包含了ServletConfig参数和设置的一些属性值的PropertyValues。
5.设置钩子方法initServletBean让子类为这个Servlet设置需要的。
2.销毁方法
空实现,让子类实现
3.环境
实现EnvironmentAware接口代表IOC容器自动注入环境:void setEnvironment(Environment environment);注入ConfigurableEnvironment
实现EnvironmentCapable接口代表了可以得到容器环境,如果容器没有设置环境environment 则设置为StandardServletEnvironment

HttpServletBean主要是设置ServletConfig转化为PropertyValues中,并初始化当前Servlet为BeanWrapper对象。还设置了环境变量。

FrameworkServlet抽象类继承HttpServletBean ,实现了ApplicationContextAware

实现ApplicationContextAware接口代表了容器自动注入IOC容器ApplicationContext,但这里处理仅仅是ApplicationContext是WebApplicationContext实例,并且WebApplicationContext空时才用。

FrameworkServlet主要为了初始化一个新的WebApplicationContext,它使用了ROOT下的WebApplicationContext作为初始,这个可以从ServletContext中取得,
因为在ServletContext监听器初始化阶段已经把ROOTWebApplicationContext加入到ServletContext属性中。
拿到ROOT WebApplicationContext作为一个新的Servlet WebApplicationContext并设置ROOT为父容器,达到了双亲委派模式,
并追加了一些servletConfig 命名空间等参数配置。
配置的DispathcerServlet可以有多个,则代表会有不同的命名空间,格式为在web.xml中配置的servlet的名字追加-servlet
比如springmvc则命名空间为springmvc-servlet

IOC容器已经初始化完成可以使用了。
然后调用DispatcherServlet的方法onRefresh(ApplicationContext context)
进行MVC的配置bean初始化,以便使用。

把下列接口实现类的实例作为属性加入到DispatcherServlet中,或者从配置中加载的或使用默认的配置的。
MultipartResolver
LocaleResolver
ThemeResolver
HandlerMapping
HandlerAdapter
HandlerExceptionResolver
RequestToViewNameTranslator
ViewResolver
FlashMapManager

上传文件解析器
MultipartResolver 默认是没有配置的
直接通过IOC容器ApplicationContext来查找是否存在配置的MultipartResolver.class类型的bean。
如果存在bean作为属性设置到DispatcherServlet中,没有就不用

国际化解析器
LocaleResolver 默认是AcceptHeaderLocaleResolver
直接通过IOC容器ApplicationContext来查找是否存在配置的LocaleResolver.class类型的bean。
如果存在bean作为属性设置到DispatcherServlet中,没有bean,就查询DispatcherServlet.properties中配置的
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
同样会把该AcceptHeaderLocaleResolver作为bean放入到IOC容器中。

主题解析器
ThemeResolver 默认为FixedThemeResolver
和上面LocaleResolver处理一样org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

映射处理类
HandlerMapping 默认:BeanNameUrlHandlerMapping和DefaultAnnotationHandlerMapping

1.从ApplicationContext IOC容器中,查询单例HandlerMapping.class类型的bean,包含从父工厂查找。
查找的所有HandlerMapping放入到Map对象中。
2.把包含HandlerMapping的Map转化成集合,然后对HandlerMapping集合排序,并把此集合作为属性保存在servlet中。

  1. 如果说bean工厂中未配置HandlerMapping,则使用默认策略,从DispatcherServlet.properties文件中,
    取出org.springframework.web.servlet.HandlerMapping配置的默认HandlerMapping类名
    org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
    通过配置的类名,查询对应的Class类型,并通过IOC创建一个实例对象,比如BeanNameUrlHandlerMapping,
    上面配置了两个HandlerMapping实现类名,则ApplicationContext有两个HandlerMapping实例。

处理器适配器接口
HandlerAdapter 默认HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter和AnnotationMethodHandlerAdapter
和HandlerMapping查找同样的逻辑步骤
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

处理异常解析器
HandlerExceptionResolver 默认AnnotationMethodHandlerExceptionResolver、ResponseStatusExceptionResolver和DefaultHandlerExceptionResolver
和HandlerMapping查找同样的逻辑步骤
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

请求到视图翻译解析器
RequestToViewNameTranslator 默认的是DefaultRequestToViewNameTranslator
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

视图解析器

ViewResolver 默认 InternalResourceViewResolver
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

FlashMap管理器
FlashMapManager 默认是 SessionFlashMapManager
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

总结:
从IOC容器中查找相应的配置,如果查找不到,就使用DispatcherServlet.properties默认配置并把配置的类型加入到IOC中作为Bean。

    1.添加依赖包
    spring-core         核心包,底层的工具包
    spring-beans        基础bean工厂生产bean
    spring-context      高级的bean工厂生产bean ApplicationContext
    commons-logging     spring记录日志需要的包
    spring-expression   spring EL表达式包,主要用于bean属性的处理
    spring-aop          spring AOP核心包
    spring-aspects      spring AOP使用AspectJ注解包
    spring-web          支持spring web的包
    spring-webmvc       springMVC核心包
    2.在maven中添加依赖包

      <properties>
      <spring.version>4.1.9.RELEASE</spring.version>
      </properties>

      <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>${spring.version}</version>
      </dependency>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>${spring.version}</version>
      </dependency>
      <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>${spring.version}</version>
      </dependency>
      </dependencies>
    <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        version="3.0">
        <context-param>
            <!-- 可配置的webFactory容器 -->
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.XmlWebApplicationContext</param-value>
        </context-param>
        <!-- 配置容器加载的spring文件可以使用, ; 使用目标下的所有文件则用/* -->
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/applicationContext.xml,/WEB-INF/springmvc.xml;/WEB-INF/spring/*</param-value>
        </context-param>
        <!--  所有的web application初始化刷新前,调用实现类的初始化容器功能  -->
        <context-param>
            <param-name>globalInitializerClasses</param-name>
            <param-value>com.zghw.springmvc.demo.MyApplicationContextInitializer</param-value>
        </context-param>
        <!-- 在当前web application初始化刷新前,调用实现类的初始化容器功能  -->
        <context-param>
            <param-name>contextInitializerClasses</param-name>
            <param-value>com.zghw.springmvc.demo.MyApplicationContextInitializer1</param-value>
        </context-param>

        <!-- 配置一个监听器 -->
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <!-- 配置一个DispatcherServlet分发器 servlet-name 参数springmvc 对应的命名空间是springmvc-servlet 
        如果init-param没有设置contextConfigLocation 则默认加载/WEB-INF/springmvc-servlet.xml文件-->
        <servlet>
            <servlet-name>springmvc</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>/WEB-INF/spring/servlet-context.xml</param-value>
            </init-param>
            <!-- 配置了随web容器一起启动初始化 -->
            <load-on-startup>1</load-on-startup>
          </servlet>
          <servlet-mapping>
            <servlet-name>springmvc</servlet-name>
            <url-pattern>/</url-pattern>
          </servlet-mapping>
    </web-app>
    package com.zghw.springmvc.demo;

    import org.springframework.context.ApplicationContextInitializer;
    import org.springframework.web.context.support.XmlWebApplicationContext;
    public class MyApplicationContextInitializer implements
            ApplicationContextInitializer<XmlWebApplicationContext> {

        public void initialize(XmlWebApplicationContext applicationContext) {
            System.out.println("在刷新容器前可以配置容器 全局");
        }

    }
    package com.zghw.springmvc.demo;

    import org.springframework.context.ApplicationContextInitializer;
    import org.springframework.web.context.support.XmlWebApplicationContext;

    public class MyApplicationContextInitializer1 implements
            ApplicationContextInitializer<XmlWebApplicationContext> {

        public void initialize(XmlWebApplicationContext applicationContext) {
            System.out.println("在刷新容器前可以配置容器 局部");
        }

    }

来源:[]()

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring mvc 源码研究简单笔记–web容器启动加载WebApplicationContext和初始化DispatcherServlet

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏