Spring源码解析-XmlBeanDefinitionReader与Resource

159 阅读2分钟

XmlBeanDefinitionReader的几个关键方法讲解

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(); //注意resourcesCurrentlyBeingLoaded是一个ThreadLocal变量,获取当前线程的Set<EncodedResource>
	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());//真正加载BeanDefinition
		}
		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();
		}
	}
}

这个方法用于从指定的 XML 文件加载 bean 定义。

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
		throws BeanDefinitionStoreException {
	try {
		Document doc = doLoadDocument(inputSource, resource);//XML文件所定义的Document对象
		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);
	}
}

这个方法实际上从指定的 XML 文件加载 bean 定义。

@SuppressWarnings("deprecation")
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
	BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
	documentReader.setEnvironment(getEnvironment());
	int countBefore = getRegistry().getBeanDefinitionCount();
	documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
	return getRegistry().getBeanDefinitionCount() - countBefore;
}

注册包含在给定 DOM 文档中的 bean 定义,会被loadBeanDefinitions所调用,创建解析器类的新实例并调用

BeanDefinitionDocumentReader这个接口用于解析包含 Spring bean 定义的 XML 文档的 SPI。由 XmlBeanDefinitionReader 用于实际解析 DOM 文档。实现类是DefaultBeanDefinitionDocumentReader。

DefaultBeanDefinitionDocumentReader类的registerBeanDefinitions方法根据“spring-beans”XSD解析bean定义,打开一个 DOM 文档;然后初始化在 beans 级别指定的默认设置 ;然后解析包含的 bean 定义。

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
	this.readerContext = readerContext;
	logger.debug("Loading bean definitions");
	Element root = doc.getDocumentElement();
	doRegisterBeanDefinitions(root);
}

在给定的根 {@code } 元素中注册每个 bean 定义。

protected void doRegisterBeanDefinitions(Element root) {
	//任何嵌套的 <beans> 元素都将导致此方法中的递归。
            // 在为了正确传播和保留 <beans> default-* 属性,跟踪当前(父)委托,它可能为空。 
            //创造新的(子)委托,带有对父级的引用,用于回退目的,然后最终将 this.delegate 重置为其原始(父)引用。
            //这种行为模拟了一堆委托,而实际上并不需要一个。
	BeanDefinitionParserDelegate parent = this.delegate;
	this.delegate = createDelegate(getReaderContext(), root, parent);

	if (this.delegate.isDefaultNamespace(root)) {
		String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
		if (StringUtils.hasText(profileSpec)) {
			String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
					profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
			if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
				return;
			}
		}
	}
        //经典的模板方法模式 preProcessXml(root);和postProcessXml(root);都是空实现,子类可以对其实现自定义扩展
	preProcessXml(root);
	parseBeanDefinitions(root, this.delegate);
	postProcessXml(root);

	this.delegate = parent;
}

BeanDefinitionParserDelegate用于解析 XML bean 定义的有状态委托类。供主解析器和任何扩展使用 {@link BeanDefinitionParser BeanDefinitionParsers}或{@link BeanDefinitionDecorator BeanDefinitionDecorators}。