Spring源码阅读之编写自定义标签

基于昨天的那篇文章,我们今天来聊一个比较简单轻松点的话题,今天我们来实现一个自定义的标签。

(本文来自公众号:z小赵)
先明确下整个项目的结构,网上有很多关于自定义标签的实现方式,但是教程包结构不清晰,导致测试无法正常进行,博主自己也栽了一个坑,为了让朋友们可以快速验证结果,我们首先来介绍一下包结构。

第一个工程包结构,该工程的作用是为了实现一个自定义标签。

第二个工程是为了验证自定义标签是否能够正常工作。

这里说一下为什么创建了两个工程,博主就是在这里遇到了一个坑,最开始博主在一个工程下实现了标签并且去做验证,遇到了一个比较怪异的报错,如下,大概意思就是说 'mytag:annotation' 找不到,苦思冥想命名定义了为什么会找不到呢?朋友们混个眼熟,后面会讲为啥。

Caused by: org.xml.sax.SAXParseException; lineNumber: 10; columnNumber: 42; cvc-complex-type.2.4.c: 通配符的匹配很全面, 但无法找到元素 'mytag:annotation' 的声明。at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203)at

  1. 清楚了包结构,我们先来介绍第一个工程涉及文件的作用
  • MyNamespaceDefinitionParse:用于解析标签的具体实现
  • MyNamespaceHandler:命名空间处理器,用于注册标签对应的解析器
  • MyTagBean:自定义BeanClass
  • spring.handlers:指定使用的命名空间处理器,即指定MyNamespaceHandler
  • spring.schemas:用于指定.xsd文件位置的
  • resource-1.0.xsd:用于定义标签,也可理解成规范标签编写规则的
  1. 我们先来介绍下resource-1.0.xsd文件内容。
<?xml version="1.0" encoding="UTF-8"?>

  1. spring.schemas文件内容如下,用于指定resource-1.0.xsd文件的位置,左边为 key,右边为该文件在本地的位置,如果该文件在本地找不到会尝试去远程去找,即左边 key 指定的远程位置去获取。
http://www.zxz.com/resource/resource-1.0.xsd=/resource-1.0.xsd

  1. spring.handlers文件内容如下,用于指定自定义标签的解析器位置,左边为 key,右边为该文件在本地的位置。
http://www.zxz.com/resource=com.zxz.resource.MyNamespaceHandler

  1. MyTagBean.java文件,设置了 name myPackage两个属性,注意这个字段名和resource-1.0.xsd文件定义的名字实际上没有什么直接联系,只是名字相同而已。
package com.zxz.resource;/*** @author zxz*/public class MyTagBean {    private String name;    private String myPackage;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getMyPackage() {        return myPackage;    }    public void setMyPackage(String myPackage) {        this.myPackage = myPackage;    }    @Override    public String toString() {        return "MyTagBean{" + "name='" + name + ''' + ", myPackage='" + myPackage + ''' + '}';    }}

  1. MyNamespaceHandler.java文件内容如下,其继承了NamespaceHandlerSupport,实现了init方法。用于注册具体annotation 标签对应的解析器,这个和上次讲的的做法是一样的,不熟悉的朋友可以先看上一讲。
package com.zxz.resource;import org.springframework.beans.factory.xml.NamespaceHandlerSupport;/** * @author zxz */public class MyNamespaceHandler extends NamespaceHandlerSupport {    public void init() {        registerBeanDefinitionParser("annotation", new MyNamespaceDefinitionParse());    }}

  1. MyNamespaceDefinitionParse.java内容如下,其实现了BeanDefinitionParse接口,来实现parse方法。
