引自 spring IoC源码分析 (3)Resource解析
定义好了Resource之后,看到XmlFactoryBean的构造函数
- public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
- super(parentBeanFactory);
- this.reader.loadBeanDefinitions(resource);
- }
跟到XmlBeanDefinitionReader 的 loadBeanDefinitions(EncodedResource encodedResource) 方法
- 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());
- }
- //线程安全 ,但这里 currentResources应该本来就是线程安全的,所以推测不是为了线程安全
- //应该是为了线程能使用同一个 currentResources ,从这里可以看出作者对 ThreadLocal 的理解深刻
- Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
- if (currentResources == null) {
- currentResources = new HashSet<EncodedResource>(4);
- this.resourcesCurrentlyBeingLoaded.set(currentResources);
- }
- //这里其实就是为了避免循环加载,如果重复加载了相同的文件就会抛出异常
- //这里看了半天才明白这个set的意图,蛋疼啊
- if (!currentResources.add(encodedResource)) {
- throw new BeanDefinitionStoreException(
- "Detected recursive 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.set(null);
- }
- }
- }
- try {
- //判断xml文件是DTD还是XSD样式,如果没定义将使用XSD
- int validationMode = getValidationModeForResource(resource);
- Document doc = this.documentLoader.loadDocument(
- inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
- return registerBeanDefinitions(doc, resource);
- }
看下getValidationModeForResource 一路跟踪下来到XmlValidationModeDetector的detectValidationMode方法
- while ((content = reader.readLine()) != null) {
- content = consumeCommentTokens(content);
- if (this.inComment || !StringUtils.hasText(content)) {
- continue;
- }
- if (hasDoctype(content)) {
- isDtdValidated = true;
- break;
- }
- if (hasOpeningTag(content)) {
- // End of meaningful data...
- break;
- }
- }
就是分析下xml文件里有没有DOCTYPE关键字,没有的话就认为是xsd格式的。然后就到了documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware()); 这个方法
- 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 去解析xml,这块不怎么熟,查了下网上的介绍也没太详细的。
接着跟踪到registerBeanDefinitions 方法,关键部分:documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
- public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
- this.readerContext = readerContext;
- logger.debug("Loading bean definitions");
- Element root = doc.getDocumentElement();
- BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
- preProcessXml(root);
- parseBeanDefinitions(root, delegate);
- postProcessXml(root);
- }
preProcessXml和postProcessXml是提供扩展用得,这里没有具体实现,从字面上理解也是给之类提供预处理和事后处理用
的。具体解析工作是parseBeanDefinitions,跟踪到private void
parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
这个方法,我们主要关注对bean的解析,所以直接看processBeanDefinition(ele, delegate)
- /**
- * Process the given bean element, parsing the bean definition
- * and registering it with the registry.
- */
- protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
- /* BeanDefinitionHolder 是BeanDefinition对象的封装类,封装了 BeanDefinition,Bean的名字和别名。用它来完成向IoC容器注 册。 BeanDefinitionParserDelegate对XML元素的信息按照Spring的Bean规则进行解析*/
- BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
- if (bdHolder != null) {
- bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
- try {
- // Register the final decorated instance.
- BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
- }
- catch (BeanDefinitionStoreException ex) {
- getReaderContext().error("Failed to register bean definition with name '" +
- bdHolder.getBeanName() + "'", ele, ex);
- }
- // Send registration event.
- getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
- }
- }