本文的例子参考 spring拓展之定义自己的namespace
前言
今年的春招已经接近尾声了,因为自己没有实际的项目经验,所以找实习的情况很不理想,心里当然是很不甘心的,所以就开始盘算着要动手做出点实际的东西出来,这样今年的秋招才会有底气。先想到的就是自己开发出一个类似于 dubbo 的 rpc 框架,能够实现基本的功能就好。
为了实现这个小目标,最开始当然是先看看 dubbo 的源码来了解下它的实现原理,因为 dubbo 是依赖于 spring 的 ioc 功能来实现服务的发布和调用的,所以最开始就得先解决 dubbo 自定义标签的解析问题,本文就是关于一个最简单的自定义标签解析的实现。
实现自定义标签的解析
为了实现自定义标签的解析,我们需要定义:
xsd 文件:这个文件用于对自定标签的命名空间规则进行约束。
spring.handlers 文件:用于指定自定义标签的命名空间的处理器。
spring.schemas 文件:指定相应命名空间的 xsd 约束文件的位置。
这三个文件需要放在 classpath 根目录的 META-INF 文件夹目录之下,在定义好这三个文件后,就可以测试自定义的标签的解析了。这么说比较抽象,还是举个栗子进行说明。
定义一个 xsd 文件
定义一个 xsd 文件来对自定义命名空间的标签进行约束,因为 xsd 文件的编写规则我们不是很清楚,所以要想实现更加复杂的约束,就需要深入的去学习 xml 和 xsd 规则,这里给个学习地址。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| <?xml version="1.0" encoding="UTF-8" standalone="no"?> <xsd:schema xmlns="https://www.aprilyolies.top/schema/beehive" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="https://www.aprilyolies.top/schema/beehive">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/> <xsd:import namespace="http://www.springframework.org/schema/beans"/> <xsd:import namespace="http://www.springframework.org/schema/tool"/>
<xsd:annotation> <xsd:documentation><![CDATA[ Namespace support for the beehive test. ]]></xsd:documentation> </xsd:annotation>
<xsd:complexType name="mybeanType"> <xsd:attribute name="id" type="xsd:ID"> <xsd:annotation> <xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation> </xsd:annotation> </xsd:attribute> <xsd:attribute name="name" type="xsd:string" use="required"> <xsd:annotation> <xsd:documentation><![CDATA[ The mybean name. ]]></xsd:documentation> </xsd:annotation> </xsd:attribute> <xsd:attribute name="class" type="xsd:string" use="required"> <xsd:annotation> <xsd:documentation><![CDATA[ The version. ]]></xsd:documentation> </xsd:annotation> </xsd:attribute> </xsd:complexType>
<xsd:element name="mybean" type="mybeanType"> <xsd:annotation> <xsd:documentation><![CDATA[ The mybean config ]]></xsd:documentation> </xsd:annotation> </xsd:element> </xsd:schema>
|
spring.handlers 文件
spring.handlers 文件用于指定自定义命名空间的处理器类。
spring.schemas 文件
spring.schemas 文件用于指定相应命名空间约束文件的位置。
上述的三个文件的存放位置十分讲究,请参看下图:
测试自定义命名空间
编写 spring 的配置文件
这是启动 spring ioc 容器的配置文件,熟悉 spring 使用的小伙伴都不会陌生。注意这里的 beehive 就是我们自定义的命名空间,而 mybean 就是我们自定义的标签。
1 2 3 4 5 6 7 8 9 10
| <?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:beehive="https://www.aprilyolies.top/schema/beehive" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd https://www.aprilyolies.top/schema/beehive https://www.aprilyolies.top/schema/beehive.xsd">
<beehive:mybean class="com.aprilyolies.beehive.People" id="people" name="eva"/>
</beans>
|
自定义命名空间的处理器
创建一个用于解析自定义命名空间的类,这个类继承了 NamespaceHandlerSupport 类,我们只需要实现 init 方法的逻辑,来向 spring 容器注册不同标签的解析器,因为我们在 xsd 文件中,只是定义了一个 mybean 标签,所以这里只需要注册一个解析器就行了。
1 2 3 4 5 6 7 8 9 10 11 12 13
| import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
public class BeehiveNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { registerBeanDefinitionParser("mybean", new MybeanParser()); } }
|
编写标签解析器
这个解析器就是上文中提到的 mybean 标签解析器,用于将 mybean 标签解析为可以由 spring 容器管理的 bean。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
public class MybeanParser implements BeanDefinitionParser { @Override public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition mbd = new RootBeanDefinition(); mbd.setBeanClassName(element.getAttribute("class")); String beanName = element.getAttribute("id"); MutablePropertyValues mutablePropertyValues = new MutablePropertyValues(); mutablePropertyValues.addPropertyValue("name", element.getAttribute("name")); mbd.setPropertyValues(mutablePropertyValues); parserContext.getRegistry().registerBeanDefinition(beanName, mbd);
return mbd; } }
|
pojo 类
没啥好解释,用于功能测试,省略了 getter 和 setter 方法。
1 2 3 4 5 6 7 8 9 10
|
public class People { private String id; private String name; private Integer age; }
|
App 类
执行这个 App 类的 main 方法,如果能正常输出 People 类的 name 属性,则表示自定义的命名空间及标签解析成功了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
public class App { public static void main(String[] args) { ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"beehive.xml"}, false);
ac.refresh();
People bean = (People) ac.getBean("people", People.class);
System.out.println(bean.getName()); } }
|
总结
本文中举的例子可以说是非常简单的,所以涉及的标签解析过程并不复杂,但是如果是用于生产环境的话,那么标签的定义就会比较复杂,相应的 xsd 文件内容也会比较多。我自己对于 xsd 的编写规则也是一片空白,有时间还是要了解一下相关的知识,毕竟我自己考虑的一个类似于 dubbo 的 rpc 框架也是需要依赖于 spring 的 ioc 容器的,如果这个 xsd 文件不会写,那就没办法开始了对吧。