首先 简单写下 spring xml解析的过程

通过一段简单的 调用spring代码开始

  1. public static void main(String[] args) {
  2. ApplicationContext app = new ClassPathXmlApplicationContext("classpath:/applicationContext.xml");
  3. User user = (User) app.getBean("user");
  4. System.out.println(user.toString());
  5. }

可以看出,简单使用spring的时候首先是要加载 xml文件,这里就涉及到 xml的解析成Beandifinition的过程,简单说下步骤

(1)使用classloader加载器加载xml文件,转换成 Resource对象

(2)经过转码和一系列操作转成 InputSource对象

(3)经过 xml validate验证,判断头信息是 dtd 还是 xsd ,进而用不同解析器解析

(4)根据解析器解析最终都会转换成 w3c的Document对象

(5)获取Document的所有子节点,将每一个子节点都转换成Beandifinition对象

(6)在将每一个节点转换成 BeanDifition对象时设计到 是否是自定义节点还是Spring默认节点,有两种不同的解析方法

那么spring默认节点有哪些:
import、alias、bean、beans

对于自定义标签的解析过程和spring默认节点的区别是对于自定义的需要指定xsd和schema的位置,进而找到解析器和

解析类,步骤如下:

(6.1)通过getNamespaceURI(),获取标签的命名空间uri

(6.2)加载spring默认指定下的配置文件,META-INF/spring.handlers,这个文件里有namespaceuri与解析

器的对应关系,比如

(6.3)解析标签,返回标签的localName;比如有标签
<lonely:user></lonely:user>,那么先获取到user

(6.4)在解析器中的init方法中找到
指定 localName对应的解析类,比如

(6.5)调用指定localName对应的解析类的parse方法完成标签的解析即可

至此,xml的解析大致过程如上,下面开始实现 自定义标签的解析

自定义标签解析实现步骤如下:

(1)编写实体类用户xsd文件描述内容

(2)编写xsd文件描述组建内容

(3)创建一个类,实现BeanDefinitionParse接口,用于标签的解析

(4)创建一个类,继承 NamespaceHandlerSupport,用于将组件注册到spring容器中

(5)编写 Spring.handles
和 Spring.schemas文件,默认在工程的 /META-INF/文件夹下

(6)创建测试文件,进行测试

实现

(1)新建maven项目,pom文件如下

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  3. <modelVersion>4.0.0</modelVersion>
  4. <groupId>com.lonely</groupId>
  5. <artifactId>customlabel</artifactId>
  6. <version>0.0.1-SNAPSHOT</version>
  7.  
  8. <properties>
  9. <spring.version>4.3.12.RELEASE</spring.version>
  10. <junit.version>4.12</junit.version>
  11. </properties>
  12.  
  13. <dependencies>
  14.  
  15. <!-- Spring mvc web依赖 -->
  16. <dependency>
  17. <groupId>org.springframework</groupId>
  18. <artifactId>spring-webmvc</artifactId>
  19. <version>${spring.version}</version>
  20. </dependency>
  21.  
  22. <!-- Spring jdbc 事务控制模块 -->
  23. <dependency>
  24. <groupId>org.springframework</groupId>
  25. <artifactId>spring-jdbc</artifactId>
  26. <version>${spring.version}</version>
  27. </dependency>
  28.  
  29. <!-- Spring aspects 有关切面模块 -->
  30. <dependency>
  31. <groupId>org.springframework</groupId>
  32. <artifactId>spring-aspects</artifactId>
  33. <version>4.3.12.RELEASE</version>
  34. </dependency>
  35.  
  36. <!-- spring test 测试模块 -->
  37. <dependency>
  38. <groupId>org.springframework</groupId>
  39. <artifactId>spring-test</artifactId>
  40. <version>${spring.version}</version>
  41. <scope>test</scope>
  42. </dependency>
  43.  
  44. <!-- junit -->
  45. <dependency>
  46. <groupId>junit</groupId>
  47. <artifactId>junit</artifactId>
  48. <version>${junit.version}</version>
  49. <scope>test</scope>
  50. </dependency>
  51.  
  52. </dependencies>
  53.  
  54. <build>
  55. <plugins>
  56. <!-- java编译插件 -->
  57. <plugin>
  58. <groupId>org.apache.maven.plugins</groupId>
  59. <artifactId>maven-compiler-plugin</artifactId>
  60. <configuration>
  61. <source>1.8</source>
  62. <target>1.8</target>
  63. <encoding>UTF-8</encoding>
  64. </configuration>
  65. </plugin>
  66. </plugins>
  67. </build>
  68. </project>

