返回介绍

4.2.2 提取自定义标签处理器

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

有了命名空间,就可以进行 NamespaceHandler 的提取了,继续之前的 parseCustomElement 函数的跟踪,分析 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver(). resolve(namespaceUri),在 readerContext 初始化的时候其属性 namespaceHandlerResolver 已经被初始化为了 DefaultNamespaceHandlerResolver 的实例,所以,这里调用的 resolve 方法其实调用的是 DefaultNamespaceHandlerResolver 类中的方法。我们进入 DefaultNamespaceHandlerResolver 的 resolve 方法进行查看。

DefaultNamespaceHandlerResolver.java

public NamespaceHandler resolve(String namespaceUri) {

 //获取所有已经配置的 handler 映射

  Map<String, Object> handlerMappings = getHandlerMappings();

 //根据命名空间找到对应的信息

  Object handlerOrClassName = handlerMappings.get(namespaceUri);

  if (handlerOrClassName == null) {

   return null;

  }else if (handlerOrClassName instanceof NamespaceHandler) {

  //已经做过解析的情况,直接从缓存读取

   return (NamespaceHandler) handlerOrClassName;

  }else {

  //没有做过解析,则返回的是类路径

   String className = (String) handlerOrClassName;

   try {

   //使用反射将类路径转化为类

    Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);

    if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {

     throw new FatalBeanException("Class [" + className + "] for

     namespace [" + namespaceUri +

     "] does not implement the [" + NamespaceHandler. class.

     getName() + "] interface");

   }

   //初始化类

    NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.

   instantiateClass(handlerClass);

   //调用自定义的 NamespaceHandler 的初始化方法

   namespaceHandler.init();

   //记录在缓存

    handlerMappings.put(namespaceUri, namespaceHandler);

    return namespaceHandler;

   }catch (ClassNotFoundException ex) {

    throw new FatalBeanException("NamespaceHandler class [" + className +

    "] for namespace [" +

    namespaceUri + "] not found", ex);

   }catch (LinkageError err) {

    throw new FatalBeanException("Invalid NamespaceHandler class [" +

    className + "] for namespace [" +

    namespaceUri + "]: problem with handler class file or dependent

    class", err);

  }

 }

}

上面的函数清晰地阐述了解析自定义 NamespaceHandler 的过程,通过之前的示例程序我们了解到如果要使用自定义标签,那么其中一项必不可少的操作就是在 Spring.handlers 文件中配置命名空间与命名空间处理器的映射关系。只有这样,Spring 才能根据映射关系找到匹配的处理器,而寻找匹配的处理器就是在上面函数中实现的,当获取到自定义的 NamespaceHandler 之后就可以进行处理器初始化并解析了。我们不妨再次回忆一下示例中对于命名空间处理器的内容:

public class MyNamespaceHandler extends NamespaceHandlerSupport {

  public void init() {

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

 }

}

当得到自定义命名空间处理后会马上执行 namespaceHandler.init() 来进行自定义 Bean DefinitionParser 的注册。在这里,你可以注册多个标签解析器,当前示例中只有支持<myname:user 的写法,你也可以在这里注册多个解析器,如<myname:A、<myname:B 等,使得 myname 的命名空间中可以支持多种标签解析。

注册后,命名空间处理器就可以根据标签的不同来调用不同的解析器进行解析。那么,根据上面的函数与之前介绍过的例子,我们基本上可以推断 getHandlerMappings 的主要功能就是读取 Spring.handlers 配置文件并将配置文件缓存在 map 中。

private Map<String, Object> getHandlerMappings() {

 //如果没有被缓存则开始进行缓存

  if (this.handlerMappings == null) {

   synchronized (this) {

    if (this.handlerMappings == null) {

     try {

     //this.handlerMappingsLocation 在构造函数中已经被初始化为:META-

     INF/Spring.handlers

      Properties mappings =

      PropertiesLoaderUtils.loadAllProperties (this.

      handlerMappingsLocation, this.classLoader);

      if (logger.isDebugEnabled()) {

       logger.debug("Loaded NamespaceHandler mappings: " + mappings);

     }

      Map<String, Object> handlerMappings = new ConcurrentHashMap<

String, Object>();

     //将 Properties 格式文件合并到 Map 格式的 handlerMappings 中

      CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);

      this.handlerMappings = handlerMappings;

    }

     catch (IOException ex) {

      throw new IllegalStateException(

      "Unable to load NamespaceHandler mappings from

      location [" + this.handlerMappingsLocation + "]", ex);

    }

   }

  }

 }

  return this.handlerMappings;

}

同我们想象的一样,借助了工具类 PropertiesLoaderUtils 对属性 handlerMappingsLocation 进行了配置文件的读取,handlerMappingsLocation 被默认初始化为“META-INF/Spring.handlers”。

发布评论

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