首先 简单写下 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.UserNamespaceHandlerSpring.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()); } }测试结果如下,可以看出 已经解析了自定义标签,并成功获取
最后,展示整个项目结构