(2)编写User实体类

  1. package com.lonely.model;
  2.  
  3. public class User {
  4.  
  5. private String id;
  6. private String name;
  7. private String age;
  8. private String height;
  9.  
  10. @Override
  11. public String toString() {
  12. return "User [name=" + name + ", age=" + age + ", height=" + height + "]";
  13. }
  14.  
  15. public String getId() {
  16. return id;
  17. }
  18.  
  19. public void setId(String id) {
  20. this.id = id;
  21. }
  22.  
  23. public String getName() {
  24. return name;
  25. }
  26.  
  27. public void setName(String name) {
  28. this.name = name;
  29. }
  30.  
  31. public String getAge() {
  32. return age;
  33. }
  34.  
  35. public void setAge(String age) {
  36. this.age = age;
  37. }
  38.  
  39. public String getHeight() {
  40. return height;
  41. }
  42.  
  43. public void setHeight(String height) {
  44. this.height = height;
  45. }
  46.  
  47. public User() {
  48. // TODO Auto-generated constructor stub
  49. }
  50.  
  51. }

(3)编写 lonely.xsd文件,放在resources目录下

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <xsd:schema 
  3.     xmlns="http://jewel.com/schema/jewel" 
  4.     xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  5.     targetNamespace="http://jewel.com/schema/jewel" 
  6.     elementFormDefault="qualified"
  7.     attributeFormDefault="unqualified">
  8.  
  9.     <xsd:element name="user">
  10.         <xsd:complexType>
  11.             <xsd:attribute name="id" type="xsd:string"></xsd:attribute>
  12.             <xsd:attribute name="name" type="xsd:string"></xsd:attribute>
  13.             <xsd:attribute name="age" type="xsd:string"></xsd:attribute>
  14.             <xsd:attribute name="height" type="xsd:string"></xsd:attribute>
  15.         </xsd:complexType>
  16.     </xsd:element>
  17.     
  18. </xsd:schema> 

(4) 编写 一个 UserParse类,用来解析标签,继承 AbstractSingleBeanDefinitionParser 类

  1. package com.lonely.parse;
  2.  
  3. import org.springframework.beans.factory.support.BeanDefinitionBuilder;
  4. import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
  5. import org.springframework.util.StringUtils;
  6. import org.w3c.dom.Element;
  7.  
  8. import com.lonely.model.User;
  9.  
  10. public class UserParse extends AbstractSingleBeanDefinitionParser {
  11.  
  12. @Override
  13. protected void doParse(Element element, BeanDefinitionBuilder builder) {
  14. // 从元素中获取内容
  15. String name = element.getAttribute("name");
  16. String age = element.getAttribute("age");
  17. String height = element.getAttribute("height");
  18. // 将元素放入到 builder中
  19. if (StringUtils.hasText(name)) {
  20. builder.addPropertyValue("name", name);
  21. }
  22. if (StringUtils.hasText(age)) {
  23. builder.addPropertyValue("age", age);
  24. }
  25. if (StringUtils.hasText(height)) {
  26. builder.addPropertyValue("height", height);
  27. }
  28. }
  29.  
  30. /**
  31. * 返回元素对应的类
  32. */
  33. @Override
  34. protected Class<?> getBeanClass(Element element) {
  35. return User.class;
  36. }
  37.  
  38. }

(5)编写一个UserNamespaceHandler类,用于组件的注册

  1. package com.lonely.handlers;
  2.  
  3. import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
  4.  
  5. import com.lonely.parse.UserParse;
  6.  
  7. public class UserNamespaceHandler extends NamespaceHandlerSupport {
  8.  
  9. @Override
  10. public void init() {
  11. registerBeanDefinitionParser("user", new UserParse());
  12. }
  13. }

(6)编写Spring.handler和Spring.schemas文件,放在 META-INF目录下

Spring.handler

  1. http\://jewel.com/schema/jewel=com.lonely.handlers.UserNamespaceHandler

Spring.schemas

  1. http\://jewel.com/schema/jewel.xsd=lonely.xsd

(7)编写测试xml, spring-test.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xmlns:lonely="http://jewel.com/schema/jewel"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
  6. http://jewel.com/schema/jewel http://jewel.com/schema/jewel.xsd">
  7.  
  8. <lonely:user id="user" name="dugu" age="24" height="180"></lonely:user>
  9.  
  10. </beans>

(8)编写测试类 Test1

  1. package com.lonely.test;
  2.  
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.support.ClassPathXmlApplicationContext;
  5.  
  6. import com.lonely.model.User;
  7.  
  8. public class Test1 {
  9.  
  10. public static void main(String[] args) {
  11. ApplicationContext app = new ClassPathXmlApplicationContext("classpath:/spring-test.xml");
  12. User user = (User) app.getBean("user");
  13. System.out.println(user.toString());
  14. }
  15.  
  16. }

测试结果如下,可以看出 已经解析了自定义标签,并成功获取

最后,展示整个项目结构

