上一节的xml解析成BeanDefinition中讲到了
XmlBeanDefinitionReader 委托DefaultBeanDefinitionDocumentReader 来解析xml文件
DefaultBeanDefinitionDocumentReader 委托 NamespaceHandler 来解析Document的Element
NamespaceHandler 委托 BeanDefinitionParser 来解析Element中的tag,
那么这次我们尝试自己命名一个dubbo类似的命名空间,暂时取名
其实自定义命名空间及实现,需要做以下几步:
1:声明命名空间,创建xsd文件
2:创建spring.schames文件。指定命名空间的xsd路径,
3:自定义实现命名空间的处理器-CustomNamespaceHandler,并创建spring.handlers指定该处理器
4:自定义实现
5:配置
6:启动测试。
我们按照上面的步骤,简单的实现一下
第一步:首先创建一个简单的maven工程,spring-custom-namespace。添加基础依赖 spring-beans
第二步:在src目录中新建custom.xsd,然后模仿spring-beans.xsd文件的格式描写自己的标签
xsd主要有几个要素 1:xmlns/targetNamespace,2
自定义schema xmlns ,写一个属于自己的路径。注意xmlns 跟targetNamespace 的配置要成对出现
第三步:在resource路径下新建文件/META-INF/spring.schemas文件,指定custom.xsd 指向的配置文件
http\://com.david.study.spring/schema/custom/custom.xsd = com/david/study/spring/custom/namespace/custom.xsd
第三步:在src目录中创建一个CustomerNamespaceHandler 类
public class CustomNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("custom",new CustomBeanDefinitionParse());
}
}
这个地方主要是注册我们自己的BeanDefinitionParse,注意key custom要跟自己的命名空间一致
第四步:实现CustomBeanDefinitionParse,解析自己定义的xsd文件的标签
public class CustomBeanDefinitionParse extends AbstractSingleBeanDefinitionParser {
static final String CUSTOM_ID_ATTRIBUTE = "id";
static final String CUSTOM_NAME_ATTRIBUTE = "name";
static final String CUSTOM_AGE_ATTRIBUTE = "age";
static final String CUSTOM_SEX_ATTRIBUTE = "sex";
static final String CUSTOM_CLASS_ATTRIBUTE = "class";
@Override
protected String getBeanClassName(Element element) {
return element.getAttribute(CUSTOM_CLASS_ATTRIBUTE);
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
builder.addPropertyValue(CUSTOM_ID_ATTRIBUTE,element.getAttribute(CUSTOM_ID_ATTRIBUTE));
builder.addPropertyValue(CUSTOM_AGE_ATTRIBUTE,element.getAttribute(CUSTOM_AGE_ATTRIBUTE));
builder.addPropertyValue(CUSTOM_NAME_ATTRIBUTE,element.getAttribute(CUSTOM_NAME_ATTRIBUTE));
builder.addPropertyValue(CUSTOM_SEX_ATTRIBUTE,element.getAttribute(CUSTOM_SEX_ATTRIBUTE));
}
}
第五步:在resource/META-INF下创建文件spring.handlers
标注当前的命名空间的解析器:
http\://com.david.study.spring/schema/custom =com.david.study.spring.custom.namespace.CustomNamespaceHandler
第六步:在resource/META-INF下创建beans.xml文件
第七步:写一个Demo
public class SpringXmlNamespaceDemo {
public static void main(String[] args) {
DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
xmlBeanDefinitionReader.loadBeanDefinitions("/META-INF/beans.xml");
Map map = defaultListableBeanFactory.getBeansOfType(Custom.class);
map.entrySet().forEach(entry->{
System.out.printf("name: %s \n",entry.getKey());
System.out.printf("value: %s \n",entry.getValue());
});
}
}
启动测试:
输出的就是当前我们配置的属性.
上面就是自定义命名空间的简单实现,dubbo的早起功能就是基于次原理实现的。不过比这个例子复杂太多