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 />  
    </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

  • 工程截图
  • spring IOC 之篇四:自定义标签的解析

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

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();
    }