spring框架3 - 自定义标签解析

    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)) {
                        this.parseDefaultElement(ele, delegate);  // 解析默认标签
                    } else {
                        delegate.parseCustomElement(ele);  // 解析自定义标签
                    }
                }
            }
        } else {
            delegate.parseCustomElement(root);  // 解析自定义标签
        }
    }

delegate.parseCustomElement(root);  // 解析自定义标签

举例:

Step1:创建user实体:

@Data
public class User {
    private String id;
    private String name;
    private String email;
}

Step2:定义一个XSD文件描述组件内容:

<?xml version="1.0" encoding="UTF-8"?>

<schema xmlns="http://www.w3.org/2001/XMLSchema"
           targetNamespace="https://www.muse.com/schema/user"
           elementFormDefault="qualified">
    <element name="user">
        <complexType>
            <attribute name="id" type="string"/>
            <attribute name="name" type="string"/>
            <attribute name="email" type="string"/>
        </complexType>
    </element>
</schema>

Step3:创建BeanDefinitionParser接口的实现类,用来解析XSD文件中的定义和组件定义。

/**
 * 自定义标签解析器
 */
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {

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

    protected void doParse(Element element, BeanDefinitionBuilder builder) {
        String id = element.getAttribute("id");
        String name = element.getAttribute("name");
        String email = element.getAttribute("email");
        if (StringUtils.hasText(id)) builder.addPropertyValue("id", id);
        if (StringUtils.hasText(name)) builder.addPropertyValue("name", name);
        if (StringUtils.hasText(email)) builder.addPropertyValue("email", email);
    }
}

以上代码的意思:从element里面读数据,读出来之后写到builder里面。

Step4:创建NamespaceHandlerSupport实现类,目的是将组件注册到Spring容器中,用来维护注册关系

/**
 * 自定义标签注册器
 */
public class UserNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
    }
}

Step5:编写spring.handlers和spring.schemas文件,默认位置是/META-INF目录下

spring.handlers文件内容:

https\://www.muse.com/schema/user=com.muse.springdemo.custom.UserNamespaceHandler

spring.schemas内容:

https\://www.muse.com/schema/user.xsd=META-INF/user.xsd

Step6:在配置文件bean.xml中引入对应的命名空间以及XSD之后,就可以配置<myname:user …/>了

<?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:muse="https://www.muse.com/schema/user"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       https://www.muse.com/schema/user
       https://www.muse.com/schema/user.xsd" default-autowire="no">

使用自定义 标签: 

<!-- 自定义标签演示 -->
<muse:user id="customUser" name="muse" email="muse@163.com" />

代码解析:

Step3的创建BeanDefinitionParser接口的实现类:UserBeanDefinitionParser

父类:AbstractSingleBeanDefinitionParser --> 父类:AbstractBeanDefinitionParser --> 实现接口:BeanDefinitionParser --> 方法:BeanDefinition parse(Element var1, ParserContext var2);

Step4的创建NamespaceHandlerSupport实现类:UserNamespaceHandler

父类:NamespaceHandlerSupport -->    -->  实现接口:NamespaceHandler  --> 方法:void init()

    protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
        this.parsers.put(elementName, parser);
    }
private final Map<String, BeanDefinitionParser> parsers = new HashMap();

测试运行:

    @Test
    void testCustom() {
        User customUser = beanFactory.getBean("customUser", User.class);
        log.info("customUser={}", customUser);
    }

运行结果:

源码解析:

    @Nullable
    public BeanDefinition parseCustomElement(Element ele) {
        return this.parseCustomElement(ele, (BeanDefinition)null);
    }

对于自定义标签的解析操作,是在parseCustomElement方法中完成的,具体来说有如下3 个步骤:

① 获得namespaceUri,此处是通过org.w3c.dom.Node中的getNamespaceURI()方法进 行获取的;

② 获得解析该自定义标签的NamespaceHandler实现类。

③ 调用该实现类的parse(...)方法进行解析操作。

	/**
	 * 解析自定义元素(在默认命名空间之外)
	 */
	// eg1:containingBd=null
	@Nullable
	public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
		/** 1:获得命名空间 */
		String namespaceUri = getNamespaceURI(ele); // eg1:namespaceUri="https://www.muse.com/schema/user"
		if (namespaceUri == null) return null;

		/** 2:获得解析该自定义标签的NamespaceHandler实现类handler */
