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

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

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

可以看出,简单使用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文件如下

<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.lonely</groupId>
<artifactId>customlabel</artifactId>
<version>0.0.1-SNAPSHOT</version> <properties>
<spring.version>4.3.12.RELEASE</spring.version>
<junit.version>4.12</junit.version>
</properties> <dependencies> <!-- Spring mvc web依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency> <!-- Spring jdbc 事务控制模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency> <!-- Spring aspects 有关切面模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.12.RELEASE</version>
</dependency> <!-- spring test 测试模块 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency> <!-- junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency> </dependencies> <build>
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>

(2)编写User实体类

package com.lonely.model;

public class User {

	private String id;
private String name;
private String age;
private String height; @Override
public String toString() {
return "User [name=" + name + ", age=" + age + ", height=" + height + "]";
} public String getId() {
return id;
} public void setId(String id) {
this.id = id;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getAge() {
return age;
} public void setAge(String age) {
this.age = age;
} public String getHeight() {
return height;
} public void setHeight(String height) {
this.height = height;
} public User() {
// TODO Auto-generated constructor stub
} }

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

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema 
    xmlns="http://jewel.com/schema/jewel" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://jewel.com/schema/jewel" 
    elementFormDefault="qualified"
    attributeFormDefault="unqualified">     <xsd:element name="user">
        <xsd:complexType>
            <xsd:attribute name="id" type="xsd:string"></xsd:attribute>
            <xsd:attribute name="name" type="xsd:string"></xsd:attribute>
            <xsd:attribute name="age" type="xsd:string"></xsd:attribute>
            <xsd:attribute name="height" type="xsd:string"></xsd:attribute>
        </xsd:complexType>
    </xsd:element>
    
</xsd:schema> 

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

package com.lonely.parse;

import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element; import com.lonely.model.User; public class UserParse extends AbstractSingleBeanDefinitionParser { @Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
// 从元素中获取内容
String name = element.getAttribute("name");
String age = element.getAttribute("age");
String height = element.getAttribute("height");
// 将元素放入到 builder中
if (StringUtils.hasText(name)) {
builder.addPropertyValue("name", name);
}
if (StringUtils.hasText(age)) {
builder.addPropertyValue("age", age);
}
if (StringUtils.hasText(height)) {
builder.addPropertyValue("height", height);
}
} /**
* 返回元素对应的类
*/
@Override
protected Class<?> getBeanClass(Element element) {
return User.class;
} }

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

package com.lonely.handlers;

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

import com.lonely.parse.UserParse;

public class UserNamespaceHandler extends NamespaceHandlerSupport {

	@Override
public void init() {
registerBeanDefinitionParser("user", new UserParse());
}
}

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

Spring.handler

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

Spring.schemas

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

(7)编写测试xml, spring-test.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:lonely="http://jewel.com/schema/jewel"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://jewel.com/schema/jewel http://jewel.com/schema/jewel.xsd"> <lonely:user id="user" name="dugu" age="24" height="180"></lonely:user> </beans>

(8)编写测试类 Test1

package com.lonely.test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import com.lonely.model.User; public class Test1 { public static void main(String[] args) {
ApplicationContext app = new ClassPathXmlApplicationContext("classpath:/spring-test.xml");
User user = (User) app.getBean("user");
System.out.println(user.toString());
} }

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

最后,展示整个项目结构

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. 一百一十三:CMS系统之前台注册界面

    html {% from 'common/_macros.html' import static %}<!DOCTYPE html><html lang="en" ...

  2. es6 实现单链表

    第一种/** * 链表节点类 */ class Node { constructor(ele) { this.ele = ele; this.next = null; } } /** * 链表类 */ ...

  3. React Native项目实战

    算是学习React Native的一次项目总结吧,目的还是提高自己. 包含的内容: 1>仿"美团"页面的实现; 2>封装项目中和自己常用的一些组件; 3>学习别人 ...

  4. 转:获取windows凭证管理器明文密码

    1.运行cmdkey /list查看windows保存凭证 方法1.mimikaz mimikatz vault::cred 2.利用powershell尝试获取 windows 普通凭据类型中的明文 ...

  5. CentOS 7升级OpenSSH

    目录 下载openssh安装包 安装telnet 卸载旧的openssh 安装依赖 安装openssh 重启验证 关闭telnet服务 参考 下载openssh安装包 下载地址 wget https: ...

  6. Windows To Go 制作详解

    拥有 Mac 的同学大概都会碰到一个头疼的问题,那就是使用 Windows 的使用需求.macOS 虽好,不过总是会有一些讨厌的软件没有 Mac 版本,这时就不得不在 Mac 上跑 Windows 了 ...

  7. linux中查找命令find、locate、whereis、which、type的区别

    find find是最常见和最强大的查找命令,你可以用它找到任何你想找的文件.与查询数据库(/var/lib/locatedb)文件不同,find查找的是磁盘空间. locate locate命令其实 ...

  8. 构建LNMP平台

    1方案 安装部署Nginx.MariaDB.PHP环境 安装部署Nginx.MariaDB.PHP.PHP-FPM: 启动Nginx.MariaDB.FPM服务: LNMP(Linux.Nginx.M ...

  9. mysql主主、mysql-proxy读写分离、keepalived高可用完美组合

    配置mysql主主复制 服务器A:172.16.100.9 服务器B:172.16.100.10 首先在服务器A和服务器B上各安装好单机版mysql5.7,安装好后,再继续下面的操作. 在服务器A和服 ...

  10. SecureCRT 8.3注册码下载

    SecureCRT注册码是一款针对“SecureCRT 8.3”软件而制作的激活破解工具,可以完美激活“SecureCRT”软件,从而达到免费使用的目的.而SecureCRT则是一款非常优秀的且支持s ...