返回介绍

4.2.3 标签解析

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

得到了解析器以及要分析的元素后,Spring 就可以将解析工作委托给自定义解析器去解析了。在 Spring 中的代码为:

return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd))

以之前提到的示例进行分析,此时的 handler 已经被实例化成为了我们自定义的 MyNamespaceHandler 了,而 MyNamespaceHandler 也已经完成了初始化的工作,但是在我们实现的自定义命名空间处理器中并没有实现 parse 方法,所以推断,这个方法是父类中的实现,查看父类 NamespaceHandlerSupport 中的 parse 方法。

NamespaceHandlerSupport.java

public BeanDefinition parse(Element element, ParserContext parserContext) {

 //寻找解析器并进行解析操作

   returnfindParserForElement(element, parserContext).parse(element, parserContext);

 }

解析过程中首先是寻找元素对应的解析器,进而调用解析器中的 parse 方法,那么结合示例来讲,其实就是首先获取在 MyNameSpaceHandler 类中的 init 方法中注册的对应的 UserBean DefinitionParser 实例,并调用其 parse 方法进行进一步解析。

private BeanDefinitionParser findParserForElement(Element element, ParserContext parser

Context) {

 //获取元素名称,也就是<myname:user 中的 user,若在示例中,此时 localName 为 user

  String localName = parserContext.getDelegate().getLocalName(element);

//根据 user 找到对应的解析器,也就是在

//registerBeanDefinitionParser("user", new UserBeanDefinitionParser());

//注册的解析器

  BeanDefinitionParser parser = this.parsers.get(localName);

  if (parser == null) {

  parserContext.getReaderContext().fatal(

   "Cannot locate BeanDefinitionParser for element [" + localName +

   "]", element);

 }

  return parser;

}

而对于 parse 方法的处理:

public final BeanDefinition parse(Element element, ParserContext parserContext) {

  AbstractBeanDefinition definition = parseInternal(element, parserContext);

  if (definition != null && !parserContext.isNested()) {

   try {

    String id = resolveId(element, definition, parserContext);

    if (!StringUtils.hasText(id)) {

    parserContext.getReaderContext().error(

     "Id is required for element '" + parserContext.

    getDelegate().getLocalName(element)

     + "' when used as a top-level tag", element);

   }

    String[] aliases = new String[0];

    String name = element.getAttribute(NAME_ATTRIBUTE);

    if (StringUtils.hasLength(name)) {

     aliases =

    StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));

   }

   //将 AbstractBeanDefinition 转换为 BeanDefinitionHolder 并注册

    BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id,

   aliases);

    registerBeanDefinition(holder, parserContext.getRegistry());

    if (shouldFireEvents()) {

    //需要通知监听器则进行处理

     BeanComponentDefinition componentDefinition = new BeanComponent

    Definition(holder);

    postProcessComponentDefinition(componentDefinition);

    parserContext.registerComponent(componentDefinition);

   }

  }

   catch (BeanDefinitionStoreException ex) {

    parserContext.getReaderContext().error(ex.getMessage(), element);

    return null;

  }

 }

  return definition;

}

虽说是对自定义配置文件的解析,但是,我们可以看到,在这个函数中大部分的代码是用来处理将解析后的 AbstractBeanDefinition 转化为 BeanDefinitionHolder 并注册的功能,而真正去做解析的事情委托给了函数 parseInternal,正是这句代码调用了我们自定义的解析函数。

在 parseInternal 中并不是直接调用自定义的 doParse 函数,而是进行了一系列的数据准备,包括对 beanClass、scope、lazyInit 等属性的准备。

protected final AbstractBeanDefinition parseInternal(Element element, ParserContext

parserContext) {

  BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();

  String parentName = getParentName(element);

  if (parentName != null) {

  builder.getRawBeanDefinition().setParentName(parentName);

 }

//获取自定义标签中的 class,此时会调用自定义解析器如 UserBeanDefinitionParser 中的 getBeanClass

方法。

  Class<?> beanClass = getBeanClass(element);

  if (beanClass != null) {

  builder.getRawBeanDefinition().setBeanClass(beanClass);

 }

  else {

 //若子类没有重写 getBeanClass 方法则尝试检查子类是否重写 getBeanClassName 方法

   String beanClassName = getBeanClassName(element);

   if (beanClassName != null) {

   builder.getRawBeanDefinition().setBeanClassName(beanClassName);

  }

 }

 builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));

  if (parserContext.isNested()) {

 //若存在父类则使用父类的 scope 属性

  builder.setScope(parserContext.getContainingBeanDefinition().getScope());

 }

  if (parserContext.isDefaultLazyInit()) {

   // Default-lazy-init applies to custom bean definitions as well.

 //配置延迟加载

  builder.setLazyInit(true);

 }

//调用子类重写的 doParse 方法进行解析

 doParse(element, parserContext, builder);

  return builder.getBeanDefinition();

 }

protected void doParse(Element element, ParserContext parserContext, BeanDefinition

Builder builder) {

 doParse(element, builder);

}

回顾一下全部的自定义标签处理过程,虽然在实例中我们定义 UserBeanDefinitionParser,但是在其中我们只是做了与自己业务逻辑相关的部分。不过我们没做但是并不代表没有,在这个处理过程中同样也是按照 Spring 中默认标签的处理方式进行,包括创建 BeanDefinition 以及进行相应默认属性的设置,对于这些工作 Spring 都默默地帮我们实现了,只是暴露出一些接口来供用户实现个性化的业务。通过对本章的了解,相信读者对 Spring 中自定义标签的使用以及在解析自定义标签过程中 Spring 为我们做了哪些工作会有一个全面的了解。到此为止我们已经完成了 Spring 中全部的解析工作,也就是说到现在为止我们已经理解了 Spring 将 bean 从配置文件到加载到内存中的全过程,而接下来的任务便是如何使用这些 bean,下一章将介绍 bean 的加载。

发布评论

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