返回介绍

2.8 解析及注册 BeanDefinitions

发布于 2025-04-22 22:09:08 字数 3096 浏览 0 评论 0 收藏

当把文件转换为 Document 后,接下来的提取及注册 bean 就是我们的重头戏。继续上面的分析,当程序已经拥有 XML 文档文件的 Document 实例对象时,就会被引入下面这个方法。

XmlBeanDefinitionReader.java

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStore

Exception {

 //使用 DefaultBeanDefinitionDocumentReader 实例化 BeanDefinitionDocumentReader

  BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();

 //将环境变量设置其中

 documentReader.setEnvironment(this.getEnvironment());

 //在实例化 BeanDefinitionReader 时候会将 BeanDefinitionRegistry 传入,默认使用继承自

 DefaultListableBeanFactory 的子类

 //记录统计前 BeanDefinition 的加载个数

  int countBefore = getRegistry().getBeanDefinitionCount();

//加载及注册 bean

  documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

 //记录本次加载的 BeanDefinition 个数

  return getRegistry().getBeanDefinitionCount() - countBefore;

}

其中的参数 doc 是通过上一节 loadDocument 加载转换出来的。在这个方法中很好地应用了面向对象中单一职责的原则,将逻辑处理委托给单一的类进行处理,而这个逻辑处理类就是 BeanDefinitionDocumentReader。 BeanDefinitionDocumentReader 是一个接口,而实例化的工作是在 createBeanDefinitionDocumentReader() 中完成的,而通过此方法,BeanDefinitionDocumentReader 真正的类型其实已经是 DefaultBeanDefinitionDocumentReader 了,进入 DefaultBeanDefinition Document Reader 后,发现这个方法的重要目的之一就是提取 root,以便于再次将 root 作为参数继续 BeanDefinition 的注册。

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {

  this.readerContext = readerContext;

  logger.debug("Loading bean definitions");

  Element root = doc.getDocumentElement();

 doRegisterBeanDefinitions(root);

}

经过艰难险阻,磕磕绊绊,我们终于到了核心逻辑的底部 doRegisterBeanDefinitions(root),至少我们在这个方法中看到了希望。

如果说以前一直是 XML 加载解析的准备阶段,那么 doRegisterBeanDefinitions 算是真正地开始进行解析了,我们期待的核心部分真正开始了。

protected void doRegisterBeanDefinitions(Element root) {

 //处理 profile 属性

  String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);

  if (StringUtils.hasText(profileSpec)) {

   Assert.state(this.environment != null, "environment property must not be null");

   String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec,

  BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);

   if (!this.environment.acceptsProfiles(specifiedProfiles)) {

   return;

  }

 }

 //专门处理解析

  BeanDefinitionParserDelegate parent = this.delegate;

  this.delegate = createHelper(readerContext, root, parent);

 //解析前处理,留给子类实现

 preProcessXml(root);

 parseBeanDefinitions(root, this.delegate);

 //解析后处理,留给子类实现

 postProcessXml(root);

  this.delegate = parent;

}

通过上面的代码我们看到了处理流程,首先是对 profile 的处理,然后开始进行解析,可是当我们跟进 preProcessXml(root) 或者 postProcessXml(root) 发现代码是空的,既然是空的写着还有什么用呢?就像面向对象设计方法学中常说的一句话,一个类要么是面向继承的设计的,要么就用 final 修饰。在 DefaultBeanDefinitionDocumentReader 中并没有用 final 修饰,所以它是面向继承而设计的。这两个方法正是为子类而设计的,如果读者有了解过设计模式,可以很快速地反映出这是模版方法模式,如果继承自 DefaultBeanDefinitionDocumentReader 的子类需要在 Bean 解析前后做一些处理的话,那么只需要重写这两个方法就可以了。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。