【Spring学习】Spring自定义标签详细步骤

news2025/1/18 16:50:57

目录标题

  • 前言
  • 一、自定义标签步骤
    • 1、定义属性POJO
    • 2、定义XSD文件描述组件内容
    • 3、定义标签解析器
    • 4、注册标签解析器
    • 5、定义spring.handlers和spring.schemas文件
    • 6、user.xml文件配置
    • 7、测试类
  • 二、仓库位置
  • 总结

前言

Spring中除了http://www.springframework.org/schema/beans命名空间提供了默认标签,其他的命名空间的标签均为自定义标签。

为了更好的理解自定义标签在Spring中是如何加载与注册的,我们现在手动写一个自定义标签。

一、自定义标签步骤

最终目录结构:
在这里插入图片描述

1、定义属性POJO

package com.cms.customtag;

import lombok.Data;

/**
 * @author: cms
 * @date: 2023/3/2 9:46 PM
 * @description: 定义自定义标签的属性。
 */
@Data
public class User {
    private String userName;

    private String email;
}

2、定义XSD文件描述组件内容

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        targetNamespace="http://www.cms.com/schema/user"
        elementFormDefault="qualified" >

    <xsd:element name="user">
            <xsd:complexType>
                <xsd:attribute name="id" type="xsd:string"/>
                <xsd:attribute name="userName" type="xsd:string"/>
                <xsd:attribute name="email" type="xsd:string"/>
            </xsd:complexType>
    </xsd:element>

</xsd:schema>

3、定义标签解析器

package com.cms.customtag;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;

/**
 * @author: cms
 * @date: 2023/3/2 10:02 PM
 * @description: 【创建】命名空间解析器。实现 BeanDefinitionParser 接口,用来解析 XSD 文件中的定义和组件定义。
 */
public class UserBeanDefinitionParser extends AbstractSimpleBeanDefinitionParser {

    /**
     *  Element对应的类
     */
    @Override
    protected Class getBeanClass (Element element) {
        return User.class;
    }

    /**
     *  功能描述:从element中解析并提取对应的元素
     */
    @Override
    public void doParse (Element element, BeanDefinitionBuilder bean) {
        String userName = element.getAttribute("userName");
        String email    = element.getAttribute("email");

        // 将提取的数据放入到 BeanDefinitionBuilder中,待到完成所有 bean 的解析后统一注册到beanFactory 中
        if(StringUtils.hasText(userName)) {
            bean.addPropertyValue("userName", userName);
        }
        if(StringUtils.hasText(email)) {
            bean.addPropertyValue("email", email);
        }
    }
}

4、注册标签解析器

package com.cms.customtag;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;

/**
 * @author: cms
 * @date: 2023/3/2 10:13 PM
 * @description: 【注册】命名空间解析器。
 */
public class MyNamespaceHandler extends NamespaceHandlerSupport {

    public void init () {
        // 'user'作为自定义标签的名称。 格式:<user id="" />
        registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
    }
}

5、定义spring.handlers和spring.schemas文件

编写 spring.handlers 和 spring.schemas 文件,默认位置是在工程的/META-INF/文件夹下,当然,你可以通过 Spring 的扩展或者修改源码的方式改变路径。

spring.handlers:

http\://www.cms.com/schema/user=com.cms.customtag.MyNamespaceHandler

spring.schemas:

http\://www.cms.com/schema/user.xsd=com/cms/customtag/user.xsd

到这里,自定义的配置就结束了,而 Spring 加载自定义的大致流程是遇到自定义标签然后就去 spring.handlers 和 spring.schemas 中去找对应的 handler 和XSD,默认位置是/META-INF/下,进而有找到对应的 handler 以及解析元素的 Parser,从而完成了整个自定义元素的解析。也就是说自定义与 Spring 中默认的标准配置不同在于 Spring 将自定义标签解析的工作委托给了用户去实现。

6、user.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"
       xmlns:myname="http://www.cms.com/schema/user"
       xsi:schemaLocation=
               "http://www.cms.com/schema/user http://www.cms.com/schema/user.xsd
               http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--mybame是命名空间http://www.cms.com/schema/user的别名-->
    <myname:user id="userBean" userName="咖啡" email="coffee.qq.com"/>

</beans>

7、测试类

package com.cms.customtag;

import org.junit.jupiter.api.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author: cms
 * @date: 2023/3/3 3:19 PM
 * @description: xxx
 */
public class CustomTagTest {

