1. 程式人生 > >spring原始碼(9)自定義標籤與自定義標籤的解析

spring原始碼(9)自定義標籤與自定義標籤的解析

一、自定義標籤

  • 建立model
package com.demo3;
/**
 * 
 * @author dqf
 * @since 5.0
 */
public class User {
    private String userName;
    private String email;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public
String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
  • 定義一個XSD檔案描述
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema" 
targetNamespace="http://www.dqf.com/schema/user"
xmlns:tns="http://www.dqf.com/schema/user"
elementFormDefault="qualified">
<element name="user"> <complexType> <attribute name="id" type="string"></attribute> <attribute name="userName" type="string"></attribute> <attribute name="email" type="string">
</attribute> </complexType> </element> </schema>
  • 定義用來解析XSD檔案中定義和元件
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser{

    protected Class getBeanClass(Element element){
        return User.class;
    }

    @Override
    protected void doParse(Element element, BeanDefinitionBuilder bean) {
        String userName = element.getAttribute("userName");
        String email = element.getAttribute("email");
        if(org.springframework.util.StringUtils.hasText(userName)){
            bean.addPropertyValue("userName", userName);
        }
        if(org.springframework.util.StringUtils.hasText(email)){
            bean.addPropertyValue("email", email);
        }
    }
}
  • 定義一個Handler檔案,將元件註冊到Spring容器
public class MyNamespaceHandler extends NamespaceHandlerSupport{

    @Override
    public void init() {
        registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
    }

}
  • 新增Spring.handlers,spring.schemas檔案
http\://www.dqf.com/schema/user=com.demo3.MyNamespaceHandler
http\://www.dqf.com/schema/user.xsd=META-INF/customtag.xsd
  • 測試
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:myname="http://www.dqf.com/schema/user"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.dqf.com/schema/user 
        http://www.dqf.com/schema/user.xsd">

    <myname:user id="testbean" userName="aaa" email="bbb"></myname:user>
    <bean id="myTestBean" class="com.demo.model.MyTestBean" />
</beans>
public class App {
    public static void main(String[] args) {
        BeanFactory bf = new XmlBeanFactory(new ClassPathResource("springContext.xml"));
        MyTestBean testBean = (MyTestBean)bf.getBean("myTestBean");
        System.out.println(testBean.getTestStr());

        User test = (User) bf.getBean("testbean");
        System.out.println(test.getUserName()+","+test.getEmail());
    }
}
  • 結果
    這裡寫圖片描述

二、自定義標籤的解析

1、整體過程

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

2、提取自定義標籤處理器

@Override
    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();
                //記錄在快取中    
                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);
            }
        }
    }

3、標籤解析

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