dubbo自定义了很多xml标签,例如<dubbo:application>,那么这些自定义标签是怎么与spring结合起来的呢?我们先看一个简单的例子。
一 编写模型类
package com.hulk.testdubbo.model; public class Hero {
private String name;
private int age; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
}
}
二 定义xsd文件
<xsd:schema
xmlns="http://hulk.com/schema"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://hulk.com/schema">
<xsd:complexType name="elementname1complexType">
<xsd:attribute name="name" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ The elementname1 name. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="age" type="xsd:int">
<xsd:annotation>
<xsd:documentation><![CDATA[ The elementname1 age. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType> <xsd:element name="elementname1" type="elementname1complexType">
<xsd:annotation>
<xsd:documentation><![CDATA[ elementname1的文档 ]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:schema>
说明:
- 定义targetNamespace(目标命名空间),xmlns的值要与这个相同
- xsd:element定义的就是将来会在xml文件中用到的元素,例如<dubbo:application>中的application
- xsd:attribute定义的就是模型类中的属性,例如<dubbo:application name="xxx">中的name,并且可以指定属性类型,进而起到检测的作用(当我们定义的是int,如果在xml中的值是非int型的,直接会报错)。
三 编写spring.schemas
作用:该文件用来指定xsd文件的位置。
http\://hulk.com/schema/hero.xsd=META-INF/hero.xsd
注意:红色部分要与xsd文件中的targetNamespace相同。
四 编写BeanDefinition解析器
作用:主要用来解析自定义的xml标签。
package com.hulk.testdubbo.schema; import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element; public class HeroBeanDefinitionParser implements BeanDefinitionParser {
private final Class<?> beanClass; public HeroBeanDefinitionParser(Class<?> beanClass) {
this.beanClass = beanClass;
} public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition beanDefinition = new RootBeanDefinition();
beanDefinition.setBeanClass(beanClass);
beanDefinition.setLazyInit(false);
beanDefinition.getPropertyValues().add("name", element.getAttribute("name"));
beanDefinition.getPropertyValues().add("age", element.getAttribute("age"));
BeanDefinitionRegistry beanDefinitionRegistry = parserContext.getRegistry();
beanDefinitionRegistry.registerBeanDefinition(beanClass.getName(),beanDefinition);//注册bean到BeanDefinitionRegistry中
return beanDefinition;
}
}
五 编写命名空间处理器
作用:主要用来注册BeanDefinition解析器。
package com.hulk.testdubbo.schema; import com.hulk.testdubbo.model.Hero;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport; public class HeroNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("elementname1", new HeroBeanDefinitionParser(Hero.class));
}
}
说明:通常为每一个xsd:element都要注册一个BeanDefinitionParser。
六 编写spring.handlers文件
作用:主要用于关联命名空间处理器和xsd中的targetNamespace。
http\://hulk.com/schema=com.hulk.testdubbo.schema.HeroNamespaceHandler
说明:key是xsd文件中的targetNamespace。
七 测试 - 编写hero.xml
<?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:hero="http://hulk.com/schema"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://hulk.com/schema http://hulk.com/schema/hero.xsd">
<hero:elementname1 name="xiaona" age="18"/>
</beans>
说明:
- xmlns:hero的value是xsd文件中的targetNamespace。
- xmlns:hero可以写成xmlns:xxx,此时<hero:elementname1/>就要写成<xxx:elementname1/>
八 测试 - 编写测试主类
package com.hulk.testdubbo.test; import com.hulk.testdubbo.model.Hero;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class Main {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("hero.xml");
Hero hero = (Hero) applicationContext.getBean(Hero.class.getName());
System.out.println("name: " + hero.getName() + " age: " + hero.getAge());
}
}
如何在spring中自定义xml标签的方法就结束了。在实际中,随着注解和javaconfg的盛行,xml的方式渐渐的会淡出舞台,但是spring的启动流程还是会的。来看一下上述代码涉及到的流程。
- 使用ResourceLoader将配置文件xml装载为Resource对象;
- 使用BeanDefinitionReader解析配置信息:将每一个<bean>解析为一个BeanDefinition对象,然后存储到BeanDefinitionRegistry中
- 实际上是BeanDefinitionReader调用BeanDefinitionParser进行了解析操作,解析完成后注册到BeanDefinitionRegistry(代码看上边的HeroBeanDefinitionParser)