// this.readerContext.getNamespaceHandlerResolver() 为:DefaultNamespaceHandlerResolver
		NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
		if (handler == null) { // eg1:handler=UserNamespaceHandler@2641
			error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
			return null;
		}

		/** 3:通过handler进行解析操作 */
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); // eg1:NamespaceHandlerSupport#parse(...)
	}

	/** 获取入参节点的命名空间URI(namespace URI)*/
	@Nullable
	public String getNamespaceURI(Node node) {
		return node.getNamespaceURI(); // eg1:return "http://www.springframework.org/schema/beans"
	}

node是w3c的。

	/**
	 * 从配置的映射中找到提供的命名空间URI的NamespaceHandler
	 */
	// eg1:namespaceUri="https://www.muse.com/schema/user"
	@Override
	@Nullable
	public NamespaceHandler resolve(String namespaceUri) {
		/** 1:延迟加载指定的NamespaceHandler映射,默认加载路径:"META-INF/spring.handlers" */
		Map<String, Object> handlerMappings = getHandlerMappings();

		/** 2:通过namespaceUri,获取对应的NamespaceHandler实现类 */
		Object handlerOrClassName = handlerMappings.get(namespaceUri); // eg1: handlerOrClassName="com.muse.springdemo.custom.UserNamespaceHandler"

		/** 3-1:如果没找到,则返回null */
		if (handlerOrClassName == null) // eg1: false
			return null;

		/** 3-2:如果找到了,并且是NamespaceHandler类型,则返回 */
		else if (handlerOrClassName instanceof NamespaceHandler) // eg1: false
			return (NamespaceHandler) handlerOrClassName;

		/** 3-3:如果是字符串类型的,则转换为NamespaceHandler类型 */
		else {
			String className = (String) handlerOrClassName; // eg1:className="com.muse.springdemo.custom.UserNamespaceHandler"
			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);

				/** 3-3-1:调用init()方法执行初始化操作 */
				namespaceHandler.init(); // eg1:UserNamespaceHandler#init()

				/** 3-3-2:将namespaceHandler实例对象,维护到映射中 */
				handlerMappings.put(namespaceUri, namespaceHandler); // eg1:namespaceUri="https://www.muse.com/schema/user",namespaceHandler=UserNamespaceHandler@2641
				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);
			}
		}
	}
1:延迟加载指定的NamespaceHandler映射,默认加载路径

resolve获得解析该自定义标签的NamespaceHandler实现类:

首先,通过调用getHandlerMappings()方法,延迟加载指定的NamespaceHandler映射, 默认加载路径:"META-INF/spring.handlers"。

其次,通过namespaceUri,获取对应的NamespaceHandler实现类:

① 如果没找到,则返回null;如果找到了NamespaceHandler,则返回

② 如果是字符串类型的,则转换为NamespaceHandler类型,并且调用init()方法进行 初始化操作,然后将namespaceUri和namespaceHandler维护到handlerMappings映 射中,最后将namespaceHandler进行返

	/**
	 * 延迟加载指定的NamespaceHandler映射,默认加载路径:"META-INF/spring.handlers"
	 */
	private Map<String, Object> getHandlerMappings() {
		// eg1: handlerMappings=[
		// "http://www.springframework.org/schema/aop" -> "org.springframework.aop.config.AopNamespaceHandler",
		// "http://www.springframework.org/schema/task" -> "org.springframework.scheduling.config.TaskNamespaceHandler",
		// "http://www.springframework.org/schema/lang" -> "org.springframework.scripting.config.LangNamespaceHandler",
		// "http://www.springframework.org/schema/c" -> "org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler",
		// "https://www.muse.com/schema/user" -> "com.muse.springdemo.custom.UserNamespaceHandler",
		// "http://www.springframework.org/schema/jee" -> "org.springframework.ejb.config.JeeNamespaceHandler",
		// "http://www.springframework.org/schema/cache" -> "org.springframework.cache.config.CacheNamespaceHandler",
		// "http://www.springframework.org/schema/p" -> "org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler",
		// "http://www.springframework.org/schema/util" -> "org.springframework.beans.factory.xml.UtilNamespaceHandler",
		// "http://www.springframework.org/schema/context" -> "org.springframework.context.config.ContextNamespaceHandler",
		// "http://www.springframework.org/schema/mvc" -> "org.springframework.web.servlet.config.MvcNamespaceHandler"]
		Map<String, Object> handlerMappings = this.handlerMappings;

		/** 1:如果handlerMappings为空,则通过加载"META-INF/spring.handlers"文件来获得handlerMappings列表 */
		if (handlerMappings == null) { // eg1: false
			synchronized (this) {
				handlerMappings = this.handlerMappings;
				if (handlerMappings == null) { // double check
					try {
						// handlerMappingsLocation="META-INF/spring.handlers"
						Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
						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);
					}
				}
			}
		}

		/** 2:如果handlerMappings不为空,则直接返回即可 */
		return handlerMappings;
	}

