Spring源码学习-自定义标签实践及原理
2021/6/30 20:22:34
本文主要是介绍Spring源码学习-自定义标签实践及原理,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
在Spring-Framework
下新建Module
先看下工程结构
代码
Teacher
package com.fy.test.model; public class Teacher { private Student student; public Teacher(Student student) { this.student = student; } public Student getStudent() { return student; } public void setStudent(Student student) { this.student = student; } @Override public String toString() { return "Teacher{" + "Student=" + student + '}'; } }
Student
package com.fy.test.model; public class Student { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
开始自定义
1. 先定义自己的标签fy.xsd
说明:
http://fy.custom.com/schema/fy
自定义的,可以随便命名,但是要保持前后统一哦
可以参考org/springframework/beans/factory/xml/spring-beans.xsd
<?xml version="1.0" encoding="UTF-8"?> <xsd:schema xmlns="http://fy.custom.com/schema/fy" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://fy.custom.com/schema/fy" elementFormDefault="qualified" attributeFormDefault="unqualified"> <xsd:import namespace="http://www.w3.org/XML/1998/namespace"/> <!--在这里模仿spring的bean标签的定义,自己写一个--> <xsd:element name="bean"> <xsd:complexType> <xsd:complexContent> <!--声明id--> <xsd:extension base="identifiedType"> <!--声明子元素--> <xsd:group ref="beanElements"/> <!--声明其他属性--> <xsd:attributeGroup ref="beanAttributes"/> </xsd:extension> </xsd:complexContent> </xsd:complexType> </xsd:element> <xsd:attributeGroup name="beanAttributes"> <xsd:attribute name="name" type="xsd:string"> <xsd:annotation> <xsd:documentation><![CDATA[ Can be used to create one or more aliases illegal in an (XML) id. Multiple aliases can be separated by any number of spaces, commas, or semi-colons (or indeed any mixture of the three). ]]></xsd:documentation> </xsd:annotation> </xsd:attribute> <xsd:attribute name="class" type="xsd:string"> <xsd:annotation> <xsd:documentation source="java:java.lang.Class"><![CDATA[ The fully qualified name of the bean's class, except if it serves only as a parent definition for child bean definitions. ]]></xsd:documentation> </xsd:annotation> </xsd:attribute> <xsd:anyAttribute namespace="##other" processContents="lax"/> </xsd:attributeGroup> <xsd:complexType name="identifiedType" abstract="true"> <xsd:annotation> <xsd:documentation><![CDATA[ The unique identifier for a bean. The scope of the identifier is the enclosing bean factory. ]]></xsd:documentation> </xsd:annotation> <xsd:attribute name="id" type="xsd:string"> <xsd:annotation> <xsd:documentation><![CDATA[ The unique identifier for a bean. A bean id may not be used more than once within the same <beans> element. ]]></xsd:documentation> </xsd:annotation> </xsd:attribute> </xsd:complexType> <xsd:group name="beanElements"> <xsd:sequence> <xsd:choice minOccurs="0" maxOccurs="unbounded"> <xsd:element ref="property"/> <xsd:any namespace="##other" processContents="strict" minOccurs="0" maxOccurs="unbounded"/> </xsd:choice> </xsd:sequence> </xsd:group> <xsd:element name="property"> <xsd:complexType> <xsd:attribute name="name" type="xsd:string"/> <xsd:attribute name="value" type="xsd:string"/> </xsd:complexType> </xsd:element> </xsd:schema>
2. 实现自定义的解析处理类,解析自己定义的标签
自定义标签解析类,通过继承
AbstractSingleBeanDefinitionParser
的方式
package com.fy.test.handler; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.w3c.dom.Element; public class FYCustomBeanParser extends AbstractSingleBeanDefinitionParser { public static final String CLASS_ATTRIBUTE = "class"; @Override protected String getBeanClassName(Element element) { if (element.hasAttribute(CLASS_ATTRIBUTE)){ return element.getAttribute(CLASS_ATTRIBUTE); } return null; } @Override protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { // 因为我定义的标签的子元素是property,所以可以直接调用spring的方法来解析 parserContext.getDelegate().parsePropertyElements(element, builder.getBeanDefinition()); } }
自定义标签解析处理类,用来指定自定义标签的用哪个解析类来解析,通过继承
NamespaceHandlerSupport
的方式
package com.fy.test.handler; import org.springframework.beans.factory.xml.NamespaceHandlerSupport; public class FYCustomBeanHandler extends NamespaceHandlerSupport { @Override public void init() { // 指定FYCustomBeanParser来解析自定义的bean标签 registerBeanDefinitionParser("bean", new FYCustomBeanParser()); } }
3. 在META-INF
中做一些配置,让Spring在解析自定义的标签时,通过自己定义的解析类进行解析
spring.handlers
http\://fy.custom.com/schema/fy=com.fy.test.handler.FYCustomBeanHandler
spring.schemas
http\://fy.custom.com/schema/fy.xsd=config/fy.xsd
4. 使用自定义标签fy-beans.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:fy="http://fy.custom.com/schema/fy" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://fy.custom.com/schema/fy http://fy.custom.com/schema/fy.xsd"> <bean id="teacher" class="com.fy.test.model.Teacher"> <property name="student" ref="student"/> </bean> <bean id="student" class="com.fy.test.model.Student"> <property name="name" value="张三"/> <property name="age" value="18"/> </bean> <!--自定义的bean标签--> <fy:bean id="student" class="com.fy.test.model.Student"> <fy:property name="name" value="李四"/> <fy:property name="age" value="20"/> </fy:bean> </beans>
5. 测试
package com.fy.test; import com.fy.test.model.Student; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class FYCustomTest { private final static String FY_BEANS_XML = "fy-beans.xml"; @Test public void testGetBean() { ApplicationContext context = new ClassPathXmlApplicationContext(FY_BEANS_XML); Student student = context.getBean("student", Student.class); System.out.println(student); } }
6. 结果OK
说明
spring-test-fy.gradle
需要添加spring-context
的依赖
可参考
spring-test.gradle
我是在Spring源码5.2.x版本中测试的,一直报这个错,始终编译不过,一度怀疑人生。
把
gradle
下的docs.gradle
文件中第220
行的校验注释掉,就可以了
自定义标签解析的原理
重点在这个resolve(String namespaceUri)
方法里
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) { this.parsers.put(elementName, parser); }
在解析的时候
public BeanDefinition parse(Element element, ParserContext parserContext) { BeanDefinitionParser parser = findParserForElement(element, parserContext); return (parser != null ? parser.parse(element, parserContext) : null); }
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) { String localName = parserContext.getDelegate().getLocalName(element); BeanDefinitionParser parser = this.parsers.get(localName); if (parser == null) { parserContext.getReaderContext().fatal( "Cannot locate BeanDefinitionParser for element [" + localName + "]", element); } return parser; }
这篇关于Spring源码学习-自定义标签实践及原理的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-05小米13T Pro系统合集:性能与摄影的极致融合,值得你升级的系统ROM
- 2024-10-01基于Python+Vue开发的医院门诊预约挂号系统
- 2024-10-01基于Python+Vue开发的旅游景区管理系统
- 2024-10-01RestfulAPI入门指南:打造简单易懂的API接口
- 2024-10-01初学者指南:了解和使用Server Action
- 2024-10-01Server Component入门指南:搭建与配置详解
- 2024-10-01React 中使用 useRequest 实现数据请求
- 2024-10-01使用 golang 将ETH账户的资产平均分散到其他账户
- 2024-10-01JWT用户校验课程:从入门到实践
- 2024-10-01Server Component课程入门指南