Spring自定义标签的实现的更多相关文章

  1. spring基础---->spring自定义标签(一)

    Spring具有一个基于架构的扩展机制,可以使用xml文件定义和配置bean.本博客将介绍如何编写自定义XML bean的解析器,并用实例来加以说明.其实我一直相信 等你出现的时候我就知道是你. Sp ...

  2. spring自定义标签之 自我实现

     引言: 最近心情比较难以平静,周末的两天就跑出去散心了,西湖边上走走,看日落,还是不错的.回来博客上发现,在自定义标签上,最后一步实现忘记加上了.其实,人生的路程中,我们总是实现着自我的价值,让自己 ...

  3. spring自定义标签之 规范定义XSD

    引言: spring的配置文件中,一切的标签都是spring定义好的.<bean/>等等,有了定义的规范,才能让用户填写的正常可用.想写自定义标签,但首先需要了解XML Schema De ...

  4. Spring 自定义标签配置

    前景:经常使用一些依赖于Spring的组件时,发现可以通过自定义配置Spring的标签来实现插件的注入,例如数据库源的配置,Mybatis的配置等.那么这些Spring标签是如何自定义配置的?学习Sp ...

  5. Spring自定义标签

    一.原理: 1.Spring通过XML解析程序将其解析为DOM树, 2.通过NamespaceHandler指定对应的Namespace的BeanDefinitionParser将其转换成BeanDe ...

  6. 自己构建一个Spring自定义标签以及原理讲解

    平时不论是在Spring配置文件中引入其他中间件(比如dubbo),还是使用切面时,都会用到自定义标签.那么配置文件中的自定义标签是如何发挥作用的,或者说程序是如何通过你添加的自定义标签实现相应的功能 ...

  7. spring 自定义标签的实现

    在我们进行Spring 框架开发中,估计用到最多的就是bean 标签吧,其实在Spring中像<mvc/><context/>这类标签以及在dubbo配置的标签都是属于自定义的 ...

  8. Spring自定义标签解析与实现

           在Spring Bean注册解析(一)和Spring Bean注册解析(二)中我们讲到,Spring在解析xml文件中的标签的时候会区分当前的标签是四种基本标签(import.alias ...

  9. spring自定义标签学习

    看到几篇很全的自定义标签,从定义到使用,写的很好. 这里我也是在那里学习的,对学习spring源码也很有帮助. 贴出来与大家共享. http://sammor.iteye.com/blog/11009 ...

随机推荐

  1. JS中map()与forEach()的用法

    相同点: 1.都是循环遍历数组中的每一项 2.每次执行匿名函数都支持三个参数,参数分别为item(当前每一项),index(索引值),arr(原数组) 3.匿名函数中的this都是指向window 4 ...

  2. 小D课堂 - 新版本微服务springcloud+Docker教程_4-01 常用的服务间调用方式讲解

    笔记 第四章 服务消费者ribbon和feign实战和注册中心高可用 1.常用的服务间调用方式讲解     简介:讲解常用的服务间的调用方式 RPC:             远程过程调用,像调用本地 ...

  3. generator自动生成数据表

    1.先写好自己要创建的字段等: 然后将将上面的在plsql中运行,创建数据表.

  4. 新股定价谁说了算?一文读懂中国IPO询价制度

    总体来说,在市场化条件下,确定股票首次公开发行的价格可以分为两个步骤:一是股票估值:选择一定的股票估值模型,对拟发行股票的公司进行估值,并初步确定发行价格和询价区间:二是发现股票市场价格,主要方式是I ...

  5. 视区相关单位vw, vh

    vw:相对于视窗的宽度,视窗宽度是100vw vh:相对于视窗的高度,视窗高度是100vh 参考资料:[https://www.zhangxinxu.com/wordpress/2012/09/new ...

  6. python基础知识(集合)

    集合 可变集合set()/不可变集合frozenset() {}  大写的拉丁字母 用于保存不重复元素.无序不能通过索引来获取 集合的创建 空集合 使用set()函数 变量名 = set() 集合的添 ...

  7. 请求头出现Provisional headers are shown

    provisional headers are shown 知多少:https://juejin.im/post/5c00980751882518805add83 请求头出现Provisional h ...

  8. nRF5 SDK Bootloader and DFU moudles(3)

    DFU控制点特性用于控制DFU过程的状态. 通过写入该特征来请求所有DFU程序. 标记过程结束的响应将作为通知收到. BLE传输 Transfer of an init packet DFU控制器首先 ...

  9. moment的简单使用方式

    官网地址:http://momentjs.cn/ 常见示例↓ moment().format('YYYY-MM-DD HH:mm:ss'); // ’2015-11-30 23:10:10‘ mome ...

  10. 如何禁止谷歌浏览器隐藏url的www前缀

    若要将Chrome浏览器的设置恢复为隐藏HTTP.HTTPS以及WWW前缀,则只需再次进入此页面: chrome://flags/#omnibox-ui-hide-steady-state-url-s ...