/** * Name of the class path resource (relative to the ContextLoader class) * that defines ContextLoader's default strategy names. */ private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";
static { // Load default strategy implementations from properties file. // This is currently strictly internal and not meant to be customized // by application developers. try { ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage()); } }
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { // <1> 若已经存在 ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE 对应的 WebApplicationContext 对象,则抛出 IllegalStateException 异常。 // 例如,在 web.xml 中存在多个 ContextLoader 。 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!"); }
// <2> 打印日志 servletContext.log("Initializing Spring root WebApplicationContext"); Log logger = LogFactory.getLog(ContextLoader.class); if (logger.isInfoEnabled()) { logger.info("Root WebApplicationContext: initialization started"); }
// 记录开始时间 long startTime = System.currentTimeMillis();
try { // Store context in local instance variable, to guarantee that // it is available on ServletContext shutdown. if (this.context == null) { // <3> 初始化 context ,即创建 context 对象 this.context = createWebApplicationContext(servletContext); } // <4> 如果是 ConfigurableWebApplicationContext 的子类,如果未刷新,则进行配置和刷新 if (this.context instanceof ConfigurableWebApplicationContext) { ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context; if (!cwac.isActive()) { // <4.1> 未刷新( 激活 ) // 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) { // <4.2> 无父容器,则进行加载和设置。 // The context instance was injected without an explicit parent -> // determine parent for root web application context, if any. ApplicationContext parent = loadParentContext(servletContext); cwac.setParent(parent); } // <4.3> 配置 context 对象,并进行刷新 configureAndRefreshWebApplicationContext(cwac, servletContext); } } // <5> 记录在 servletContext 中 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
/** * Map from (thread context) ClassLoader to corresponding 'current' WebApplicationContext. */ private static final Map<ClassLoader, WebApplicationContext> currentContextPerThread = new ConcurrentHashMap<>(1); /** * The 'current' WebApplicationContext, if the ContextLoader class is * deployed in the web app ClassLoader itself. */ @Nullable private static volatile WebApplicationContext currentContext;
public static final String CONTEXT_ID_PARAM = "contextId";
public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) { // <1> 如果 wac 使用了默认编号,则重新设置 id 属性 if (ObjectUtils.identityToString(wac).equals(wac.getId())) { // The application context id is still set to its original default value // -> assign a more useful id based on available information // 情况一,使用 contextId 属性 String idParam = sc.getInitParameter(CONTEXT_ID_PARAM); if (idParam != null) { wac.setId(idParam); // 情况二,自动生成 } else { // Generate default id... wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(sc.getContextPath())); } }
// The wac environment's #initPropertySources will be called in any case when the context // is refreshed; do it eagerly here to ensure servlet property sources are in place for // use in any post-processing or initialization that occurs below prior to #refresh // <4> TODO 芋艿,暂时忽略 ConfigurableEnvironment env = wac.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env).initPropertySources(sc, null); }
// <5> 执行自定义初始化 context TODO 芋艿,暂时忽略 customizeContext(sc, wac);