Spring 源码解析(二)加载配置文件2
接上一章,我们来具体分析下configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc)方法
//org.springframework.web.context.ContextLoader.class
1 protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) { 2 if (ObjectUtils.identityToString(wac).equals(wac.getId())) { 3 // The application context id is still set to its original default value 4 // -> assign a more useful id based on available information 5 String idParam = sc.getInitParameter(CONTEXT_ID_PARAM); 6 if (idParam != null) { 7 wac.setId(idParam); 8 } 9 else { 10 // Generate default id... 11 wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + 12 ObjectUtils.getDisplayString(sc.getContextPath())); 13 } 14 } 15 16 wac.setServletContext(sc); 17 String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM); 18 if (configLocationParam != null) { 19 wac.setConfigLocation(configLocationParam); 20 } 21 22 // The wac environment's #initPropertySources will be called in any case when the context 23 // is refreshed; do it eagerly here to ensure servlet property sources are in place for 24 // use in any post-processing or initialization that occurs below prior to #refresh 25 ConfigurableEnvironment env = wac.getEnvironment(); 26 if (env instanceof ConfigurableWebEnvironment) { 27 ((ConfigurableWebEnvironment) env).initPropertySources(sc, null); 28 } 29 30 customizeContext(sc, wac); 31 wac.refresh(); //刷新容器32 }
第16行,将servletContext设置到WebApplicationContext中,结合前面的分析,通过这里的设置servletContext和WebApplicationContext就可以互相方法了。
第17行,获取配置文件路径,如果在web.xml配置了contextConfigLocation参数,通过19行设置到WebApplicationContext。
第25-28行,创建环境对象。
第31行,刷新容器,spring初始化主要集中在这个方法,进入方法(org.springframework.context.support.AbstractApplicationContext)
//org.springframework.context.support.AbstractApplicationContext
1 @Override 2 public void refresh() throws BeansException, IllegalStateException { 3 synchronized (this.startupShutdownMonitor) { 4 // Prepare this context for refreshing. 5 prepareRefresh(); 6 7 // Tell the subclass to refresh the internal bean factory. 8 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 9 10 // Prepare the bean factory for use in this context. 11 prepareBeanFactory(beanFactory); 12 13 try { 14 // Allows post-processing of the bean factory in context subclasses. 15 postProcessBeanFactory(beanFactory); 16 17 // Invoke factory processors registered as beans in the context. 18 invokeBeanFactoryPostProcessors(beanFactory); 19 20 // Register bean processors that intercept bean creation. 21 registerBeanPostProcessors(beanFactory); 22 23 // Initialize message source for this context. 24 initMessageSource(); 25 26 // Initialize event multicaster for this context. 27 initApplicationEventMulticaster(); 28 29 // Initialize other special beans in specific context subclasses. 30 onRefresh(); 31 32 // Check for listener beans and register them. 33 registerListeners(); 34 35 // Instantiate all remaining (non-lazy-init) singletons. 36 finishBeanFactoryInitialization(beanFactory); 37 38 // Last step: publish corresponding event. 39 finishRefresh(); 40 } 41 42 catch (BeansException ex) { 43 // Destroy already created singletons to avoid dangling resources. 44 destroyBeans(); 45 46 // Reset 'active' flag. 47 cancelRefresh(ex); 48 49 // Propagate exception to caller. 50 throw ex; 51 } 52 } 53 }
第8行,创建beanFactory,根据spring配置文件初始化得到BeanDefinitions,进入方法(org.springframework.context.support.AbstractApplicationContext类中的方法)
//org.springframework.context.support.AbstractApplicationContext
1 /** 2 * Tell the subclass to refresh the internal bean factory. 3 * @return the fresh BeanFactory instance 4 * @see #refreshBeanFactory() 5 * @see #getBeanFactory() 6 */ 7 protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { 8 refreshBeanFactory(); 9 ConfigurableListableBeanFactory beanFactory = getBeanFactory(); 10 if (logger.isDebugEnabled()) { 11 logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); 12 } 13 return beanFactory; 14 }
进入refreshBeanFactory()方法(org.springframework.context.support.AbstractRefreshableApplicationContext类中的方法)
//org.springframework.context.support.AbstractRefreshableApplicationContext.class
1 /** 2 * This implementation performs an actual refresh of this context's underlying 3 * bean factory, shutting down the previous bean factory (if any) and 4 * initializing a fresh bean factory for the next phase of the context's lifecycle. 5 */ 6 @Override 7 protected final void refreshBeanFactory() throws BeansException { 8 if (hasBeanFactory()) { 9 destroyBeans(); 10 closeBeanFactory(); 11 } 12 try { 13 DefaultListableBeanFactory beanFactory = createBeanFactory(); 14 beanFactory.setSerializationId(getId()); 15 customizeBeanFactory(beanFactory); 16 loadBeanDefinitions(beanFactory); 17 synchronized (this.beanFactoryMonitor) { 18 this.beanFactory = beanFactory; 19 } 20 } 21 catch (IOException ex) { 22 throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); 23 } 24 }
第13行,创建了DefaultListableBeanFactory,Spring的核心
第16行,加载配置文件,初始化DefaultListableBeanFactory
第18行,将DefaultListableBeanFactory设置到this.beanFactory(在AbstractRefreshableApplicationContext中定义的)
进入loadBeanDefinitions(beanFatory)方法(org.springframework.web.context.support.XmlWebApplicationContext类中的方法)
//org.springframework.web.context.support.XmlWebApplicationContext
1 /** 2 * Loads the bean definitions via an XmlBeanDefinitionReader. 3 * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader 4 * @see #initBeanDefinitionReader 5 * @see #loadBeanDefinitions 6 */ 7 @Override 8 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { 9 // Create a new XmlBeanDefinitionReader for the given BeanFactory. 10 XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); 11 12 // Configure the bean definition reader with this context's 13 // resource loading environment. 14 beanDefinitionReader.setEnvironment(getEnvironment()); 15 beanDefinitionReader.setResourceLoader(this); 16 beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); 17 18 // Allow a subclass to provide custom initialization of the reader, 19 // then proceed with actually loading the bean definitions. 20 initBeanDefinitionReader(beanDefinitionReader); 21 loadBeanDefinitions(beanDefinitionReader); 22 }
这个方法主要工作就是定义并初始了XmlBeanDefinitionReader实例。
注意15行,是把this(XmlWebApplicationContext实例)设置到了XmlBeanDefinitionReader实例中,进入loadBeanDefinitions(beanDefinitionReader)方法
//org.springframework.web.context.support.XmlWebApplicationContext
1 /** 2 * Load the bean definitions with the given XmlBeanDefinitionReader. 3 * <p>The lifecycle of the bean factory is handled by the refreshBeanFactory method; 4 * therefore this method is just supposed to load and/or register bean definitions. 5 * <p>Delegates to a ResourcePatternResolver for resolving location patterns 6 * into Resource instances. 7 * @throws java.io.IOException if the required XML document isn't found 8 * @see #refreshBeanFactory 9 * @see #getConfigLocations 10 * @see #getResources 11 * @see #getResourcePatternResolver 12 */ 13 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException { 14 String[] configLocations = getConfigLocations(); 15 if (configLocations != null) { 16 for (String configLocation : configLocations) { 17 reader.loadBeanDefinitions(configLocation); 18 } 19 } 20 }
第14行,获取配置文件,可以看出获取了多个配置文件,这就解释了在web.xml中contextConfigLocation参数值可以配置多个xml文件。如果web.xml没有设置配置文件,则默认配置文件为:/WEB-INF/applicationContext.xml,这个通过跟踪getConfigLocations()不难发现,这个留给大家自行跟踪查看。
然后调用XmlBeanDefinitionReader实例,依次解析配置文件。
下一章我们就重分析XmlBeanDefinitionReader实例如何解析配置文件。
★★★友情提示★★★
XmlWebApplicationContext类继承结构: