上一篇文章中我们介绍了loadBeanDefinitions的对beanDefinition的加载工作,本次我们将研究其更深层次,如何解析自定义标签。
解析文件的过程:
1.加载spring.handlers配置文件
2.将配置文件内容加载到map结合中
3.根据指定的key去获取对应的处理器
如果需要自定义标签的话,需要做一下的步骤
- 创建一个对应的解析处理器类
- 创建一个普通的spring.handlers配置文件,让应用程序能够完成加载工作。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 以Resource的方式获得配置文件的资源位置
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
// 以String的形式获得配置文件的位置
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
``
沿着代码的逻辑一路F7进来,进入到进行解析自定义标签的地方
```java
//类 DefaultBeanDefinitionDocumentReader
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)) { // 如果namespace不是http://www.springframework.org/schema/beans
parseDefaultElement(ele, delegate);
}
else { // 本次我们研究的类, 解析自定义的标签
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
进入到parseCustomElement 方法中去 这里就是主要的解析代码中
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 获取对应的命名空间 其实就是Spring.handlers中key 值, 比如的测试用例中此处为http://abc.com/schema/dream
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
// 根据命名空间找到对应的NamespaceHandlerspring
// 详细点就是 从获取的配置好的handler映射中,使用命名空间获取到对应的解析类,然后使用反射将类路径转换成类,然后将结果记录在缓存中
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进行解析
//获取到对应的解析器,然后去解析类的doParse方法进行解析
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
以下是自定义标签的过程
新增的文件为:
附代码:
//自定义一个标签类Dream 省略get和set方法
public class Dream {
private String dreamId;
private String dreamName;
private String howToDo;
private String deadLine;
private String id;
}
//自定义标签解析类DreamBeanDefinitionParser
package com.mashibing.testSelfTag;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
//自定义标签解析类
public class DreamBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
return Dream.class;
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
//获取到标签的属性值
String dreamId=element.getAttribute("dreamId");
String dreamName=element.getAttribute("dreamName");
String howToDo=element.getAttribute("howToDo");
String deadLine=element.getAttribute("deadLine");
if (StringUtils.hasText(dreamId)){
builder.addPropertyValue("dreamId",dreamId);
}
if (StringUtils.hasText(dreamName)){
builder.addPropertyValue("dreamName",dreamName);
}
if (StringUtils.hasText(howToDo)){
builder.addPropertyValue("howToDo",howToDo);
}
if (StringUtils.hasText(deadLine)){
builder.addPropertyValue("deadLine",deadLine);
}
//super.doParse(element, builder);
}
}
//DreamNamespaceHandler 处理类
package com.mashibing.testSelfTag;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
public class DreamNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("dream",new DreamBeanDefinitionParser());
}
}
dream.xsd文件
<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://abc.com/schema/dream"
xmlns:tns="http://abc.com/schema/dream"
elementFormDefault="qualified">
<element name="dream">
<complexType>
<attribute name="id" type="string"/>
<attribute name ="dreamId" type = "string"/>
<attribute name ="dreamName" type = "string"/>
<attribute name ="howToDo" type = "string"/>
<attribute name ="deadLine" type="string"/>
</complexType>
</element>
</schema>
//Spring.hadlers文件
http\://abc.com/schema/dream=com.mashibing.testSelfTag.DreamNamespaceHandler
//Spring.schema文件
http\://abc.com/schema/dream.xsd=META-INF/dream.xsd
最后测试类:
public class TestSelfTag {
public static void main(String[] args) {
ApplicationContext context = new MyClassPathXmlApplicationContext("selftag.xml");
User user=(User)context.getBean("testbean");
System.out.println("username:"+user.getUsername()+" "+"email:"+user.getEmail());
}
}
最后我们看下执行的结果:
每天学习一点,坚持进步,加油