SpringIoc源码(四)- BeanFactory(三)- 自定义标签实现和分析

目录

1、自定义标签实现

1)、定义Bean

2)、spring.handlers

3)、spring.schemas

3)、Spring Xml配置文件

4) 、测试

2、自定义标签实现分析

1)、获取NamespaceHandler

2)、获取自定义的解析器(AbstractSingleBeanDefinitionParser的子类)


    为什么要看自定义标签,因为Spring中aop(aspectj-autoproxy)、事务开关(tx)等很多都实现了自定义标签,并且在当前项目中搜索了一下spring.handlers,发现有至少50个实现了自定义标签。


1、自定义标签实现

 

1)、定义Bean

@Data
public class KevinInfo {

    private String name;
}

 

    在maven项目resources(或者打包后的classes)下添加META-INF目录

2)、spring.handlers

    添加文件的内容为:

http\://www.kevin.com/schema/kevinInfo=com.kevin.tool.spring.ioc.customlabel.KevinNamespaceHandler

    定义NamespaceHandlerSupport的子类并在init方法中调用registerBeanDefinitionParser方法,如下:

public class KevinNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        // kevinInfo对应 Xsd文件中的 <element name="kevinInfo">
        registerBeanDefinitionParser("kevinInfo", new KevinInfoParser());
    }
}

    同时也指定了解析器,实现自AbstractSingleBeanDefinitionParser

public class KevinInfoParser extends AbstractSingleBeanDefinitionParser {
    @Override
    protected Class<?> getBeanClass(Element element) {
        return KevinInfo.class;
    }

    @Override
    protected void doParse(Element element, ParserContext parserContext, 
        BeanDefinitionBuilder builder) {

        String name = element.getAttribute("name");
        builder.addPropertyValue("name", name);
    }
}

 

3)、spring.schemas

    添加文件的内容为:

http\://www.kevin.com/schema/kevin.xsd=META-INF/kevin.xsd

    指定了xsd的位置,为同级目录,如下:

<?xml version="1.0" encoding="UTF-8" ?>
    <schema xmlns="http://www.w3.org/2001/XMLSchema"
            targetNamespace="http://www.kevin.com/schema/kevinInfo"
            elementFormDefault="qualified">

    <element name="kevinInfo">

        <complexType>
            <!-- bean id -->
            <attribute name="id" type="string" />
            <attribute name="name" type="string" />
        </complexType>
    </element>
</schema>

3)、Spring Xml配置文件

4) 、测试

public class CustomLabelTest {
    public static void main(String[] args) {
        BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-bean.xml"));
        KevinInfo kevinInfo = (KevinInfo)beanFactory.getBean("beanId");
        System.out.println(kevinInfo.getName());
    }
}

 

2、自定义标签实现分析

    回到上一篇分析自定义标签的位置,获取到了非Spring自定义的标签

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
    if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
            Node node = nl.item(i);
            if (node instanceof Element) {
                Element ele = (Element) node;
                if (delegate.isDefaultNamespace(ele)) {
                    parseDefaultElement(ele, delegate);
                }
                else {
                    delegate.parseCustomElement(ele);
                }
            }
        }
    }
    else {
        delegate.parseCustomElement(root);
    }
}

继续分析自定义标签:

public BeanDefinition parseCustomElement(Element ele) {
    return parseCustomElement(ele, null);
}
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
    String namespaceUri = getNamespaceURI(ele);
    if (namespaceUri == null) {
        return null;
    }
    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
    if (handler == null) {
        return null;
    }
    return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

    之前有分析过delefate是外层初始化传入,并且在调用方法之前有创建NamespaceResolver:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    int countBefore = getRegistry().getBeanDefinitionCount();
    documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
    return getRegistry().getBeanDefinitionCount() - countBefore;
}

  调用registerBeanDefinitions时调用了createReaderContext方法,内部又初始化了NamespaceResolverDefaultNamespaceHandlerResolver

public XmlReaderContext createReaderContext(Resource resource) {
    return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
            this.sourceExtractor, this, getNamespaceHandlerResolver());
}
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
    ClassLoader cl = (getResourceLoader() != null ? 
        getResourceLoader().getClassLoader() : getBeanClassLoader());
    return new DefaultNamespaceHandlerResolver(cl);
}

    进入构造函数:

public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) {
    this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);
}

    继续,(找了好久不知道DefaultNamespaceHandlerResolver内部的handlerMappings不知道是什么时候初始化的),还好debug进行调试,神奇的一幕发生了。

    这一步,本来是抛异常的,并且只都为空。debug,下一步

    异常没有了,handlerMappings初始化完了。网上有的说是其他线程完成的。不知道了,反正在这里初始化完了。

    还是继续往下:

1)、获取NamespaceHandler

所以当前拿到的命名空间就是http://www.kevin.com/schema/kevinInfo,去XmlReaderContext的namespaceHandlerResolver中handlerMappings去获取。调用resolve方法:

public NamespaceHandler resolve(String namespaceUri) {
    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("Could not find NamespaceHandler class [" + className +
                    "] for namespace [" + namespaceUri + "]", ex);
        }
        catch (LinkageError err) {
            throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
                    className + "] for namespace [" + namespaceUri + "]", err);
        }
    }
}

    使用反射获取到当前的NamespaceHandler 为KevinNamespaceHandler,调用其init方法,就是我们之前定义的:

@Override
public void init() {
    registerBeanDefinitionParser("kevinInfo", new KevinInfoParser());
}
protected final void registerBeanDefinitionParser(String elementName, 
    BeanDefinitionParser parser) {

    this.parsers.put(elementName, parser);
}

    这才将key和value值注入到NamespaceHandlerSupport中的parsers中,再调用parse方法。

 

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

2)、获取自定义的解析器(AbstractSingleBeanDefinitionParser的子类)

public BeanDefinition parse(Element element, ParserContext parserContext) {
    BeanDefinitionParser parser = findParserForElement(element, parserContext);
    return (parser != null ? parser.parse(element, parserContext) : null);
}
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
    String localName = parserContext.getDelegate().getLocalName(element);
    BeanDefinitionParser parser = this.parsers.get(localName);
    if (parser == null) {
        parserContext.getReaderContext().fatal(
                "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
    }
    return parser;
}

    很清楚的,刚才put进去,获取到了自定义的KevinInfoParser,再调用自定义的parse方法。

@Override
protected void doParse(Element element, ParserContext parserContext, 
    BeanDefinitionBuilder builder) {

    String name = element.getAttribute("name");
    builder.addPropertyValue("name", name);
}

   

    这样就实现了自定义标签的实现和解析,over!

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值