javaweb应用初始化spring applicationContext过程

通过ContextLoaderListener初始化applicationContext

javaweb引用启动时会加载web.xml,并且会执行配置的listener,在这里注册一个监听器,在内部初始化applicationContext就可以了。这里监听的类是org.springframework.web.context.ContextLoaderListener
该类继承了ServletContextListener接口,web应用启动时会执行contextInitialized方法。

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

可以看到,该方法就是用来初始化applicationContext的。

    public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
        if(servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
            throw new IllegalStateException("Cannot initialize context because there is already a root application context present - check whether you have multiple ContextLoader* definitions in your web.xml!");
        } else {
            Log logger = LogFactory.getLog(ContextLoader.class);
            servletContext.log("Initializing Spring root WebApplicationContext");
            if(logger.isInfoEnabled()) {
                logger.info("Root WebApplicationContext: initialization started");
            }

            long startTime = System.currentTimeMillis();

            try {
                if(this.context == null) {
                    this.context = this.createWebApplicationContext(servletContext);
                }

                if(this.context instanceof ConfigurableWebApplicationContext) {
                    ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext)this.context;
                    if(!cwac.isActive()) {
                        if(cwac.getParent() == null) {
                            ApplicationContext parent = this.loadParentContext(servletContext);
                            cwac.setParent(parent);
                        }

                        this.configureAndRefreshWebApplicationContext(cwac, servletContext);
                    }
                }

                servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
                ClassLoader ccl = Thread.currentThread().getContextClassLoader();
                if(ccl == ContextLoader.class.getClassLoader()) {
                    currentContext = this.context;
                } else if(ccl != null) {
                    currentContextPerThread.put(ccl, this.context);
                }

                if(logger.isDebugEnabled()) {
                    logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" + WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
                }

                if(logger.isInfoEnabled()) {
                    long elapsedTime = System.currentTimeMillis() - startTime;
                    logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
                }

                return this.context;
            } catch (RuntimeException var8) {
                logger.error("Context initialization failed", var8);
                servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var8);
                throw var8;
            } catch (Error var9) {
                logger.error("Context initialization failed", var9);
                servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, var9);
                throw var9;
            }
        }
    }

继续打开往下看,applicationContext是存在servletContext中的,key值为ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值,可以看到是通过调用
createWebApplicationContext初始化的,内部调用determineContextClass获取具体的class,如果配置了contextClass变量,则使用该变量获取class,否则使用默认的初始化,这样applicationContext对象就创建完成了。
然后需要获取配置文件初始化bean。
具体是调用了configureAndRefreshWebApplicationContext方法,打开该方法可以看到:

    protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
        String configLocationParam;
        if(ObjectUtils.identityToString(wac).equals(wac.getId())) {
            configLocationParam = sc.getInitParameter("contextId");
            if(configLocationParam != null) {
                wac.setId(configLocationParam);
            } else {
                wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath()));
            }
        }

        wac.setServletContext(sc);
        configLocationParam = sc.getInitParameter("contextConfigLocation");
        if(configLocationParam != null) {
            wac.setConfigLocation(configLocationParam);
        }

        ConfigurableEnvironment env = wac.getEnvironment();
        if(env instanceof ConfigurableWebEnvironment) {
            ((ConfigurableWebEnvironment)env).initPropertySources(sc, (ServletConfig)null);
        }

        this.customizeContext(sc, wac);
        wac.refresh();
    }

可以看到,如果设置了contextConfigLocation初始化参数,则用该参数,否则使用默认参数,这样,application创建bean就齐全了。创建完成后设置进ServletContext中,后续使用只要从里面取出就可以了,key 为ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE。

你可能感兴趣的:(个人理解)