/** 3-3-1:调用init()方法执行初始化操作 */

/**
 * 自定义标签注册器
 */
public class UserNamespaceHandler extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
    }
}
    protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
        this.parsers.put(elementName, parser);
    }

parsers是一个hashmap。

/** 3:通过handler进行解析操作 */

handler=UserNamespaceHandler@2641

/** 3:通过handler进行解析操作 */
return handler.parse(ele, 
    new ParserContext(this.readerContext, this, containingBd)); 
    // eg1:NamespaceHandlerSupport#parse(...)

NamespaceHandlerSupport#parse(...): 

在parse(...)方法中我们可以看到,首先是通过findParserForElement方法来找到 localName对应的解析器。以上面的示例为例,在bean.xml中配置的是<muse:user id="customUser" name="muse" email="muse@163.com" />

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

此时的parser是UserBeanDefinitionParser对象, 不为空,于是走parser.parse(element, parserContext)。

针对:

    <!-- 自定义标签演示 -->
    <muse:user id="customUser" name="muse" email="muse@163.com" />

先解析出一个definition,然后再注册进去。

@Nullable
public final BeanDefinition parse(Element element, ParserContext parserContext) {
	AbstractBeanDefinition definition = this.parseInternal(element, parserContext);
	if (definition != null && !parserContext.isNested()) {
		try {
			String id = this.resolveId(element, definition, parserContext);  // id为customUser
			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;   // muse
			if (this.shouldParseNameAsAliases()) {
				String name = element.getAttribute("name");  // muse
				if (StringUtils.hasLength(name)) {
					aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
				}
			}

			BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
			this.registerBeanDefinition(holder, parserContext.getRegistry());
			if (this.shouldFireEvents()) {
				BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
				this.postProcessComponentDefinition(componentDefinition);
				parserContext.registerComponent(componentDefinition);
			}
		} catch (BeanDefinitionStoreException var8) {
			BeanDefinitionStoreException ex = var8;
			String msg = ex.getMessage();
			parserContext.getReaderContext().error(msg != null ? msg : ex.toString(), element);
			return null;
		}
	}

	return definition;
}
protected void registerBeanDefinition(BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
	BeanDefinitionReaderUtils.registerBeanDefinition(definition, registry);
}

beanName的注册和alias的注册:

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
	String beanName = definitionHolder.getBeanName();
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
	String[] aliases = definitionHolder.getAliases();
	if (aliases != null) {
		String[] var4 = aliases;
		int var5 = aliases.length;
		for(int var6 = 0; var6 < var5; ++var6) {
			String alias = var4[var6];
			registry.registerAlias(beanName, alias);
		}
	}
}

 

解析definition的过程:

    protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
        String parentName = this.getParentName(element);
        if (parentName != null) {
            builder.getRawBeanDefinition().setParentName(parentName);
        }

        Class<?> beanClass = this.getBeanClass(element);
        if (beanClass != null) {
            builder.getRawBeanDefinition().setBeanClass(beanClass);
        } else {
            String beanClassName = this.getBeanClassName(element);
            if (beanClassName != null) {
                builder.getRawBeanDefinition().setBeanClassName(beanClassName);
            }
        }

        builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
        BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
        if (containingBd != null) {
            builder.setScope(containingBd.getScope());
        }

        if (parserContext.isDefaultLazyInit()) {
            builder.setLazyInit(true);
        }

        this.doParse(element, parserContext, builder);
        return builder.getBeanDefinition();
    }
    protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
        this.doParse(element, builder);
    }

至此通过代码的方式将customUser这个bean注册进去了。

1h42min: 总结。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值