package com.zxz.resource;import org.springframework.beans.MutablePropertyValues;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.w3c.dom.Element;/** * @author zxz */public class MyNamespaceDefinitionParse implements BeanDefinitionParser {    public BeanDefinition parse(Element element, ParserContext parserContext) {        RootBeanDefinition beanDefinition = new RootBeanDefinition();        // 设置beanClass        beanDefinition.setBeanClass(MyTagBean.class);        MutablePropertyValues mutablePropertyValues = beanDefinition.getPropertyValues();        // 添加name属性        if (element.hasAttribute("name")) {            mutablePropertyValues.addPropertyValue("name", element.getAttribute("name"));        }        // 添加package属性        if (element.hasAttribute("myPackage")) {            mutablePropertyValues.addPropertyValue("myPackage", element.getAttribute("myPackage"));        }        String id = element.getAttribute("id");        // 拿到注册表, 注册BeanDefinition        parserContext.getRegistry().registerBeanDefinition(id, beanDefinition);        return beanDefinition;    }}

至此,我们的自定义标签就制作完成了,接下来打成 jar 包,在第二个测试工程中进行测试。


  1. 第二个工程文件介绍。
  • applicationContext.xml:编写定义标签内容
  • Test.java:测试方法
  • pom.xml:引入第一个工程的 jar 包

  1. applicationContext.xml文件内容如下,在测试启动的时候会找 http://www.zxz.com/resource/resource-1.0.xsd和http://www.zxz.com/resource对应的.xsd文件和对应的处理器。回答下前面的那个报错原因,因为在 spring 启动的时候会先扫描本地所有的.handlers和.schemas文件,如果本地找不到回去远程找。但是从我们的报错可以看出,应该是没有扫描到我们自定义的两个文件,但是我们将其打成 jar 包,在另外一个工程里引用就可以扫到,所以我猜想 spring 启动只扫描在 pom 文件指定的那些包下文件。
<?xml version="1.0" encoding="UTF-8"?>

  1. Test.xml文件内容如下。
import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class Test {    public static void main(String[] args) {        ApplicationContext context = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");        System.out.println(context.getBean("myTagBean"));    }}

11. 运行测试代码,最终输出结果如下。

总结

以上即为创建一个自定义标签的流程,全部代码都经过测试并得出预期结果。

具体的运行原理我在上一篇讲解标签的源码解析讲解过了,不熟悉的朋友先看看上一篇内容。至此,我们关于标签解析成BeanDefinition对象并将其注册到BeanFactory的全部流程就讲完了,涉及到的其他细节朋友大家自行了解,或者可以和我交流。

下一篇文章我们来讲讲下一个比较重要的流程invokeBeanFactoryPostProcessors,希望大家和我继续坚持下去,搞定 Spring 最核心的灵魂。

感谢大家支持,多多转发关注不迷路~~

感谢大家支持~~

c++报错:引用了未定义标签_大牛带你解读Spring源码,编写自定义标签,您能学会吗?...相关推荐

  1. python3中input()方法报错traceback变量未定义的解决方法

    python3中input()方法报错traceback变量未定义的解决方法 参考文章: (1)python3中input()方法报错traceback变量未定义的解决方法 (2)https://ww ...

  2. java报错找不到对象,使用Spring源码报错java:找不到类 InstrumentationSavingAgent的问题...

    使用Spring源码,报错java:找不到类 InstrumentationSavingAgent 报错如下: Error:(26, 38) java: 找不到符号 符号: 类 Instrumenta ...

  3. Spring源码编译报错那些事

    Spring源码编译报错那些事(不会吧不会吧,不会真的有人刚学习源码就被劝退了吧

  4. spring 源码_spring源码系列(一)——spring循环引用

    众所周知spring在默认单例的情况下是支持循环引用的 为了节省图片大小我把那些可以动得gif图片做成了只循环一次,如果看到图片不动了请右键选择在新标签打开,那么图片就会动,手机用户则更简单,直接手指 ...

  5. 【Spring源码】4. 自己搞个标签?~自定义标签保姆级全过程(图解向,堆图预警)

    [Spring源码系列- IOC] 1 [Spring源码]0.安装Gradle环境 2 [Spring源码]1.下载与编译_pom relocation to an other version nu ...

  6. 使用base标签后图片无法加载_Spring 源码学习(二)-默认标签解析

    `Spring` 解析默认标签~ 从上一篇笔记可以看出,在容器注册 bean 信息的时候,做了很多解析操作,而 xml 文件中包含了很多标签.属性,例如 bean . import 标签, meta ...

  7. java基础巩固-宇宙第一AiYWM:为了维持生计,Spring全家桶_Part1-3(学学Spring源码呗:默认的标签和自定义标签是咋解析的)~整起

    Part3:上一次说到了Spring的DefaultBeanDefinitionDocumentReader类中的parseBeanDefinitions(Element root, BeanDefi ...

  8. 《Spring源码深度解析 郝佳 第2版》XML标签的解析

    目录 往期博客<Spring源码深度解析 郝佳 第2版>容器的基本实现与XML文件的加载 分析了xml文件的加载,接下来就是标签的解析,入口函数有两个 默认标签的解析 自定义标签的解析 一 ...

  9. url获取网站信息不包含网页源文件内的标签_前嗅ForeSpider链接抽取应用场景及链接在源码的html标签里写脚本...

    今天,小编给大家带来的教程为:前嗅ForeSpider脚本教程中,链接抽取的应用场景,以及链接在源码的html标签里写脚本的实战教程.具体内容如下: 一.应用场景 当需要手动添加链接时,可添加链接脚本 ...

最新文章

  1. 使用雪花id或uuid作为Mysql主键,被老板怼了一顿!
  2. 解决编译apache出现的问题:configure: error: APR not found . Please read the documentation
  3. python 概率分布_python实现beta分布概率密度函数的方法
  4. 文治者必有武备不然长大了挨欺负_2017届高考语文全国卷文言文专题阅读15篇(附答案)...
  5. 关于xrdp的安装设置
  6. pythonclass全局变量_Python的变量(全局变量、局部变量、类变量和实例变量)
  7. 双十一丨你负责买买买 我做你背后的那个数据人
  8. csv java 科学计数法_javaweb开发页面数字过长显示科学计数法的问题
  9. 算法——排序——冒泡排序图解动画
  10. dom4j解析xml
  11. wpa_supplicant 使用
  12. python调用打印机打印图片
  13. mysql远程主机强迫关闭了_HAProxy出现远程主机强迫关闭了一个现有的连接 的错误及解决...
  14. 【个人随笔】留下第一个脚印
  15. JavaServer Faces 2.0 can not be installed解决方案
  16. 【HTML第二个综合案例】----相亲App注册页面
  17. 萌新问题合集:2.win10关于ftp保存了密码怎么取消?
  18. 每个机器学习工程师都应该知道的机器学习算法
  19. MySQL的COUNT语句暗藏玄机
  20. 运营必备 - 400 电话

热门文章

  1. POJ 3168 排序+扫描
  2. zabbix企业应用:通过SNMP和iDRAC监控DELL服务器硬件
  3. 01.LoT.UI 前后台通用框架分解系列之——小图片背景全屏显示(可自动切换背景)...
  4. RADIO控件变量添加
  5. vue中watch数组或者对象
  6. 页面显示问题用layer插件
  7. tree(2018.10.26)
  8. DB pivot unpivot
  9. 文件系统的简单的操作
  10. Burst Balloons