基于Spring的可扩展Schema进行开发自定义配置标签支持
2016-05-17 17:47
567 查看
一、背景
最近和朋友一起想开发一个类似alibaba dubbo的功能的工具,其中就用到了基于Spring的可扩展Schema进行开发自定义配置标签支持,通过上网查资料自己写了一个demo.今天在这里进行和大家分享,也记录下方便以后复习备忘。
二、demo测试环境
1.JDK1.7
2.spring 4.2.5.RELEASE
3.基于Maven
4.开发工具Eclipse
三、项目介绍
1.实现步骤分析
[1].设计配置属性并开发JavaBean.
[2].编写xsd文件.
[3].编写NamespaceHandler和BeanDefinitionParser完成解析工作.
[4].编写spring.handlers和spring.schemas串联起所有部件.
[5].编写名为application.xml的spring配置文件
[6].Maven Java项目的pom.xml.
[7].编写测试类进行测试.
2.实现代码
[1].设计配置属性并开发JavaBean代码(基于BaseBean进行定义)
BaseBean.java
ApplicationBean.java
[2].编写xsd文件.
hafiz.xsd(为上一步设计好的配置项编写XSD文件,XSD是schema的定义文件,配置的输入和解析输出都是以XSD为契约,本例中XSD如下:)
注意:1.关于xsd:schema的各个属性具体含义就不作过多解释,可以参见http://www.w3school.com.cn/schema/schema_schema.asp.
2.<xsd:element name="application">对应着配置项节点的名称,因此在应用中会用application作为节点名来引用这个配置.
3.<xsd:attribute name="name" type="xsd:string" />和<xsd:attribute name="version" type="xsd:string" />以及
<xsd:attribute name="description" type="xsd:string" />对应着配置项application的三个属性名,因此在应用中可以配置name和version以及description三个属性,都是string类型。
4.完成后需把xsd存放在classpath下,一般都放在META-INF目录下(本例就放在这个目录下)
[3].编写NamespaceHandler和BeanDefinitionParser完成解析工作.
下面需要完成解析工作,会用到NamespaceHandler和BeanDefinitionParser这两个概念。具体说来NamespaceHandler会根据schema和节点名找到某个BeanDefinitionParser,然后由BeanDefinitionParser完成具体的解析工作。因此需要分别完成NamespaceHandler和BeanDefinitionParser的实现类,Spring提供了默认实现类NamespaceHandlerSupport和BeanDefinitionParser,简单的方式就是去继承这两个类。本例就是采取这种方式:
HafizNamespaceHandler.java
注:其中registerBeanDefinitionParser("application", new ApplicationBeanDefinitionParser());就是用来把节点名和解析类联系起来,在配置中引用application配置项时,就会用ApplicationBeanDefinitionParser来解析配置。
ApplicationBeanDefinitionParser.java
注:其中element.getAttribute就是用配置中取得属性值,rbd.getPropertyValues().addPropertyValue就是把属性值放到bean中。
[4].编写spring.handlers和spring.schemas串联起所有部件
上面几个步骤走下来会发现开发好的handler与xsd还没法让spring容器感知到,就这样放上去是没法把前面做的工作纳入体系中的,spring提供了spring.handlers和spring.schemas这两个配置文件来完成这项工作,这两个文件需要我们自己编写并放入META-INF文件夹中,这两个文件的地址必须是META-INF/spring.handlers和META-INF/spring.schemas,spring会默认去载入它们,本例中spring.handlers如下所示:
http\://www.hafiz.com/schema/hafiz=com.hafiz.zhang.tag.handlers.HafizNamespaceHandler
以上表示当使用到名为"http://www.hafiz.com/schema/hafiz"的schema引用时,会通过com.hafiz.zhang.tag.handlers.HafizNamespaceHandler来完成解析.
spring.schemas如下所示:
http\://www.hafiz.com/schema/hafiz.xsd=META-INF/hafiz.xsd
以上就是载入xsd文件。
注:以上两个文件中的"\"表示转义。
[5].编写名为application.xml的spring配置文件
编写application.xml文件并放在classpath下,建议这样做,但不是必须放在该位置。
其中xmlns:hafiz="http://www.hafiz.com/schema/hafiz"是用来指定自定义schema,xsi:schemaLocation用来指定xsd文件。
<hafiz:application id="test_demo" name="applicationBean" version="1.1.0" description="这是我自动拓展spring的schema的测试demo"/>是一个具体的自定义配置使用实例.
注:此处的hafiz不是不能改变的,只要使用和上面指定的“xmlns:标签名”的标签名一样就可以(代码加粗标黑处)。
[6].Maven Java项目的pom.xml.
在该文件中主要引入spring的依赖
[7].编写测试类进行测试.
在控制台会输出:
附:项目结构图
到此为止,spring的自定义标签就已经实现了,欢迎大家进行交流学习~
最近和朋友一起想开发一个类似alibaba dubbo的功能的工具,其中就用到了基于Spring的可扩展Schema进行开发自定义配置标签支持,通过上网查资料自己写了一个demo.今天在这里进行和大家分享,也记录下方便以后复习备忘。
二、demo测试环境
1.JDK1.7
2.spring 4.2.5.RELEASE
3.基于Maven
4.开发工具Eclipse
三、项目介绍
1.实现步骤分析
[1].设计配置属性并开发JavaBean.
[2].编写xsd文件.
[3].编写NamespaceHandler和BeanDefinitionParser完成解析工作.
[4].编写spring.handlers和spring.schemas串联起所有部件.
[5].编写名为application.xml的spring配置文件
[6].Maven Java项目的pom.xml.
[7].编写测试类进行测试.
2.实现代码
[1].设计配置属性并开发JavaBean代码(基于BaseBean进行定义)
BaseBean.java
package com.hafiz.zhang.tag.bean; public interface BaseBean { public abstract void init() throws Exception; public abstract void destory(); }
ApplicationBean.java
package com.hafiz.zhang.tag.bean; public class ApplicationBean implements BaseBean { private String id; private String name; private String version; private String description; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @Override public String toString() { return "ApplicationBean [id=" + id + ", name=" + name + ", version=" + version + ", description=" + description + "]"; } @Override public void init() throws Exception { System.out.println("---------ApplicationBean init---------"); } @Override public void destory() { System.out.println("---------ApplicationBean destory---------"); } }
[2].编写xsd文件.
hafiz.xsd(为上一步设计好的配置项编写XSD文件,XSD是schema的定义文件,配置的输入和解析输出都是以XSD为契约,本例中XSD如下:)
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns="http://www.hafiz.com/schema/hafiz" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans" targetNamespace="http://www.hafiz.com/schema/hafiz" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xsd:import namespace="http://www.springframework.org/schema/beans"/> <xsd:element name="application"> <xsd:complexType> <xsd:complexContent> <xsd:extension base="beans:identifiedType"> <xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="version" type="xsd:string"/> <xsd:attribute name="description" type="xsd:string"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> </xsd:element> </xsd:schema>
注意:1.关于xsd:schema的各个属性具体含义就不作过多解释,可以参见http://www.w3school.com.cn/schema/schema_schema.asp.
2.<xsd:element name="application">对应着配置项节点的名称,因此在应用中会用application作为节点名来引用这个配置.
3.<xsd:attribute name="name" type="xsd:string" />和<xsd:attribute name="version" type="xsd:string" />以及
<xsd:attribute name="description" type="xsd:string" />对应着配置项application的三个属性名,因此在应用中可以配置name和version以及description三个属性,都是string类型。
4.完成后需把xsd存放在classpath下,一般都放在META-INF目录下(本例就放在这个目录下)
[3].编写NamespaceHandler和BeanDefinitionParser完成解析工作.
下面需要完成解析工作,会用到NamespaceHandler和BeanDefinitionParser这两个概念。具体说来NamespaceHandler会根据schema和节点名找到某个BeanDefinitionParser,然后由BeanDefinitionParser完成具体的解析工作。因此需要分别完成NamespaceHandler和BeanDefinitionParser的实现类,Spring提供了默认实现类NamespaceHandlerSupport和BeanDefinitionParser,简单的方式就是去继承这两个类。本例就是采取这种方式:
HafizNamespaceHandler.java
package com.hafiz.zhang.tag.handlers; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; import com.hafiz.zhang.tag.bean.ApplicationBean; import com.hafiz.zhang.tag.parser.ApplicationBeanDefinitionParser; /** * @author hafiz.Zhang * @Date 2016年5月17日 下午12:22:57 * @Description 定义自定义的命名空间hafiz处理器 */ public class HafizNamespaceHandler extends NamespaceHandlerSupport { @Override public void init() { //在这里进行注册自定义命名空间 registerBeanDefinitionParser("application", new ApplicationBeanDefinitionParser(ApplicationBean.class)); } }
注:其中registerBeanDefinitionParser("application", new ApplicationBeanDefinitionParser());就是用来把节点名和解析类联系起来,在配置中引用application配置项时,就会用ApplicationBeanDefinitionParser来解析配置。
ApplicationBeanDefinitionParser.java
package com.hafiz.zhang.tag.parser; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.util.StringUtils; import org.w3c.dom.Element; /** * @author hafiz.Zhang * @Date 2016年5月17日 下午12:27:12 * @Description 在这里定义自定义命名空间的bean解析器 */ public class ApplicationBeanDefinitionParser implements BeanDefinitionParser { private Class<?> clazz; public ApplicationBeanDefinitionParser(Class<?> clazz) { this.clazz = clazz; } @Override public BeanDefinition parse(Element element, ParserContext parserContext) { RootBeanDefinition rbd = new RootBeanDefinition(); rbd.setBeanClass(clazz); String id = element.getAttribute("id"); String name = element.getAttribute("name"); String version = element.getAttribute("version"); String desc = element.getAttribute("description"); if(StringUtils.hasText(id)) { rbd.getPropertyValues().addPropertyValue("id", id); } if(StringUtils.hasText(name)) { parserContext.getRegistry().registerBeanDefinition(name, rbd);//这句话非常重要,意思是基于名字进行把对应的bean加载到spring容器中 rbd.getPropertyValues().addPropertyValue("name", name); } if(StringUtils.hasText(version)) { rbd.getPropertyValues().addPropertyValue("version", version); } if(StringUtils.hasText(desc)) { rbd.getPropertyValues().addPropertyValue("description", desc); } rbd.setInitMethodName("init"); rbd.setDestroyMethodName("destory"); return rbd; } }
注:其中element.getAttribute就是用配置中取得属性值,rbd.getPropertyValues().addPropertyValue就是把属性值放到bean中。
[4].编写spring.handlers和spring.schemas串联起所有部件
上面几个步骤走下来会发现开发好的handler与xsd还没法让spring容器感知到,就这样放上去是没法把前面做的工作纳入体系中的,spring提供了spring.handlers和spring.schemas这两个配置文件来完成这项工作,这两个文件需要我们自己编写并放入META-INF文件夹中,这两个文件的地址必须是META-INF/spring.handlers和META-INF/spring.schemas,spring会默认去载入它们,本例中spring.handlers如下所示:
http\://www.hafiz.com/schema/hafiz=com.hafiz.zhang.tag.handlers.HafizNamespaceHandler
以上表示当使用到名为"http://www.hafiz.com/schema/hafiz"的schema引用时,会通过com.hafiz.zhang.tag.handlers.HafizNamespaceHandler来完成解析.
spring.schemas如下所示:
http\://www.hafiz.com/schema/hafiz.xsd=META-INF/hafiz.xsd
以上就是载入xsd文件。
注:以上两个文件中的"\"表示转义。
[5].编写名为application.xml的spring配置文件
编写application.xml文件并放在classpath下,建议这样做,但不是必须放在该位置。
<?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:hafiz="http://www.hafiz.com/schema/hafiz" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.hafiz.com/schema/hafiz http://www.hafiz.com/schema/hafiz.xsd"> <hafiz:application id="test_demo" name="appliationBean" version="1.1.0" description="这是我自动拓展spring的schema的测试demo"/> </beans>
其中xmlns:hafiz="http://www.hafiz.com/schema/hafiz"是用来指定自定义schema,xsi:schemaLocation用来指定xsd文件。
<hafiz:application id="test_demo" name="applicationBean" version="1.1.0" description="这是我自动拓展spring的schema的测试demo"/>是一个具体的自定义配置使用实例.
注:此处的hafiz不是不能改变的,只要使用和上面指定的“xmlns:标签名”的标签名一样就可以(代码加粗标黑处)。
[6].Maven Java项目的pom.xml.
在该文件中主要引入spring的依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.hafiz.zhang</groupId> <artifactId>springTag</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>springTag</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.2.5.RELEASE</spring.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <!-- springframework start --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${spring.version}</version> </dependency> <!-- springframe end --> </dependencies> </project>
[7].编写测试类进行测试.
package com.hafiz.zhang.test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.hafiz.zhang.tag.bean.ApplicationBean; /** * @author hafiz.Zhang * @Date 2016年5月17日 下午2:01:37 * @Description 在此类中进行测试自定义拓展的schema */ public class ApplicationTest { private static ApplicationContext ac; public static void main( String[] args ) { ac = new ClassPathXmlApplicationContext("application.xml"); ApplicationBean bean = (ApplicationBean)ac.getBean("appliationBean"); System.out.println( "配置文件中的bean为:" ); System.out.println( "id = " + bean.getId() ); System.out.println( "name = " + bean.getName() ); System.out.println( "version = " + bean.getVersion() ); System.out.println( "description = " + bean.getDescription() ); } }
在控制台会输出:
附:项目结构图
到此为止,spring的自定义标签就已经实现了,欢迎大家进行交流学习~
相关文章推荐
- JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式)
- Spring3整合Quartz2实现定时任务及动态任务调整(添加删除暂停恢复)--推荐
- java 中锁实现
- SpringMVC 产品笔记
- spring MVC拦截器介绍
- Java中byte与16进制字符串的互相转换
- Java 设计模式——组合模式
- Java 设计模式——组合模式
- 在eclipse 上搭建ssh框架
- 关于gradle编译时'your_jdk_path\bin\java.exe'' finished with non-zero exit value 2
- myeclipse常快捷键
- springMvc 完美解决 multipart/form-data 方式提交请求 在 Filter 中 ServletRequest.getParameter方法 获取不到参数的问题
- Java中的乱码问题
- Java:Collection与Collections的区别
- Java中利用位与和位或进行函数参数优化的技巧
- 2016-5-17 java验证框架 Validator的使用
- 【Codeforces】66A - Petya and Java(模拟)
- struts2接收参数的3种方法
- Java中普通代码块,构造代码块,静态代码块区别及代码示例
- mate 8、荣耀6,手机连接eclipse、AS调试应用没有log输出