Spring 系列
- IoC 容器
- AOP
- SpringMVC
- Spring 事务
- Spring 源码故事(瞎编版)
- Spring 整体脉络
- Spring 类解析
- Spring 自定义标签解析
- Spring Scan 包扫描
- Spring 注解工具类
- Spring 别名注册
- Spring 标签解析类
- Spring ApplicationListener
- Spring messageSource
- Spring 自定义属性解析器
- Spring 排序工具
- Spring-import 注解
- Spring-定时任务
- Spring StopWatch
- Spring 元数据
- Spring 条件接口
- Spring MultiValueMap
- Spring MethodOverride
- Spring BeanDefinitionReaderUtils
- Spring PropertyPlaceholderHelper
- Spring-AnnotationFormatterFactory
- Spring-Formatter
- Spring-Parser
- Spring-Printer
- Spring5 新特性
- Spring RMI
- Spring Message
- SpringBoot
- SpringBootBatch
- Spring Cloud
- SpringSecurity
MyBatis
- 基础支持层
- 核心处理层
- 类解析
Netty
- 网络 IO 技术基础
- JDK1.8 NIO 包 核心组件源码剖析
- Netty 粘拆包及解决方案
- Netty 多协议开发
- 基于 Netty 开发服务端及客户端
- Netty 主要组件的源码分析
- Netty 高级特性
- Netty 技术细节源码分析
Dubbo
- 架构设计
- SPI 机制
- 注册中心
- 远程通信
- RPC
- 集群
Tomcat
- Servlet 与 Servlet 容器
- Web 容器
Redis
Nacos
Sentinel
RocketMQ
- RocketMQ NameServer 与 Broker 的通信
- RocketMQ 生产者启动流程
- RocketMQ 消息发送流程
- RocketMQ 消息发送存储流程
- RocketMQ MappedFile 内存映射文件详解
- RocketMQ ConsumeQueue 详解
- RocketMQ CommitLog 详解
- RocketMQ IndexFile 详解
- RocketMQ 消费者启动流程
- RocketMQ 消息拉取流程
- RocketMQ Broker 处理拉取消息请求流程
- RocketMQ 消息消费流程
番外篇(JDK 1.8)
- 基础类库
- 集合
- 并发编程
学习心得
Spring 自定义标签解析
Spring 自定义标签解析
- Author: HuiFer
- 源码阅读仓库: SourceHot-Spring
- 与自定义标签解析相关的类
org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser
org.springframework.beans.factory.xml.NamespaceHandlerSupport
- 开始源码之前先搭建一个环境
环境搭建
- 创建对象
public class UserXtd {
private String userName;
private String emailAddress;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
}
- 创建 xsd 文件
<?xml version="1.0" encoding="UTF-8" ?>
<schema xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.huifer.com/schema/user"
elementFormDefault="qualified">
<element name="myUser">
<complexType>
<attribute name="id" type="string"/>
<attribute name="userName" type="string"/>
<attribute name="emailAddress" type="string"/>
</complexType>
</element>
</schema>
- 创建 namespaceHandler
public class UserNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("myUser", new UserBeanDefinitionParser());
}
}
- 创建 beanDefinitionParser
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
/**
* 标签对应class
* @param element the {@code Element} that is being parsed
* @return
*/
@Override
protected Class<?> getBeanClass(Element element) {
return UserXtd.class;
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// 获取 userName 标签属性值
String name = element.getAttribute("userName");
// 获取 emailAddress 标签属性值
String address = element.getAttribute("emailAddress");
if (StringUtils.hasText(name)) {
builder.addPropertyValue("userName", name);
}
if (StringUtils.hasText(address)) {
builder.addPropertyValue("emailAddress", address);
}
}
}
- 创建 resource/META-INF/spring.handlers
http\://www.huifer.com/schema/user=com.huifer.source.spring.parser.UserNamespaceHandler
- 创建 resource/META-INF/spring.schemas
http\://www.huifer.com/schema/user.xsd=META-INF/spring-test.xsd
- 创建测试用例 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.huifer.com/schema/user"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.huifer.com/schema/user http://www.huifer.com/schema/user.xsd
">
<myname:myUser id="testUserBean" userName="huifer" emailAddress="huifer97@163.com"/>
</beans>
- 创建 Java 运行方法
/**
* 自定义标签测试用例
*/
public class XSDDemo {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("XTD-xml.xml");
UserXtd user = (UserXtd) applicationContext.getBean("testUserBean");
System.out.println(user.getEmailAddress());
}
}
- 这里我们希望输出结果是
huifer97@163.com
,运行后结果也确实是huifer97@163.com
解析 DefaultNamespaceHandlerResolver
- 入口方法
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
// 不同标签的解析
parseDefaultElement(ele, delegate);
}
else {
// 非spring 默认标签解析
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
- 调用链路
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(org.w3c.dom.Element)
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)
/**
* Parse a custom element (outside of the default namespace).
* <p>
* 自定义标签解析
*
* @param ele the element to parse
* @param containingBd the containing bean definition (if any)
* @return the resulting bean definition
*/
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 自定义标签解析
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
// 根据命名空间获取处理类
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
// 自定义处理器
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
http://www.huifer.com/schema/user
和我们定义的 xsd 文件中的 url 相同,如何找到对应的 NamespaceHandler,在META-INF/spring.handlers
中有定义,http\://www.huifer.com/schema/user=com.huifer.source.spring.parser.UserNamespaceHandler
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
这行代码就是获取spring.handlers
中的定义处理方法
org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver.resolve
/**
* Locate the {@link NamespaceHandler} for the supplied namespace URI
* from the configured mappings.
*
* 根据 namespaceUri 获取对应的 {@link NamespaceHandler}
* @param namespaceUri the relevant namespace URI
* @return the located {@link NamespaceHandler}, or {@code null} if none found
*/
@Override
@Nullable
public NamespaceHandler resolve(String namespaceUri) {
// 获取handlerMapping
Map<String, Object> handlerMappings = getHandlerMappings();
// 从 handlerMapping 中获取类名
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
// 判断是否处理过,处理过直接返回
else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler) handlerOrClassName;
}
else {
// 没有处理,进行反射还原类
String className = (String) handlerOrClassName;
try {
// 通过反射还原类
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
// 初始化类
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
// 调用init()方法,自定义类中实现
namespaceHandler.init();
// 放入缓存
handlerMappings.put(namespaceUri, namespaceHandler);
// 返回自定义的 namespaceHandler
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
"] for namespace [" + namespaceUri + "]", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
className + "] for namespace [" + namespaceUri + "]", err);
}
}
}
org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#getHandlerMappings
跟踪这个方法
/**
* Load the specified NamespaceHandler mappings lazily.
*
* 获取handlerMappings
*/
private Map<String, Object> getHandlerMappings() {
Map<String, Object> handlerMappings = this.handlerMappings;
}
这里直接存在数据了,他是从什么时候加载的?
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinitions
这个方法在注册 bean 定义的时候调用
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); // 注册方法 // createReaderContext 初始化HandlerMapping documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; }
继续跟踪
createReaderContext
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#createReaderContext
public XmlReaderContext createReaderContext(Resource resource) { return new XmlReaderContext(resource, this.problemReporter, this.eventListener, this.sourceExtractor, this, getNamespaceHandlerResolver()); }
继续跟踪
getNamespaceHandlerResolver
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#getNamespaceHandlerResolver
public NamespaceHandlerResolver getNamespaceHandlerResolver() { if (this.namespaceHandlerResolver == null) { this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver(); } return this.namespaceHandlerResolver; }
继续跟踪
createDefaultNamespaceHandlerResolver
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#createDefaultNamespaceHandlerResolver
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() { ClassLoader cl = (getResourceLoader() != null ? getResourceLoader().getClassLoader() : getBeanClassLoader()); return new DefaultNamespaceHandlerResolver(cl); }
继续跟踪
DefaultNamespaceHandlerResolver
org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver
public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) { this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION); }
他回到了我们之前疑问的地方
handlerMappings
如何出现的断点
public DefaultNamespaceHandlerResolver(@Nullable ClassLoader classLoader) { this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION); }
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
此时还是空
走完
@Override public String toString() { return "NamespaceHandlerResolver using mappings " + getHandlerMappings(); }
/**
* Load the specified NamespaceHandler mappings lazily.
*
* 获取handlerMappings
*/
private Map<String, Object> getHandlerMappings() {
Map<String, Object> handlerMappings = this.handlerMappings;
// 缓存不存在
if (handlerMappings == null) {
synchronized (this) {
handlerMappings = this.handlerMappings;
if (handlerMappings == null) {
if (logger.isTraceEnabled()) {
logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
}
try {
// 将本地文件读出
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (logger.isTraceEnabled()) {
logger.trace("Loaded NamespaceHandler mappings: " + mappings);
}
handlerMappings = new ConcurrentHashMap<>(mappings.size());
// 转换成map结构
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);
this.handlerMappings = handlerMappings;
}
catch (IOException ex) {
throw new IllegalStateException(
"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
}
}
}
}
return handlerMappings;
}
org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#resolve
@Override
@Nullable
public NamespaceHandler resolve(String namespaceUri) {
// 获取handlerMapping
Map<String, Object> handlerMappings = getHandlerMappings();
// 从 handlerMapping 中获取类名
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
// 判断是否处理过,处理过直接返回
else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler) handlerOrClassName;
}
else {
// 没有处理,进行反射还原类
String className = (String) handlerOrClassName;
try {
// 通过反射还原类
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
// 初始化类
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
// 调用init()方法,自定义类中实现
namespaceHandler.init();
// 放入缓存
handlerMappings.put(namespaceUri, namespaceHandler);
// 返回自定义的 namespaceHandler
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
"] for namespace [" + namespaceUri + "]", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
className + "] for namespace [" + namespaceUri + "]", err);
}
}
}
执行init
方法
public class UserNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("myUser", new UserBeanDefinitionParser());
}
}
/**
* Subclasses can call this to register the supplied {@link BeanDefinitionParser} to
* handle the specified element. The element name is the local (non-namespace qualified)
* name.
*
* 将标签名称,标签解析类放入
*/
protected final void registerBeanDefinitionParser(String elementName, BeanDefinitionParser parser) {
this.parsers.put(elementName, parser);
}
方法走完,回到开始的方法
/** * Parse a custom element (outside of the default namespace). * <p> * 自定义标签解析 * * @param ele the element to parse * @param containingBd the containing bean definition (if any) * @return the resulting bean definition */ @Nullable public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) { // 自定义标签解析 String namespaceUri = getNamespaceURI(ele); if (namespaceUri == null) { return null; } // 根据命名空间获取处理类 // org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver.resolve NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele); return null; } // 自定义处理器 return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)); }
org.springframework.beans.factory.xml.NamespaceHandler#parse
org.springframework.beans.factory.xml.NamespaceHandlerSupport.parse
@Override @Nullable public BeanDefinition parse(Element element, ParserContext parserContext) { BeanDefinitionParser parser = findParserForElement(element, parserContext); return (parser != null ? parser.parse(element, parserContext) : null); }
org.springframework.beans.factory.xml.NamespaceHandlerSupport#findParserForElement
@Nullable
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
// 获取标签名称
String localName = parserContext.getDelegate().getLocalName(element);
// 在map中获取对应的标签解析类
BeanDefinitionParser parser = this.parsers.get(localName);
// 空报错
if (parser == null) {
parserContext.getReaderContext().fatal(
"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
// 不为空返回
return parser;
}
org.springframework.beans.factory.xml.BeanDefinitionParser#parse
org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parse
public final BeanDefinition parse(Element element, ParserContext parserContext) {
/**
* {@link AbstractSingleBeanDefinitionParser#parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)}
*/
AbstractBeanDefinition definition = parseInternal(element, parserContext);
}
org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#parseInternal
@Override
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
String parentName = getParentName(element);
if (parentName != null) {
builder.getRawBeanDefinition().setParentName(parentName);
}
// 调用自己实现的方法 com.huifer.source.spring.parser.UserBeanDefinitionParser.getBeanClass
Class<?> beanClass = getBeanClass(element);
if (beanClass != null) {
builder.getRawBeanDefinition().setBeanClass(beanClass);
}
else {
// getBeanClassName 同样也是可以在自定义的解析类中实现
String beanClassName = getBeanClassName(element);
if (beanClassName != null) {
builder.getRawBeanDefinition().setBeanClassName(beanClassName);
}
}
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
if (containingBd != null) {
// Inner bean definition must receive same scope as containing bean.
// 设置scope
builder.setScope(containingBd.getScope());
}
if (parserContext.isDefaultLazyInit()) {
// Default-lazy-init applies to custom bean definitions as well.
// 设置 lazy-init
builder.setLazyInit(true);
}
// 执行解析方法,在自定义解析类中存在com.huifer.source.spring.parser.UserBeanDefinitionParser.doParse
doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}
执行com.huifer.source.spring.parser.UserBeanDefinitionParser#doParse
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// 获取 userName 标签属性值
String name = element.getAttribute("userName");
// 获取 emailAddress 标签属性值
String address = element.getAttribute("emailAddress");
if (StringUtils.hasText(name)) {
builder.addPropertyValue("userName", name);
}
if (StringUtils.hasText(address)) {
builder.addPropertyValue("emailAddress", address);
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论