    @Test
    public void test () {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("com/cms/customtag/user.xml");
        User user = (User) context.getBean("userBean");
        System.out.println(user.getUserName() + "," + user.getEmail());
    }
}

结果:

16:09:05.397 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@2b6856dd
16:09:05.499 [main] DEBUG org.springframework.beans.factory.xml.XmlBeanDefinitionReader - Loaded 1 bean definitions from class path resource [com/cms/customtag/user.xml]
16:09:05.512 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'userBean'
咖啡,coffee.qq.com

Process finished with exit code 0

二、仓库位置

【Gitee】spring-xml-demo模块

总结

待补充。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/387042.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pytorch-在竞赛中去摸索用法,用房价预测比赛了解数据处理流程

实战Kaggle比赛&#xff1a;房价预测 让我们动手实战一个Kaggle比赛&#xff1a;房价预测House Prices - Advanced Regression Techniques | Kaggle。本文将提供未经调优的数据的预处理、模型的设计和超参数的选择。通过动手操作、仔细观察实验现象、认真分析实验结果并不断调…

5分钟被美团面试官请出去,3年测试经验被这几个题问到心虚

5分钟前&#xff1a;“哥们我去美团面试了&#xff01;祝我好运~”5分钟后&#xff1a;“刚从美团走出来&#xff0c;被自动化测试的一些面试题难到了…”“越想越觉得可惜回想面试经过&#xff0c;在几个关键的问题没有给到面试官想要的答案。”“我不是不会&#xff0c;我都干…

工业互联网标识解析二节节点平台_能源管理工业互联网大数据平台

能源管理工业互联网大数据平台项目&#xff0c;是由吉佳通达负责建设的&#xff0c;通过建设形成能源管理的数字化产业基地&#xff0c;推动能源数字化转型升级&#xff0c;形成大数据运营平台。以能源管理与各个企业节点进行数据对接后&#xff0c;利用工业互联网唯一标识身份…

几个C语言容易忽略的问题

1 取模符号自增问题 我们不妨尝试写这样的程序 #include<stdio.h> int main(){int n,t5;printf("%d\n",7%(-3));//1printf("%d\n",(-7)%3);//-1while(--t)printf("%d\n",t);t5;while(t--)printf("%d\n",t);return 0; } 运行…

十、Spring IoC注解式开发

1 声明Bean的注解 负责声明Bean的注解&#xff0c;常见的包括四个&#xff1a; ComponentControllerServiceRepository Controller、Service、Repository这三个注解都是Component注解的别名。 也就是说&#xff1a;这四个注解的功能都一样。用哪个都可以。 只是为了增强程序…

CSS奇思妙想之-利用CSS裁剪(clip-path)完成各种图形

在日常开发当中&#xff0c;如果想要开发多边形&#xff0c;一般都需要多个盒子或者伪元素的帮助&#xff0c;有没有一直办法能只使用一个盒子实现呢&#xff1f; 有的&#xff1a;css裁剪 clip-path介绍 css裁剪&#xff08;clip-path&#xff09;这个属性平时率非常低。但是…

Submodule命令:android如何将自己项目中的某个Module作为gitlab中第三方公共库

一、创建远程公共库 1、Android Studio创建本地仓库 创建一个新的module 在新建module中添加代码(此处示例代码) 右击新建的module&#xff0c;打开新建module的命令行界面&#xff0c; 因为我们只上传这个module的代码&#xff0c;而不是整个项目的代码 命令行中输入以下命令…

2023年03月IDE流行度最新排名

点击查看最新IDE流行度最新排名&#xff08;每月更新&#xff09; 2023年03月IDE流行度最新排名 顶级IDE排名是通过分析在谷歌上搜索IDE下载页面的频率而创建的 一个IDE被搜索的次数越多&#xff0c;这个IDE就被认为越受欢迎。原始数据来自谷歌Trends 如果您相信集体智慧&am…

【vue】环境安装与实例创建

vue是一套用于构建前端界面的框架。 文章目录1. vue环境安装2. 创建项目vue init创建项目Vite创建项目vue create创建项目vue ui创建项目3. 打包项目1. vue环境安装 首先安装nodejs并配置npm国内镜像&#xff1a;https://zhuanlan.zhihu.com/p/442215189 升级或安装cnpm并查看…

Java 字符编码

编码&#xff1a;数据存储进计算机中需要转换为二进制存储&#xff0c;这个过程就是编码。 解码&#xff1a;计算机读取数据并展示在页面上&#xff0c;需要将二进制转换为人类语言的过程&#xff0c;叫做解码。 乱码&#xff1a;如果编码和解码时使用的码表不一样&#xff0c;…

