Spring中添加自定义标签
文章目录
- 前言
- 总结
- 0 项目结构
- 1. 项目准备
- 1.1 新建gradle项目
- 1.2 新建spring配置文件
- 1.3新建启动类
- 2. 开始自定义标签
- 2.1 确定需求
- 2.2 建立实体类和具体解析类
- 2.3 新建blog标签解析类
- 2.4 新建NamespaceHandler
- 2.5 添加资源文件
- 2.5.1 添加spring.handlers
- 2.5.2 添加spring.schemas文件
- 2.5.3 添加cxyxh.xsd文件
- 3.使用自定义标签
- 3.1 修改配置文件
- 3.2 执行启动类
- 4. 扩展
- 5. 错误
- 5.1 id属性是必须的
- 5.1.1 具体解析
- 5.2在源码中进行自定义标签测试时
前言
尝试在spring中自定义标签。需求:我需要在spring中添加一个自定义标签cxyxh:blog将属性读取到BeanFactory中,并能通过指定的id获取到Bean。
总结
最终成功的引入了自定的标签 cxyxh:blog。
0 项目结构
软件及版本:
idea:2020.2
gradle: 6.3
spring: 5.2.9.RELEASE
1. 项目准备
1.1 新建gradle项目
在build.gradle文件中引入,阿里云的maven仓库地址和spring-context的依赖。
添加阿里云的依赖:maven { url "https://maven.aliyun.com/repository/public" }
之后下载jar包速度会快一点
本次因为只是测试自定义标签,所以只需要引入spring-context的依赖就行。使用的版本是5.2.9的版本
spring-context依赖又依赖了,spring-bean和spring-core。所以引入spring-context,相当于三个都引入了。
plugins {id 'java'
}group 'org.example'
version '1.0-SNAPSHOT'repositories {maven { url "https://maven.aliyun.com/repository/public" }mavenCentral()
}dependencies {testCompile group: 'junit', name: 'junit', version: '4.12'// https://mvnrepository.com/artifact/org.springframework/spring-contextcompile group: 'org.springframework', name: 'spring-context', version: '5.2.9.RELEASE'
}
1.2 新建spring配置文件
resource/config/spring-config.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"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
1.3新建启动类
Main.java
package com.cxyxh.custom.tag;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class Main {public static void main(String[] args) {ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/config/spring-config.xml");Object personController = applicationContext.getBean("blog");System.out.println(personController);}
}
启动类建立完成之后可以尝试启动一下,输出为null。
2. 开始自定义标签
2.1 确定需求
需要支持 <cxyxh:blog id="blog" uri="blog.cxyxh.cn" protocol="https" port="443"/>
标签的解析。
定下namespace为“http://www.cxyxh.cn/schemas/cxyxh”
。这里可以自定义随便字符串。
2.2 建立实体类和具体解析类
Blog.java
因为需求中标签一共有4个字段,但是我们只需要三个,id只是一个标识符。新建一个Blog.java的实体类,属性有:uri,protocol,port。然后设置他的setter/getter方法以及toString()方法
package com.cxyxh.custom.tag.sleftag;public class Blog {private String uri;private String protocol;private Integer port;public String getUri() {return uri;}public void setUri(String uri) {this.uri = uri;}public String getProtocol() {return protocol;}public void setProtocol(String protocol) {this.protocol = protocol;}public Integer getPort() {return port;}public void setPort(Integer port) {this.port = port;}@Overridepublic String toString() {return "Blog{" +"uri='" + uri + '\'' +", protocol='" + protocol + '\'' +", port=" + port +'}';}
}
2.3 新建blog标签解析类
需求中的标签,只需要将值读出来,然后存入Bean中就行,不需要其他操作。
需要实现getBeanClass()
获取这个标签解析类解析的标签属于哪个类。
实现doParse()
具体实现解析标签,然后存入BeanDefinition中。
可以选择实现shouldGenerateId()
方法,用于自动生成id。
package com.cxyxh.custom.tag.sleftag;import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;public class BlogBeanDefinitonParser extends AbstractSingleBeanDefinitionParser {@Overrideprotected Class<?> getBeanClass(Element element) {return Blog.class;}@Overrideprotected void doParse(Element element, BeanDefinitionBuilder builder) {String uri = element.getAttribute("uri");String port = element.getAttribute("port");String protocol = element.getAttribute("protocol");if (StringUtils.hasText(uri)){builder.addPropertyValue("uri", uri);}if (StringUtils.hasText(port)){builder.addPropertyValue("port", Integer.valueOf(port));}if (StringUtils.hasText(protocol)){builder.addPropertyValue("protocol", protocol);}}
}
2.4 新建NamespaceHandler
NamespaceHandler接口会在解析自定义标签时使用。
需要实现init()方法,然后调用registerBeanDefinitionParse()
将 标签名 以及对应的解析类注册到NamespaceHandlerSupport中,会在后续解析自定义标签是,根据标签名获取具体的解析类来解析标签。
所以在需求中的标签是blog,此处registerBeanDefinitionParse()
方法的第一个参数就是"blog"。
package com.cxyxh.custom.tag.sleftag;import org.springframework.beans.factory.xml.NamespaceHandlerSupport;public class CxyxhNamespaceHandler extends NamespaceHandlerSupport {@Overridepublic void init() {registerBeanDefinitionParser("blog", new BlogBeanDefinitonParser());}
}
2.5 添加资源文件
2.5.1 添加spring.handlers
这是一个properties类型的文件,key是之前我们定下的namespace,但是“:”需要转义,而value值对应就是之前新建的NamespaceHandler类的全限定名。
http\://www.cxyxh.cn/schemas/cxyxh=com.cxyxh.custom.tag.sleftag.CxyxhNamespaceHandler
2.5.2 添加spring.schemas文件
这也是一个properties类型的文件:key是自己定的,会在spring的配置文件中用到,value值是xsd文件的相对地址。
http\://www.cxyxh.cn/schemas/cxyxh/cxyxh-1.0.xsd=META-INF/cxyxh.xsd
spring.handlers和spring.schemas这两个文件的文件名不区分大小写
2.5.3 添加cxyxh.xsd文件
此文件中定义的是 标签需要遵循的规范。指定了xmlns就是namespace,此处targetNamespace需要和xmlns值一样。注意在顶级标签中必须有一个id属性并且有值。id属性的值就是BeanName,用于取在容器中的Bean。
在<xsd:element name="blog">
的name中便是我们的标签<cxyxh:blog >
中的blog
在<xsd:attribute>
中定义的就是标签能使用的属性值
<?xml version="1.0" encoding="UTF-8" standalone="no"?><xsd:schema xmlns="http://www.cxyxh.cn/schemas/cxyxh"xmlns:xsd="http://www.w3.org/2001/XMLSchema"targetNamespace="http://www.cxyxh.cn/schemas/cxyxh"elementFormDefault="qualified"><xsd:element name="blog"><xsd:complexType><xsd:attribute name="id" type="xsd:string"/><xsd:attribute name="uri" type="xsd:string"/><xsd:attribute name="protocol" type="xsd:string"/><xsd:attribute name="port" type="xsd:string"/></xsd:complexType></xsd:element>
</xsd:schema>
3.使用自定义标签
3.1 修改配置文件
<?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:cxyxh="http://www.cxyxh.cn/schemas/cxyxh"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.cxyxh.cn/schemas/cxyxhhttp://www.cxyxh.cn/schemas/cxyxh/cxyxh-1.0.xsd"><cxyxh:blog id="blog" uri="blog.cxyxh.cn" protocol="https" port="443"/>
</beans>
添加了:
xmlns:cxyxh="http://www.cxyxh.cn/schemas/cxyxh"
key中的cxyxh就是标签<cxyxh:blog>
中的cxyxh, value对应的是namespace的值。
在xsi:schemaLocation 指定 schema的位置。
http://www.cxyxh.cn/schemas/cxyxh
http://www.cxyxh.cn/schemas/cxyxh/cxyxh-1.0.xsd
第一个是指定的是spring.handlers中的key值,第二个是spring.schemas中的key值
3.2 执行启动类
执行结果为:
Blog{uri='blog.cxyxh.cn', protocol='https', port=443}
4. 扩展
如果还需要添加cxyxh下的其他标签,步骤如下
- 添加标签的解析类:***BeanDefinitionParser.java
- 在CxyxhNamespaceHandler中的init方法中,添加一条registerBeanDefinitionParser(),第一个参数是你需要添加的标签名,第二个是对应的解析类。
- 在cxyxh,xsd文件中,在添加一条新的element就行。
如果需要添加其他标签,重复本文的步骤就行。
5. 错误
5.1 id属性是必须的
提示消息为:Configuration problem: Id is required for element 'blog' when used as a top-level tag
。
错误是:需要一个id的key。所以检查在是spring-config.xml的自定义的标签中是否有id的属性。
5.1.1 具体解析
在spring解析完属性之后会尝试获取id属性,如果没有则报错。
报错位置:
获取id方法:resolveId()
这段代码就是自动生成一个id,但是和我们使用id指定的不一样值为:com.springframework.sourcecode.startioc.selftag.Blog#0
parserContext.getReaderContext().generateBeanName(definition);
所以如果不是需要单独的取得话,可以重写shouldGenerateId()方法,然后返回true,他会自动生成一个id。
5.2在源码中进行自定义标签测试时
本处错误出现在,源码中编译期间。
将gradle文件夹下的docs.gradle文件的第220行代码注释掉,这里对META-INF/spring.schemas文件做了特殊处理。将这个文件里的所有的key取出来,然后做特殊替换,然后做了一个断言,必须保证替换前和替换后不相等才能继续。
def shortName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1') assert shortName != key//如果不满足这个条件则,不让过也就是,schema中的key的值和替换之后的值必须不一样。
主要目的应该是保证,源代码中只能解析spring的自己的标签。
处理方式就是:
1、将本处断言关闭,注释掉
2、将文件的文件名换成某个字母大写就行
Spring中添加自定义标签相关推荐
- Spring中bean标签的属性和值:
Spring中bean标签的属性和值: <bean name="user" class="com.pojo.User" init-method=" ...
- 【Spring全家桶系列】Spring中bean标签的配置与使用
⭐️前面的话⭐️ 本文已经收录到<Spring框架全家桶系列>专栏(该专栏计划在全部文章更新完毕后付费,反正订阅不要钱,要不来一个?),本文将介绍Spring中XML配置Bean,有关be ...
- spring中默认标签Bean标签解析一
在Spring种有两种标签,一种是默认标签,另一种是自定义标签.对两种标签的用法和解析方式存在着很大的不同. 首先分析的是默认标签的解析过程. 解析标签的入口代码 protected void par ...
- Spring中的p标签(转)good
Spring的p标签是基于XML Schema的配置方式,目的是为了简化配置方式. 在XML文件头部添加xmlns:p="http://www.springframework.org/sch ...
- java 自定义xml_6.1 如何在spring中自定义xml标签
dubbo自定义了很多xml标签,例如,那么这些自定义标签是怎么与spring结合起来的呢?我们先看一个简单的例子. 一 编写模型类 1 packagecom.hulk.testdubbo.model ...
- spring中context:property-placeholder标签详解
spring中context:property-placeholder标签的使用说明 1,有些参数在某些阶段中是常量. 在开发阶段我们连接数据库时的url,username,password等信息 分 ...
- 中input标签赋值_Java程序员:Spring MVC JSP表单标签示例
Spring MVC的表单标签为Java程序员提供了许多额外的支持.例如数据绑定,允许自动设置数据并从Java对象中检索数据. 从2.0版本开始,Spring提供了一组全面的数据绑定感知标记,用于在使 ...
- spring中<tx:annotation-driven>标签转为注解@EnableTransactionManagement
spring中涉及事务的内容使用注解开发时,需开启事务的注解驱动 <?xml version="1.0" encoding="UTF-8"?> &l ...
- Spring中部署Activiti流程定义的三种姿势
摘要:本文对工作流Activiti框架中流程定义的部署进行了详细说明介绍. 本文分享自华为云社区<项目中工作流部署详细解析!Spring中部署Activiti流程定义的三种姿势>,作者:攻 ...
最新文章
- @程序员:这些瓜没吃到,可以告别互联网了!
- [Ubuntu] SVN常用的批量操作
- 简单探索MNIST(Softmax回归和两层CNN)-Tensorflow学习
- unity热更新json_Unity3D热更新 CSHotFix入门教程之HelloWorld
- python的数据类型和变量的定义及使用
- Boost:验证atomic <>不对函数指针提供算术运算
- 多进程服务器(python 版)
- 李飞飞:一站式全链路数据管理与服务成为产业布局重点
- matlab处理足球数据,如何用MATLAB画一个足球出来?
- Linux下编译googletest
- np.expand_dims
- 阿斯克码表java_一分钟了解阿斯克码
- matlab2014a如何画电机效率云图,maxwell电机转矩扫描与使用MTPA策略绘制效率map图...
- 微信支付-----扫码支付,统一下单
- 怎么用电脑屏幕录制功能录制游戏视频
- 数据科学风云之互联网金融
- win10计算机文件夹隐藏,Win10此电脑6个文件夹隐藏方法
- Otterctf 2018 内存取证
- 小米校招 C++研发 相机部 一二面
- Win7 x64动态开启DSE