美文网首页
spring-webmvc应用中有几个ApplicationCo

spring-webmvc应用中有几个ApplicationCo

作者: dracula337435 | 来源:发表于2019-04-04 18:35 被阅读0次

    1. 先给结论,一父多子

    一个web.xml会对应1个,其中每一个DispatcherServlet会对应一个,且后者对应ApplicationContextparent均为前者

    org.springframework.web.servlet.DispatcherServletjavadoc

    A web application can define any number of DispatcherServlets. Each servlet will operate in its own namespace, loading its own application context with mappings, handlers, etc. Only the root application context as loaded by ContextLoaderListener, if any, will be shared.

    2.一父的初始化

    ContextLoaderListener的类图

    ContextLoaderListener中回调,在void contextInitialized(ServletContextEvent event)函数中,转交给父类ContextLoaderWebApplicationContext initWebApplicationContext(ServletContext servletContext)函数,如下:

    @Override
    public void contextInitialized(ServletContextEvent event) {
        initWebApplicationContext(event.getServletContext());
    }
    

    ContextLoaderinitWebApplicationContext方法的时序图为

    ContextLoader#initWebApplicationContext的时序图

    此方法中可见

    // 略
    this.context = createWebApplicationContext(servletContext);
    // 略
    servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
    

    可见这里初始了一个root,放入ServletContext中,后文中还要取出

    3.多子的初始化

    DispatcherServlet的类图

    Servlet接口的public void init(ServletConfig config) throws ServletException方法在web应用启动时被回调,方法实现所在类为GenericServlet,代码如下:

    @Override
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }
    

    其中public void init() throws ServletException专用于被覆盖,方法实现所在类为HttpServletBean,代码如下:

    @Override
    public final void init() throws ServletException {
        //略
        // Let subclasses do whatever initialization they like.
        initServletBean();
    }
    

    其中protected void initServletBean() throws ServletException方法实现所在类为FrameworkServlet,代码片段如下:

    @Override
    protected final void initServletBean() throws ServletException {
        getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
        if (logger.isInfoEnabled()) {
            logger.info("Initializing Servlet '" + getServletName() + "'");
        }
        long startTime = System.currentTimeMillis();
    
        try {
            this.webApplicationContext = initWebApplicationContext();
            initFrameworkServlet();
        }
        catch (ServletException | RuntimeException ex) {
            logger.error("Context initialization failed", ex);
            throw ex;
        }
    
        // 略一段日志
    
        if (logger.isInfoEnabled()) {
            logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
        }
    }
    

    题外话,这里有spring-mvc打出的标志性日志:

    INFO 15873 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
    INFO 15873 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
    INFO 15873 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 7 ms
    

    继续探究初始化,本类中protected WebApplicationContext initWebApplicationContext()为关键类,代码片段如下:

    protected WebApplicationContext initWebApplicationContext() {
        WebApplicationContext rootContext =
                WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        WebApplicationContext wac = null;
    
        if (this.webApplicationContext != null) {
            // A context instance was injected at construction time -> use it
            wac = this.webApplicationContext;
            if (wac instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
                if (!cwac.isActive()) {
                    // The context has not yet been refreshed -> provide services such as
                    // setting the parent context, setting the application context id, etc
                    if (cwac.getParent() == null) {
                        // The context instance was injected without an explicit parent -> set
                        // the root application context (if any; may be null) as the parent
                        cwac.setParent(rootContext);
                    }
                    configureAndRefreshWebApplicationContext(cwac);
                }
            }
        }
        if (wac == null) {
            // No context instance was injected at construction time -> see if one
            // has been registered in the servlet context. If one exists, it is assumed
            // that the parent context (if any) has already been set and that the
            // user has performed any initialization such as setting the context id
            wac = findWebApplicationContext();
        }
        if (wac == null) {
            // No context instance is defined for this servlet -> create a local one
            wac = createWebApplicationContext(rootContext);
        }
    
        //略
    }
    

    可见,这段代码做的主要是

    1. 得到WebApplicationContext类型的rootContext变量,得到的方式与章节2结尾处放入的方式相对应,从同样位置(ServletContext)用同样名字(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE)取
    2. 尝试多种方法初始化DispatcherServlet对应的WebApplicationContext,并将其parent设置为rootContext

    相关文章

      网友评论

          本文标题:spring-webmvc应用中有几个ApplicationCo

          本文链接:https://www.haomeiwen.com/subject/aobfiqtx.html