• Spring的启动过程


    spring中DispatcherServlet、WebApplicationContext、ServletContext之间的关系

    1. 首先,对于一个web应用,其部署在web容器中,web容器提供其一个全局的上下文环境,这个上下文就是ServletContext,其为后面的spring IoC容器提供宿主环境;
    2. 其次,在web.xml中会提供有contextLoaderListener。在web容器启动时,会触发容器初始化事件,此时contextLoaderListener会监听到这个事件,其contextInitialized方法会被调用,在这个方法中,spring会初始化一个启动上下文,这个上下文被称为根上下文,即WebApplicationContext,这是一个接口类,确切的说,其实际的实现类是XmlWebApplicationContext。这个就是spring的IoC容器,其对应的Bean定义的配置由web.xml中的context-param标签指定。在这个IoC容器初始化完毕后,spring以WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE为属性Key,将其存储到ServletContext中,便于获取;

    3. 再次,contextLoaderListener监听器初始化完毕后,开始初始化web.xml中配置的Servlet,这个servlet可以配置多个,以最常见的DispatcherServlet为例,这个servlet实际上是一个标准的前端控制器,用以转发、匹配、处理每个servlet请求。DispatcherServlet上下文在初始化的时候会建立自己的IoC上下文,用以持有spring mvc相关的bean。在建立DispatcherServlet自己的IoC上下文时,会利用WebApplicationContext.ROOTWEBAPPLICATIONCONTEXTATTRIBUTE先从ServletContext中获取之前的根上下文(即WebApplicationContext)作为自己上下文的parent上下文。有了这个parent上下文之后,再初始化自己持有的上下文。这个DispatcherServlet初始化自己上下文的工作在其initStrategies方法中可以看到,大概的工作就是初始化处理器映射、视图解析等。这个servlet自己持有的上下文默认实现类也是mlWebApplicationContext。初始化完毕后,spring以与servlet的名字相关(此处不是简单的以servlet名为Key,而是通过一些转换,具体可自行查看源码)的属性为属性Key,也将其存到ServletContext中,以便后续使用。这样每个servlet就持有自己的上下文,即拥有自己独立的bean空间,同时各个servlet共享相同的bean,即根上下文(第2步中初始化的上下文)定义的那些bean。

    ContextLoaderListener初始化的上下文和DispatcherServlet初始化的上下文关系,如图3-1


    图3-1

    从图中可以看出:

    ContextLoaderListener初始化的上下文加载的Bean是对于整个应用程序共享的,不管是使用什么表现层技术,一般如DAO层、Service层Bean;

    DispatcherServlet初始化的上下文加载的Bean是只对Spring Web MVC有效的Bean,如Controller、HandlerMapping、HandlerAdapter等等,该初始化上下文应该只加载Web相关组件。

    3.4、DispatcherServlet初始化顺序

    继承体系结构如下所示:




    1、HttpServletBean继承HttpServlet,因此在Web容器启动时将调用它的init方法,该初始化方法的主要作用

    :::将Servlet初始化参数(init-param)设置到该组件上(如contextAttribute、contextClass、namespace、contextConfigLocation),通过BeanWrapper简化设值过程,方便后续使用;

    :::提供给子类初始化扩展点,initServletBean(),该方法由FrameworkServlet覆盖。

    Java代码  收藏代码
    1. public abstract class HttpServletBean extends HttpServlet implements EnvironmentAware{  
    2. @Override  
    3.     public final void init() throws ServletException {  
    4.        //省略部分代码  
    5.        //1、如下代码的作用是将Servlet初始化参数设置到该组件上  
    6. //如contextAttribute、contextClass、namespace、contextConfigLocation;  
    7.        try {  
    8.            PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);  
    9.            BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);  
    10.            ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());  
    11.            bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, this.environment));  
    12.            initBeanWrapper(bw);  
    13.            bw.setPropertyValues(pvs, true);  
    14.        }  
    15.        catch (BeansException ex) {  
    16.            //…………省略其他代码  
    17.        }  
    18.        //2、提供给子类初始化的扩展点,该方法由FrameworkServlet覆盖  
    19.        initServletBean();  
    20.        if (logger.isDebugEnabled()) {  
    21.            logger.debug("Servlet '" + getServletName() + "' configured successfully");  
    22.        }  
    23.     }  
    24.     //…………省略其他代码  
    25. }  

    2、FrameworkServlet继承HttpServletBean,通过initServletBean()进行Web上下文初始化,该方法主要覆盖一下两件事情:

        初始化web上下文;

        提供给子类初始化扩展点;

    Java代码  收藏代码
    1. public abstract class FrameworkServlet extends HttpServletBean {  
    2. @Override  
    3.     protected final void initServletBean() throws ServletException {  
    4.         //省略部分代码  
    5.        try {  
    6.              //1、初始化Web上下文  
    7.            this.webApplicationContext = initWebApplicationContext();  
    8.              //2、提供给子类初始化的扩展点  
    9.            initFrameworkServlet();  
    10.        }  
    11.         //省略部分代码  
    12.     }  
    13. }  
    Java代码  收藏代码
    1. protected WebApplicationContext initWebApplicationContext() {  
    2.         //ROOT上下文(ContextLoaderListener加载的)  
    3.        WebApplicationContext rootContext =  
    4.               WebApplicationContextUtils.getWebApplicationContext(getServletContext());  
    5.        WebApplicationContext wac = null;  
    6.        if (this.webApplicationContext != null) {  
    7.            // 1、在创建该Servlet注入的上下文  
    8.            wac = this.webApplicationContext;  
    9.            if (wac instanceof ConfigurableWebApplicationContext) {  
    10.               ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;  
    11.               if (!cwac.isActive()) {  
    12.                   if (cwac.getParent() == null) {  
    13.                       cwac.setParent(rootContext);  
    14.                   }  
    15.                   configureAndRefreshWebApplicationContext(cwac);  
    16.               }  
    17.            }  
    18.        }  
    19.        if (wac == null) {  
    20.              //2、查找已经绑定的上下文  
    21.            wac = findWebApplicationContext();  
    22.        }  
    23.        if (wac == null) {  
    24.             //3、如果没有找到相应的上下文,并指定父亲为ContextLoaderListener  
    25.            wac = createWebApplicationContext(rootContext);  
    26.        }  
    27.        if (!this.refreshEventReceived) {  
    28.              //4、刷新上下文(执行一些初始化)  
    29.            onRefresh(wac);  
    30.        }  
    31.        if (this.publishContext) {  
    32.            // Publish the context as a servlet context attribute.  
    33.            String attrName = getServletContextAttributeName();  
    34.            getServletContext().setAttribute(attrName, wac);  
    35.            //省略部分代码  
    36.        }  
    37.        return wac;  
    38.     }  

    从initWebApplicationContext()方法可以看出,基本上如果ContextLoaderListener加载了上下文将作为根上下文(DispatcherServlet的父容器)。

    最后调用了onRefresh()方法执行容器的一些初始化,这个方法由子类实现,来进行扩展。

    3、DispatcherServlet继承FrameworkServlet,并实现了onRefresh()方法提供一些前端控制器相关的配置:

    Java代码  收藏代码
    1. public class DispatcherServlet extends FrameworkServlet {  
    2.      //实现子类的onRefresh()方法,该方法委托为initStrategies()方法。  
    3.     @Override  
    4.     protected void onRefresh(ApplicationContext context) {  
    5.        initStrategies(context);  
    6.     }  
    7.     //初始化默认的Spring Web MVC框架使用的策略(如HandlerMapping)  
    8.     protected void initStrategies(ApplicationContext context) {  
    9.        initMultipartResolver(context);  
    10.        initLocaleResolver(context);  
    11.        initThemeResolver(context);  
    12.        initHandlerMappings(context);  
    13.        initHandlerAdapters(context);  
    14.        initHandlerExceptionResolvers(context);  
    15.        initRequestToViewNameTranslator(context);  
    16.        initViewResolvers(context);  
    17.        initFlashMapManager(context);  
    18.     }  
    19. }  

    从如上代码可以看出,DispatcherServlet启动时会进行我们需要的Web层Bean的配置,如HandlerMapping、HandlerAdapter等,而且如果我们没有配置,还会给我们提供默认的配置。

    从如上代码我们可以看出,整个DispatcherServlet初始化的过程和做了些什么事情,具体主要做了如下两件事情:

    1、初始化Spring Web MVC使用的Web上下文,并且可能指定父容器为(ContextLoaderListener加载了根上下文);

    2、初始化DispatcherServlet使用的策略,如HandlerMapping、HandlerAdapter等。

  • 相关阅读:
    【python cookbook】替换字符串中的子串(使用Template)
    python 学习sys
    【python cookbook】 替换字符串中的子串
    Python文件读写
    【python cookbook】python过滤字符串中不属于指定集合的字符
    【python cookbook】改变多行文本字符串的缩进
    python字符编码
    【python cookbook】python访问子字符串
    【python cookbook】python 控制大小写
    过关了
  • 原文地址:https://www.cnblogs.com/gujiande/p/6564317.html
Copyright © 2020-2023  润新知