Spring 源码解析(三)加载配置文件3
继续上一章,我们来分析XmlBeanDefinitionReader的loadBeanDefinitions(configLocation)方法,跟踪方法最后调用的是其父类org.springframework.beans.factory.support.AbstractBeanDefinitionReader中的loadBeanDefinitions(String location, Set<Resource> actualResources)方法
//org.springframework.beans.factory.support.AbstractBeanDefinitionReader
1 /** 2 * Load bean definitions from the specified resource location. 3 * <p>The location can also be a location pattern, provided that the 4 * ResourceLoader of this bean definition reader is a ResourcePatternResolver. 5 * @param location the resource location, to be loaded with the ResourceLoader 6 * (or ResourcePatternResolver) of this bean definition reader 7 * @param actualResources a Set to be filled with the actual Resource objects 8 * that have been resolved during the loading process. May be {@code null} 9 * to indicate that the caller is not interested in those Resource objects. 10 * @return the number of bean definitions found 11 * @throws BeanDefinitionStoreException in case of loading or parsing errors 12 * @see #getResourceLoader() 13 * @see #loadBeanDefinitions(org.springframework.core.io.Resource) 14 * @see #loadBeanDefinitions(org.springframework.core.io.Resource[]) 15 */ 16 public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException { 17 ResourceLoader resourceLoader = getResourceLoader(); 18 if (resourceLoader == null) { 19 throw new BeanDefinitionStoreException( 20 "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); 21 } 22 23 if (resourceLoader instanceof ResourcePatternResolver) { 24 // Resource pattern matching available. 25 try { 26 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); 27 int loadCount = loadBeanDefinitions(resources); 28 if (actualResources != null) { 29 for (Resource resource : resources) { 30 actualResources.add(resource); 31 } 32 } 33 if (logger.isDebugEnabled()) { 34 logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); 35 } 36 return loadCount; 37 } 38 catch (IOException ex) { 39 throw new BeanDefinitionStoreException( 40 "Could not resolve bean definition resource pattern [" + location + "]", ex); 41 } 42 } 43 else { 44 // Can only load single resources by absolute URL. 45 Resource resource = resourceLoader.getResource(location); 46 int loadCount = loadBeanDefinitions(resource); 47 if (actualResources != null) { 48 actualResources.add(resource); 49 } 50 if (logger.isDebugEnabled()) { 51 logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); 52 } 53 return loadCount; 54 } 55 }
从注释的第一句话--Load bean definitions from the specified resource location,我们就能明白这个方法做了什么事情。
第17行,获取ResourceLoader,其实就是前面创建的XmlWebApplicationContext实例。下图清楚表明了两者之间的关系

第26行,按照配置文件路径location获取Resource类型数组,实际的实现类为ServletContextResource,这个类中包装了servletContext和配置文件路径path,还提供了一些访问资源的方法。
第27行,解析了配置文件,跟踪方法,最终调用的是类中的loadBeanDefinitions(EncodedResource encodedResource)方法
//org.springframework.beans.factory.xml.XmlBeanDefinitionReader
1 /** 2 * Load bean definitions from the specified XML file. 3 * @param encodedResource the resource descriptor for the XML file, 4 * allowing to specify an encoding to use for parsing the file 5 * @return the number of bean definitions found 6 * @throws BeanDefinitionStoreException in case of loading or parsing errors 7 */ 8 public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { 9 Assert.notNull(encodedResource, "EncodedResource must not be null"); 10 if (logger.isInfoEnabled()) { 11 logger.info("Loading XML bean definitions from " + encodedResource.getResource()); 12 } 13 14 Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); 15 if (currentResources == null) { 16 currentResources = new HashSet<EncodedResource>(4); 17 this.resourcesCurrentlyBeingLoaded.set(currentResources); 18 } 19 if (!currentResources.add(encodedResource)) { 20 throw new BeanDefinitionStoreException( 21 "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); 22 } 23 try { 24 InputStream inputStream = encodedResource.getResource().getInputStream(); 25 try { 26 InputSource inputSource = new InputSource(inputStream); 27 if (encodedResource.getEncoding() != null) { 28 inputSource.setEncoding(encodedResource.getEncoding()); 29 } 30 return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); 31 } 32 finally { 33 inputStream.close(); 34 } 35 } 36 catch (IOException ex) { 37 throw new BeanDefinitionStoreException( 38 "IOException parsing XML document from " + encodedResource.getResource(), ex); 39 } 40 finally { 41 currentResources.remove(encodedResource); 42 if (currentResources.isEmpty()) { 43 this.resourcesCurrentlyBeingLoaded.remove(); 44 } 45 } 46 }
第24行,从Resource(实际是前边创建的servletContextResource)获取输入流。
第26行,根据数据流创建InputSource。
第30行,处理InputSource,即解析配置文件,进入方法
//org.springframework.beans.factory.xml.XmlBeanDefinitionReader
1 /** 2 * Actually load bean definitions from the specified XML file. 3 * @param inputSource the SAX InputSource to read from 4 * @param resource the resource descriptor for the XML file 5 * @return the number of bean definitions found 6 * @throws BeanDefinitionStoreException in case of loading or parsing errors 7 * @see #doLoadDocument 8 * @see #registerBeanDefinitions 9 */ 10 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) 11 throws BeanDefinitionStoreException { 12 try { 13 Document doc = doLoadDocument(inputSource, resource); 14 return registerBeanDefinitions(doc, resource); 15 } 16 //省略catch 17 }
从注释的第一行--Actually load bean definitions from the specified XML file,这个方法是真正从指定的配置文件加载bean。
第13行,将配置文件转换Document实例。
第14行,解析Document实例,进入方法
//org.springframework.beans.factory.xml.XmlBeanDefinitionReader
1 /** 2 * Register the bean definitions contained in the given DOM document. 3 * Called by {@code loadBeanDefinitions}. 4 * <p>Creates a new instance of the parser class and invokes 5 * {@code registerBeanDefinitions} on it. 6 * @param doc the DOM document 7 * @param resource the resource descriptor (for context information) 8 * @return the number of bean definitions found 9 * @throws BeanDefinitionStoreException in case of parsing errors 10 * @see #loadBeanDefinitions 11 * @see #setDocumentReaderClass 12 * @see BeanDefinitionDocumentReader#registerBeanDefinitions 13 */ 14 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { 15 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); 16 documentReader.setEnvironment(this.getEnvironment()); 17 int countBefore = getRegistry().getBeanDefinitionCount(); 18 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); 19 return getRegistry().getBeanDefinitionCount() - countBefore; 20 }
第15行,创建BeanDefinitionDocumentReader实例(实际上是其实现类DefaultBeanDefinitionDocumentReader实例),用来解析Document。
第18行,创建了XmlReaderContext实例,调用DefaultBeanDefinitionDocumentReader的registerBeanDefinitions()方法解析document。
我们先来总结下XmlBeanDefinitionReader的工作,下一章介绍BeanDefinitionDocumentReader如何解析document。
1、根据配置文件路径创建Resource实例(实际上是其实现类servletContextResource实例,包含了servletContext和配置文件路径path),
2、通过Resource实例创建InputSource,
3、根据InputSource、Resource创建Document,
4、创建XmlReaderContext实例,包含了Resource、ProblemReporter、EventListener 、SourceExtractor、XmlBeanDefinitionReader、NamespaceHandlerResolver,
4、创建BeanDefinitionDocumentReader实例(实际上是其实现类DefaultBeanDefinitionDocumentReader实例),
5、调用DefaultBeanDefinitionDocumentReader的registerBeanDefinitions(Document doc, XmlReaderContext readerContext)方法解析Document。

浙公网安备 33010602011771号