XmlBeanFactory继承自DefaultListableBeanFactory,相比DefaultListableBeanFactory,它能解析Xml配置文件,因为它持有XmlBeanDefinitionReader,其构造方法调用了loadBeanDefinition方法
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource(resource)); }
loadBeanDefinition方法调用了下面这个方法
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<EncodedResource>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); } try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource(inputStream); if (encodedResource.getEncoding() != null) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this.resourcesCurrentlyBeingLoaded.remove(); } } }
通过查看代码可以看出改方法做了几件事情:
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { currentResources = new HashSet<EncodedResource>(4); this.resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException( "Detected cyclic loading of " + encodedResource + " - check your import definitions!"); }
获取线程的本地变量
resourcesCurrentlyBeingLoaded
,
resourcesCurrentlyBeingLoaded
保存了当前线程所加载的资源,是一个Set<EncodeResource>集合
真正的核心是调用doLoadBeanDefinitions(inputSource, encodedResource.getResource());
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); return registerBeanDefinitions(doc, resource); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (SAXParseException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex); } catch (SAXException ex) { throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", ex); } catch (ParserConfigurationException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, ex); } catch (IOException ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, ex); } catch (Throwable ex) { throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, ex); } }
doLoadBeanDefinitions方法做了两件事情:
1、doLoadDocument(inputSource, resource);
实际是调用了DefaultDocumentLoader对象的
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver, ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception { DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware); if (logger.isDebugEnabled()) { logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]"); } DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler); return builder.parse(inputSource); }
创建了DocumentBuilderFactory对象
然后构建了DocumentBuilder 对象
然后执行DocumentBuilder对象的parse解析方法
其实说白了就是将一个inputSource解析称一个document对象返回
具体怎么解析此处就不在跟踪下去,留个疑问,后续在回头看吧
2、registerBeanDefinitions(doc, resource);
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
此方法好像很厉害的样子,
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
此句创建一个BeanDefinitionDocumentReader对象,是怎么创建的呢?
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); }
这个创建方式比较奇葩啊!其实就是通过反射创建一个DefaultBeanDefinitionDocumentReader对象,然后在强转为BeanDefinitionDocumentReader类型的对象
此处等同于
return (BeanDefinitionDocumentReader)new DefaultBeanDefinitionDocumentReader();
为什么要这样子去创建一个BeanDefinitionDocumentReader类型的对象呢?我特么也纳闷。。。。。。容我思考片刻,
如果说是为了增加灵活性,documentReaderClass类型做到可配置化,那也不需要使用放射啊?
设置一个BeanDefinitionDocumentReader的成员变量,改成员变量默认使用DefaultBeanDefinitionDocumentReader
然后在需要修改的使用,对外提供一个public的set方法,传一个需要的BeanDefinitionDocumentReader类型进来不就可以了?为什么要使用反射呢?使用反射效果和这个一样的呀。。。。默认也是实例化DefaultBeanDefinitionDocumentReader.class;在需要更改的时候
public void setDocumentReaderClass(Class<?> documentReaderClass) { if (documentReaderClass == null || !BeanDefinitionDocumentReader.class.isAssignableFrom(documentReaderClass)) { throw new IllegalArgumentException( "documentReaderClass must be an implementation of the BeanDefinitionDocumentReader interface"); } this.documentReaderClass = documentReaderClass; }
调用setDocumentReaderClass方法去更改。那么使用反射的意义何在?百思不得其解
难道是为了防止这个类没有还没有被加载? 好像是这么一回事啊,别忘了spring通过XmlBeanFactory对象去读取配置文件,然后实例化对象的,在读取解析和生成DocumentReader之前,怎么能使用set方法传递一个BeanDefinitionDocumentReader类型进去呢?因为这个spring容器还没构建好,所以无法保证这个BeanDefinitionDocumentReader是已经正常初试化的。
int countBefore = getRegistry().getBeanDefinitionCount();
获得BeanDefinition定义器注册之前bean的数量
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
注册BeanDefinition
return getRegistry().getBeanDefinitionCount() - countBefore;
返回的是注册前后的数量差
这里有个疑问 BeanDefinition是什么概念,有什么作用,注册这玩意是干嘛用的呢?
总的来说
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
做两件事情,1、加载解析配置文件2、根据配置文件解析后的Document对象注册beanDefinition