spring自定义标签的解析8

本文详细介绍了Spring框架中自定义标签的解析过程,包括如何根据bean定义获取命名空间、如何提取自定义标签处理器以及如何将解析后的AbstractBeanDefinition转换为BeanDefinitionHolder并注册等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自定义标签的解析

/**

     * Parse the elements at the root level in the document:

     * "import", "alias", "bean".

     * @param root the DOM root element of the document

     */

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

        }

    }

 

从配置文件到document的转换并提取对应的root,将开始所有元素的解析

public BeanDefinition parseCustomElement(Element ele) {

        return parseCustomElement(ele, null);

    }

 

    public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {

        String namespaceUri = getNamespaceURI(ele);

        NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);

        if (handler == null) {

            error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);

            return null;

        }

        return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));

    }

 

1根据对应的bean获得命名空间,根据命名空间解析对应的处理器,然后根据用户自定义的处理器进行解析

 

获取标签的命名空间

BeanDefinitionParserDelegate类

public String getNamespaceURI(Node node) {

        return node.getNamespaceURI();

    }

String org.w3c.dom.Node.getNamespaceURI()获得node对应的uri

提取自定义标签处理器

NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);

public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver {}

/**

     * Locate the {@link NamespaceHandler} for the supplied namespace URI

     * from the configured mappings.

     * @param namespaceUri the relevant namespace URI

     * @return the located {@link NamespaceHandler}, or {@code null} if none found

     */

    @Override

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

            }

        }

    }

 

 

GetHandlerMapping()就是读取Spring.handlers配置文件并将配置文件缓存在map

/**

     * Load the specified NamespaceHandler mappings lazily.

     */

    private Map<String, Object> getHandlerMappings() {

        if (this.handlerMappings == null) {

            synchronized (this) {

                if (this.handlerMappings == null) {

                    try {

                        Properties mappings =

                                PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);

                        if (logger.isDebugEnabled()) {

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

                        }

                        Map<String, Object> handlerMappings = new ConcurrentHashMap<>(mappings.size());

                        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对属性handlerMappigLocation进行配置文件的读取,handlerMappingLocation被默认初始化为”META-INF/Spring.handlers”

public interface NamespaceHandler{}

 

    /**

     * Parses the supplied {@link Element} by delegating to the {@link BeanDefinitionParser} that is

     * registered for that {@link Element}.

     */

    @Override

    public BeanDefinition parse(Element element, ParserContext parserContext) {

        return findParserForElement(element, parserContext).parse(element, parserContext);

    }

/**

     * Locates the {@link BeanDefinitionParser} from the register implementations using

     * the local name of the supplied {@link Element}.

     */

    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;

    }

 

public abstract class AbstractBeanDefinitionParser implements BeanDefinitionParser

 

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

    }

 

 

上段代码将解析 后的AbstractBeanDefinition转化为BeanDefinitionHolder并注册,函数parseInternal完成解析的工作

@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<?> beanClass = getBeanClass(element);

        if (beanClass != null) {

            builder.getRawBeanDefinition().setBeanClass(beanClass);

        }

        else {

            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.

            builder.setScope(parserContext.getContainingBeanDefinition().getScope());

        }

        if (parserContext.isDefaultLazyInit()) {

            // Default-lazy-init applies to custom bean definitions as well.

            builder.setLazyInit(true);

        }

        doParse(element, parserContext, builder);

        return builder.getBeanDefinition();

    }

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

        doParse(element, builder);

    }

转载于:https://my.oschina.net/iioschina/blog/831131

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值