ChatGPT火爆,元宇宙“熄火”?别操之过急,也别敷衍了事

近期&#xff0c;在ChatGPT火爆的同时&#xff0c;元宇宙“遇冷”的消息引起关注。据科技圈流传&#xff0c;大量元宇宙聊天群一夜之间改名为ChatGPT聊天群。ChatGPT火爆出圈导致元宇宙“熄火”&#xff0c;真的是这样吗&#xff1f;ChatGPT与元宇宙二者有怎样的底层逻辑关联&a…

Linux进程信号(产生、保存、处理)/可重入函数概念/volatile理解/SIGCHLD信号

首先区分一下Linux信号跟进程间通信中的信号量&#xff0c;它们的关系就犹如老婆跟老婆饼一样&#xff0c;没有一毛钱的关系。 信号的概念 信号的概念&#xff1a;信号是进程之间事件异步通知的一种方式&#xff0c;属于软中断。比如&#xff1a;红绿灯是一种信号&#xff0c…

机器学习:基于神经网络对用户评论情感分析预测

机器学习&#xff1a;基于神经网络对用户评论情感分析预测 作者&#xff1a;AOAIYI 作者简介&#xff1a;Python领域新星作者、多项比赛获奖者&#xff1a;AOAIYI首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可以点赞&#x1f4…

深入理解RDBMS-学习笔记

1 经典案例 1.1 红包雨 1.2 事务ACID 1.3 红包雨与ACID 1.3.1 原子性 1.3.2 一致性 1.3.3 隔离性 1.3.4 持久化 1.4 红包雨与高并发 1.5 红包雨与高可靠 2 发展历史 2.1 前DBMS时代 2.1.1 人工管理 2.1.2 文件系统 1950s&#xff0c;现代计算机的雏形基本出现。1956年IB…

怎样对一张图像进行直方图均衡化?(或者图像均衡化代码?)

怎样对一张图像进行直方图均衡化&#xff1f;&#xff08;或者图像均衡化代码&#xff1f;&#xff09; 图像增强概述 图像增强是有目的地强调图像的整体或局部特性&#xff0c;将原来不清晰的图像变得清晰或强调某些感兴趣的特征&#xff0c;扩大图像中不同物体特征之间的差…

认识异或运算

1.什么是异或运算 异或运算是位运算的一种&#xff0c;符号为&#xff1a;^ 运算规则为&#xff1a;相同为0&#xff0c;不同为1 例如 性质&#xff1a; N ^ 0 N N ^ N 0 A ^ B B ^ A (A ^ B) ^ C A ^ (B ^ C)N ^ 0 N public class XorOperation {public static void …

【算法基础】排序 插入、归并、堆、快速 升序+降序

目录 1.排序 1.1 插入排序 1.2 归并排序 1.3 推排序 1.4 快速排序 1.排序 1.1 插入排序 时间复杂度&#xff1a;O(n)~O(n*n) 空间复杂度&#xff1a;O(1) 稳定 步骤&#xff1a; 1.设第一个元素为有序列。 2.取有序列后面的一个元素。 3.将该元素插入到有序列中的正确位…

【C语言学习笔记】:一维数组指针,二维数组指针

数组&#xff08;Array&#xff09;是一系列具有相同类型的数据的集合&#xff0c;每一份数据叫做一个数组元素&#xff08;Element&#xff09;。数组中的所有元素在内存中是连续排列的&#xff0c;整个数组占用的是一块内存。以int arr[] { 99, 15, 100, 888, 252 };为例&am…

Linux | 调试器GDB的详细教程【纯命令行调试】

文章目录一、前言二、调试版本与发布版本1、见见gdb2、程序员与测试人员3、为什么Release不能调试但DeBug可以调试❓三、使用gdb调试代码1、指令集汇总2、命令演示⌨ 行号显示⌨ 断点设置⌨ 查看断点信息⌨ 删除断点⌨ 开启 / 禁用断点⌨ 运行 / 调试⌨ 逐过程和逐语句⌨ 打印 …

C/C++开发,无可避免的多线程(篇二).thread与其支持库

一、原子类型与原子操作 1.1 原子类型与操作介绍 在前一篇博文中&#xff0c;多线程交互示例代码中&#xff0c;给出了一个原子类型定义&#xff1a; // 原子数据类型 atomic_llong total {0}; 那么什么事原子数据类型呢&#xff0c;和c的基础数据类型有什么不同呢&#xff1a…