Spring BeanDefinitionDocumentReader
- Author: HuiFer
- 源码浏览仓库: SourceHot-spring
- 全门路:
org.springframework.beans.factory.xml.BeanDefinitionDocumentReader
/**
* SPI for parsing an XML document that contains Spring bean definitions. * Used by {@link XmlBeanDefinitionReader} for actually parsing a DOM document. * * <p>Instantiated per document to parse: implementations can hold * state in instance variables during the execution of the * {@code registerBeanDefinitions} method — for example, global * settings that are defined for all bean definitions in the document. * * * <p>bean 定义文档读取 </p>
* @author Juergen Hoeller * @author Rob Harrop * @since 18.12.2003 * @see XmlBeanDefinitionReader#setDocumentReaderClass */public interface BeanDefinitionDocumentReader {
/** * Read bean definitions from the given DOM document and * register them with the registry in the given reader context. * 注册 bean 定义
* @param doc the DOM document * @param readerContext the current context of the reader * (includes the target registry and the resource being parsed) * @throws BeanDefinitionStoreException in case of parsing errors */ void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) throws BeanDefinitionStoreException;
}
-
通过正文咱们能够晓得这个接口定义的行为如下
- 读取 xml 配置文件, 转换成 Spring bean definition
- 将 Spring bean definition 放入内存中
- 办法作用
- 读取给定文档, 转换成 Spring bean definition 放入内存
registerBeanDefinitions
- 接口定义的办法
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {this.readerContext = readerContext; doRegisterBeanDefinitions(doc.getDocumentElement());}
- 最终会交给
doRegisterBeanDefinitions
执行
doRegisterBeanDefinitions
@SuppressWarnings("deprecation") // for Environment.acceptsProfiles(String...) protected void doRegisterBeanDefinitions(Element root) {// Any nested <beans> elements will cause recursion in this method. In // order to propagate and preserve <beans> default-* attributes correctly, // keep track of the current (parent) delegate, which may be null. Create // the new (child) delegate with a reference to the parent for fallback purposes, // then ultimately reset this.delegate back to its original (parent) reference. // this behavior emulates a stack of delegates without actually necessitating one. BeanDefinitionParserDelegate parent = this.delegate; // 创立 BeanDefinitionParserDelegate this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) { // profile 属性获取
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); // 是否存在 profile if (StringUtils.hasText(profileSpec)) { // profile 切分后的数据
String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); // We cannot use Profiles.of(...) since profile expressions are not supported // in XML config. See SPR-12458 for details. if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {if (logger.isDebugEnabled()) {logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching:" + getReaderContext().getResource()); } return; } } }
// 前置解决
preProcessXml(root); // bean definition 解决
parseBeanDefinitions(root, this.delegate); // 后置 xml 解决
postProcessXml(root);
this.delegate = parent; }
createDelegate
this.delegate = createDelegate(getReaderContext(), root, parent)
-
参数阐明
- xml 解析器
- element xml 节点
- 父
BeanDefinitionParserDelegate
protected final XmlReaderContext getReaderContext() {Assert.state(this.readerContext != null, "No XmlReaderContext available"); return this.readerContext;}
preProcessXml
- 前置解决办法为空
parseBeanDefinitions
-
解析标签
- 标签 import
- 标签 alias
- 标签 bean
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {if (delegate.isDefaultNamespace(root)) { // 子节点列表
NodeList nl = root.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) {Node node = nl.item(i); if (node instanceof Element) {Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { // 解决标签的办法
parseDefaultElement(ele, delegate); } else { // 解决自定义标签
delegate.parseCustomElement(ele); } } } } else { // 解决自定义标签
delegate.parseCustomElement(root); }}
postProcessXml
- 后置解决办法为空
parseDefaultElement
- 将
parseDefaultElement
提出残缺的解析
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
// 解析 import 标签
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {importBeanDefinitionResource(ele); } // 解析 alias 标签
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {processAliasRegistration(ele); } // 解析 bean 标签
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {processBeanDefinition(ele, delegate); } // 解析 beans 标签
// 嵌套的 beans else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {// recurse doRegisterBeanDefinitions(ele); }}
importBeanDefinitionResource
protected void importBeanDefinitionResource(Element ele) {
// 获取 resource 属性
String location = ele.getAttribute(RESOURCE_ATTRIBUTE); if (!StringUtils.hasText(location)) {getReaderContext().error("Resource location must not be empty", ele); return; }
// Resolve system properties: e.g. "${user.dir}" // 解决配置文件占位符
location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
// 资源汇合
Set<Resource> actualResources = new LinkedHashSet<>(4);
// Discover whether the location is an absolute or relative URI // 是不是相对地址
boolean absoluteLocation = false; try { // 1. 判断是否为 url // 2. 通过转换成 URI 判断是否是相对地址
absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();} catch (URISyntaxException ex) {// cannot convert to an URI, considering the location relative // unless it is the well-known Spring prefix "classpath*:"}
// Absolute or relative? if (absoluteLocation) { try { // 获取 import 的数量
int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources); if (logger.isTraceEnabled()) {logger.trace("Imported" + importCount + "bean definitions from URL location [" + location + "]"); } } catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to import bean definitions from URL location [" + location + "]", ele, ex); } } else { // No URL -> considering resource location as relative to the current file. try { // import 的数量
int importCount; // 资源信息
Resource relativeResource = getReaderContext().getResource().createRelative(location); // 资源是否存在
if (relativeResource.exists()) { // 确定加载的 bean 定义数量
importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource); // 退出资源汇合
actualResources.add(relativeResource); } // 资源不存在解决计划
else { // 获取资源 URL 的数据
String baseLocation = getReaderContext().getResource().getURL().toString(); // 获取 import 数量
importCount = getReaderContext().getReader().loadBeanDefinitions(StringUtils.applyRelativePath(baseLocation, location), actualResources); } if (logger.isTraceEnabled()) {logger.trace("Imported" + importCount + "bean definitions from relative location [" + location + "]"); } } catch (IOException ex) {getReaderContext().error("Failed to resolve current resource location", ele, ex); } catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, ex); } } Resource[] actResArray = actualResources.toArray(new Resource[0]); // 唤醒 import 处理事件
getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));}
processAliasRegistration
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processAliasRegistration
- alias 标签解析
protected void processAliasRegistration(Element ele) {
// 获取 name 属性
String name = ele.getAttribute(NAME_ATTRIBUTE); // 获取 alias 属性
String alias = ele.getAttribute(ALIAS_ATTRIBUTE); boolean valid = true; // name 属性验证
if (!StringUtils.hasText(name)) {getReaderContext().error("Name must not be empty", ele); valid = false; } // alias 属性验证
if (!StringUtils.hasText(alias)) {getReaderContext().error("Alias must not be empty", ele); valid = false; } if (valid) {try { getReaderContext().getRegistry().registerAlias(name, alias); } catch (Exception ex) {getReaderContext().error("Failed to register alias'" + alias + "'for bean with name'" + name + "'", ele, ex); } // 事件触发
getReaderContext().fireAliasRegistered(name, alias, extractSource(ele)); }}
processBeanDefinition
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { // bean definition 装璜
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. // 注册 beanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) {getReaderContext().error("Failed to register bean definition with name'" + bdHolder.getBeanName() + "'", ele, ex); } // Send registration event. // component 注册事件触发
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); }}
- BeanDefinitionParserDelegate
ClassPathContextResource
- 创立出资源接口
protected static class ClassPathContextResource extends ClassPathResource implements ContextResource {public ClassPathContextResource(String path, @Nullable ClassLoader classLoader) {super(path, classLoader); }
@Override public String getPathWithinContext() { return getPath(); }
@Override public Resource createRelative(String relativePath) {String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath); return new ClassPathContextResource(pathToUse, getClassLoader()); }}
fireImportProcessed
/**
* Fire an import-processed event. * * 执行 import 事件
* @param importedResource 导入的文件
* @param actualResources 资源门路
* @param source source */public void fireImportProcessed(String importedResource, Resource[] actualResources, @Nullable Object source) {this.eventListener.importProcessed(new ImportDefinition(importedResource, actualResources, source));}
ReaderEventListener
事件监听
关注的办法
void importProcessed(ImportDefinition importDefinition);
实现
org.springframework.beans.testfixture.beans.CollectingReaderEventListener#importProcessed
@Override
public void importProcessed(ImportDefinition importDefinition) {this.imports.add(importDefinition);}
放入 imports
列表中
关注办法
void aliasRegistered(AliasDefinition aliasDefinition);```
实现
- `org.springframework.beans.testfixture.beans.CollectingReaderEventListener#aliasRegistered`
@Override
public void aliasRegistered(AliasDefinition aliasDefinition) {
// 获取曾经注册过的 beanName 对应的别名
List<AliasDefinition> aliases = this.aliasMap.get(aliasDefinition.getBeanName()); if (aliases == null) {aliases = new ArrayList<>(); // beanName 和 别名对应关系设置
this.aliasMap.put(aliasDefinition.getBeanName(), aliases); } // 别名列表增加
aliases.add(aliasDefinition);}
关注办法
void componentRegistered(ComponentDefinition componentDefinition);
实现
- `org.springframework.beans.testfixture.beans.CollectingReaderEventListener#componentRegistered`
@Override
public void componentRegistered(ComponentDefinition componentDefinition) {
this.componentDefinitions.put(componentDefinition.getName(), componentDefinition);}