• spring IOC 之篇四:自定义标签的解析


    对代码delegate.parseCustomElement(ele);进行深入分析

    对于dubbo就是使用了spring自定义标签解析的功能特性。Spring自定 义标签解析的过程如下:

    1. 创建一个需要扩展的组件
    2. 定义一个XSD描述文件内容
    3. 创建一个类实现BeanDefinitionParser接口,用来解析XSD文件中的定义和组件中的定义
    4. 创建一个Handler组件,扩展自NamespaceHandlerSupport,目的是将组件注册到Spring容器
    5. 编写Spring.handlersSpring.schemas文件

    现在开始依据上面的步骤开始使用自定义标签解析

    1.创建一个类用来接收配置文件中的属性

    public class People {
            private String id;  
            private String name;  
            private Integer age; 
    // 省略get/set方法
    • 创建一个xsd文件描述xml语法约束
    • <?xml version="1.0" encoding="UTF-8"?>  
      <xsd:schema   
          xmlns="http://blog.csdn.net/cutesource/schema/people"  
          xmlns:xsd="http://www.w3.org/2001/XMLSchema"   
          xmlns:beans="http://www.springframework.org/schema/beans"  
          targetNamespace="http://blog.csdn.net/cutesource/schema/people"  
          elementFormDefault="qualified"   
          attributeFormDefault="unqualified">  
          <xsd:import namespace="http://www.springframework.org/schema/beans" />  
          <xsd:element name="people">  
              <xsd:complexType>  
                  <xsd:complexContent>  
                      <xsd:extension base="beans:identifiedType">  
                          <xsd:attribute name="name" type="xsd:string" />  
                          <xsd:attribute name="age" type="xsd:int" />  
                      </xsd:extension>  
                  </xsd:complexContent>  
              </xsd:complexType>  
          </xsd:element>  
      </xsd:schema> 
      在xsd定义了age 和name属性,与people实体里面的属性一一对应
    • 创建一个文件,实现BeanDefinitionParser接口,解析XSD和XML文件中的定义
    package com.spring.test.parser;
    
    import org.springframework.beans.factory.support.BeanDefinitionBuilder;
    import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
    import org.springframework.util.StringUtils;
    import org.w3c.dom.Element;
    
    import com.spring.test.pojo.People;
    
    public class PeopleBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
        // Element对应的类
     @Override
        protected Class getBeanClass(Element element) {  
            return People.class;  
    }  
    
    // 从element中解析并提取对应元素
         @Override
        protected void doParse(Element element, BeanDefinitionBuilder bean) {  
            String name = element.getAttribute("name");  
            String age = element.getAttribute("age");  
            String id = element.getAttribute("id");  
            if (StringUtils.hasText(id)) {  
          // 将提取的数据放入BeanDefinitionBuilder 中,待解析完成后放入统一注册到beanFactory
                bean.addPropertyValue("id", id);  
            }  
            if (StringUtils.hasText(name)) {  
                bean.addPropertyValue("name", name);  
            }  
            if (StringUtils.hasText(age)) {  
                bean.addPropertyValue("age", Integer.valueOf(age));  
            }  
        }  
    }







    编写Spring.handlers和Spring.schemas文件

    Spring.handlers

    http://blog.csdn.net/cutesource/schema/people=com.spring.test.handler.MyNamespaceHandler

    Spring.schemas

    http://blog.csdn.net/cutesource/schema/people.xsd=META-INF/people.xsd

    到这里自定义标签的各种配置就结束了,而Spring自定义标签解析的流程就是根据Spring.handlersSpring.schemas定义的内容去找对应的handlerxsd,默认位置是 META-INF/下面

    • 创建测试配置文件 引入自定义标签的解析的路径和名称空间
    • <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"  
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
          xmlns:cutesource="http://blog.csdn.net/cutesource/schema/people"  
          xsi:schemaLocation="  
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
      http://blog.csdn.net/cutesource/schema/people http://blog.csdn.net/cutesource/schema/people.xsd">  
          <cutesource:people id="cutesource" name="袁志俊" age="27"/>  
      </beans> 

      创建测试

    • public class CustomHandler {
          
          public static void main(String[] args) {
              
              
              ApplicationContext ctx = new ClassPathXmlApplicationContext("customer.xml");
              People p = (People)ctx.getBean("people");  
              System.out.println(p.getId());  
              System.out.println(p.getName());  
              System.out.println(p.getAge());
      }

      控制台打印:

      Init method after properties are set id : initIt---afterPropertiesSet
      initIt---afterPropertiesSet
      袁志俊
      27

    • 工程截图

    了解了自定义标签的使用,接下来对源码进行分析

    public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
           // 获取对应的命名空间
            String namespaceUri = getNamespaceURI(ele);
         // 根据命名空间找到对应的NamespaceHandler
            NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
            if (handler == null) {
                error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
                return null;
            }
        // 调用自定义的NamespaceHandler进行解析
            return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
        }

    主要分析: NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); 根据命名空间找到对应的NamespaceHandler

    在readerContext初始化的时候,其属性NamespaceHandlerResolver已经被初始化为DefaultNamespaceHandlerResolver实例,我们直接调用DefaultNamespaceHandlerResolverresolve方法即可。

        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.init();
    // 将解析好的Handler 记录在缓存
                    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);
                }
            }
        }

    继续进行handler.parse(ele, new ParserContext(this.readerContext, this, containingBd))的分析

    /**
         * Locates the {@link BeanDefinitionParser} from the register implementations using
         * the local name of the supplied {@link Element}.
         */
        private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
            // 获取的名称为people 即localName为people
            String localName = parserContext.getDelegate().getLocalName(element);
            // 获取对应的解析器 即代码registerBeanDefinitionParser("people", new PeopleBeanDefinitionParser()); 注册的解析器
            BeanDefinitionParser parser = this.parsers.get(localName);
            if (parser == null) {
                parserContext.getReaderContext().fatal(
                        "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
            }
            return parser;
        }

    解析方法的分析

    @Override
        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 = null;
                    if (shouldParseNameAsAliases()) {
                        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 BeanComponentDefinition(holder);
                        postProcessComponentDefinition(componentDefinition);
                        parserContext.registerComponent(componentDefinition);
                    }
                }
                catch (BeanDefinitionStoreException ex) {
                    parserContext.getReaderContext().error(ex.getMessage(), element);
                    return null;
                }
            }
            return definition;
        }

    主要解析逻辑

    AbstractBeanDefinition definition = parseInternal(element, parserContext)的处理

    @Override
        protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
            String parentName = getParentName(element);
            if (parentName != null) {
                builder.getRawBeanDefinition().setParentName(parentName);
            }
    // 获取自定义标签的中class,此时会调用自定义解析器,PeopleBeanDefinitionParser中的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()) {
                // Inner bean definition must receive same scope as containing bean.
        // 如果存在父类,则调用父类的scope属性        builder.setScope(parserContext.getContainingBeanDefinition().getScope());
            }
            if (parserContext.isDefaultLazyInit()) {
                // Default-lazy-init applies to custom bean definitions as well.
      // 是否配置延迟加载
                builder.setLazyInit(true);
            }
     // 调用子类重写的parse方法
            doParse(element, parserContext, builder);
            return builder.getBeanDefinition();
        }
  • 相关阅读:
    小条打印机输出简析
    Visual Studio离线安装
    删除“Open in Windows Terminal”右键菜单
    《新媒体营销精华:精准定位+爆款打造+匠心运营+内容变现》笔者的新书,欢迎各位粉丝上京东购买
    vue3.0 的 Composition API 的一种使用方法
    对比传统的Xilinx AMP方案和OPENAMP方案-xapp1078和ug1186【转】
    OpenAMP简介【转】
    git 用法【笔记】
    针对非对称多处理系统实现更简单的软件开发【转】
    内核探测工具systemtap简介【转】
  • 原文地址:https://www.cnblogs.com/histlyb/p/8983572.html
Copyright © 2020-2023  润新知