打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
编程语言Spring 源码阅读-2-自定义标签简单使用与解析

编程语言Spring 源码阅读-2-自定义标签简单使用与解析

自定义标签解析

1、自定义标签的使用

在探究自定义标签的解析过程前,温顾一下使用会更方便解析过程的理解。

定义XSD文件

<?xml version="1.0"?>
	
		
        	

XSD 如何定义可以看w3c中XML Schema中的教程

定义实体类

public class User{
	private String id;
	private String userName;
	private String email;
	// 省略 set/get 方法
}

实现BeanDefinitionParser接口

/**
 * 自定义标签的解析器
 */
public class UserBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
    @Override
    protected Class<?> getBeanClass(Element element) {
        return User.class;
    }
    /**
     * 用来解析自定义的标签
     */
    @Override
    protected void doParse(Element element, BeanDefinitionBuilder bean) {
        // 获取自定义标签属性
        String userName = element.getAttribute("userName");
        String email = element.getAttribute("email");
        bean.addPropertyValue("userName",userName);
        bean.addPropertyValue("email",email);
    }
}

扩展NamespaceHandlerSupport

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

public class CustomNamespaceHandlerSupport extends NamespaceHandlerSupport {
    @Override
    public void init() {
        registerBeanDefinitionParser("user", new UserBeanDefinitionParser());
    }
}

配置此代码后,当遇到自定义标签user:xxxx,user开头的自定义标签的元素时,就会使用UserBeanDefinitionParser解析器解析。

配置schema文件路径以及handler

默认在META-INF文件夹下配置

Spring.handlers

http://www.w3school.com.cn/schema/user=com.yxx.CustomNamespaceHandlerSupport

Spring.schemes

http://www.w3school.com.cn/schema/user.xsd=META-INF/Spring-test.xsd

配置此信息可以让Spring找到xsd文件以及自定义NamespaceHandlerSupport

2、自定义标签解析

回到在默认标签解析时候的方法

DefaultBeanDefinitionDocumentReader#parseBeanDefinitions

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   // 对beans 处理
   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) {
            // 对 bean处理
            Element ele = (Element) node;
            if (delegate.isDefaultNamespace(ele)) {
               // 处理 默认的 http //w ww.springframework org/scherna beans
               parseDefaultElement(ele, delegate);
            }
            else {
                // 处理自定义的 比如 tx下的
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}

解析自定义标签

BeanDefinitionParserDelegate#parseCustomElement

public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
   // 获取 命名空间 namespaceUri http://xxxxx.xsd
   // w3c提供的Node 提供了方法
   String namespaceUri = getNamespaceURI(ele);
   if (namespaceUri == null) {
      return null;
   }
   // 提取自定义的标签处理器
   // 通过命名空间获取对应的namespacehandler
   NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
   if (handler == null) {
      error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
      return null;
   }
   // 使用自定自定义的 namespacehandler 进行解析
   // 例如namespacehandler 可以解析全部的  myname 命名空间的 标签
   // 命名空间处理器  namespacehandler 通过 不同的标签调用不同的  AbstractSingleBeanDefitionParser
   return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

此方法中首先获取此ele的命名空间,并通过命名空间处理程序解析器(DefaultNamespaceHandlerResolver)根绝命名空间名称获取命名空间处理器(NamespaceHandler),然后通过parse方法处理自定义标签(实际上此方法执行的就是UserBeanDefinitionParser#doParse)。

DefaultNamespaceHandlerResolver#resolve

public NamespaceHandler resolve(String namespaceUri) {
   // 获取handler mapper -----> 其实就是Spring.handlers 中配置的namespace-handler
   MaphandlerMappings = getHandlerMappings();
   // 查看此namespace是否存在对应的handler
   Object handlerOrClassName = handlerMappings.get(namespaceUri);
   // 不存在
   if (handlerOrClassName == null) {
      return null;
   }
   // 如果存在缓存 直接返回
   else if (handlerOrClassName instanceof NamespaceHandler) {
      return (NamespaceHandler) handlerOrClassName;
   }
   else {
      // 存的是className
      String className = (String) handlerOrClassName;
      try {
         // 获取对应的classname 的Class对象
         Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
         // 判断此Class 是否 集成实现 NamespaceHandler
         if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
            throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
                  "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
         }
         // 实例化 namespacehandler 并类型转换
         NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
         // 初始化
         // 将AbstractSingleBeanDefitionParser实例化并 注册到BeanDefnitionParser缓存中, registerBeanDefnitionParser
         namespaceHandler.init();
         // 将namespacehandler添加到缓存
         handlerMappings.put(namespaceUri, namespaceHandler);
         return namespaceHandler;
      }
   ...
   }
}

handlerMappings此Map缓存中存放的为namespace-handler的映射,但是这个handler可能是已经实例化的NamespaceHandler,也可能是handlerClassName,如果是handlerClassName,需要先实例化再添加到缓存

NamespaceHandlerSupport#parse

public BeanDefinition parse(Element element, ParserContext parserContext) {
   // 查找 parserContext 对应的 的解析器
   BeanDefinitionParser parser = findParserForElement(element, parserContext);
   // parser不为空 就解析标签, 并将beanDefinition注册到Spring容器中
   return (parser != null ? parser.parse(element, parserContext) : null);
}

将任务分解,首先查找出该ele解析的BeanDefinitionParser,然后进行解析,最后会执行UserBeanDefinitionParser#doParse。

NamespaceHandlerSupport#findParserForElement

@Nullable
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
   // 获取中的user
   String localName = parserContext.getDelegate().getLocalName(element);
   // registerBeanDefinitionParser (”user ”, new UserBeanDefinitionParser ()) ;  这里已经将 user --解析器保存在了  map中
   // 获取user对应的解析器
   BeanDefinitionParser parser = this.parsers.get(localName);
   if (parser == null) {
      parserContext.getReaderContext().fatal(
            "Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
   }
   return parser;
}

解析完成

AbstractBeanDefinitionParser#parse

	public final BeanDefinition parse(Element element, ParserContext parserContext) {
		// 解析自定义标签除去默认属性的其他属性以及子标签
		AbstractBeanDefinition definition = parseInternal(element, parserContext);
		if (definition != null && !parserContext.isNested()) {
			try {
				String id = resolveId(element, definition, parserContext);
				if (!StringUtils.hasText(id)) {
					parserContext.getReaderContext().error(
							"Id is required for element '" + parserContext.getDelegate().getLocalName(element)
									+ "' when used as a top-level tag", element);
				}
				String[] aliases = null;
				// 解析 name 分割成别名
				if (shouldParseNameAsAliases()) {
					String name = element.getAttribute(NAME_ATTRIBUTE);
					if (StringUtils.hasLength(name)) {
						aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
					}
				}
				// 构造BeanDefinitionHolder对象
				BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
				// 注册beanDefinition
				registerBeanDefinition(holder, parserContext.getRegistry());
				if (shouldFireEvents()) {
					BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
					postProcessComponentDefinition(componentDefinition);
					parserContext.registerComponent(componentDefinition);
				}
			}
			catch (BeanDefinitionStoreException ex) {
				String msg = ex.getMessage();
				parserContext.getReaderContext().error((msg != null ? msg : ex.toString()), element);
				return null;
			}
		}
		return definition;
	}

AbstractSingleBeanDefinitionParser#parseInternal

@Override
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
   // 创建 BeanDefinition 构造器
   BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
   // getParentName 由子类去实现  获取父类名字
   String parentName = getParentName(element);
   if (parentName != null) {
      builder.getRawBeanDefinition().setParentName(parentName);
   }
   // getBeanClass 由子类重写获取当前标签对应的类类型 返回Class
   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.
      builder.setScope(containingBd.getScope());
   }
   if (parserContext.isDefaultLazyInit()) {
      // Default-lazy-init applies to custom bean definitions as well.
      builder.setLazyInit(true);
   }
   // 子类重写的 解析方法
   doParse(element, parserContext, builder);
   return builder.getBeanDefinition();
}

此方法解析parent、beanClass以及继承父类的scope和是否懒加载,并最终调用doParse方法实现自定义标签的处理,doParse此方法就为UserBeanDefinitionParser#doParse

至此自定义标签的解析完毕

经历的过程:

  1. 通过命名空间获取自定义的标签处理器

  2. 通过element获取当前标签的解析器

  3. 处理默认属性 id、name以及name分割后的alias

  4. 集成父类的scope和是否懒加载

  5. 调用自定义处理标签的UserBeanDefinitionParser#doParse方法

  6. 构造BeanDefinitionHolder对象

  7. 注册BeanDefinition

---- ** Cover 《Spring 源码深度解析》**

文章来源:https://www.cnblogs.com/aismvy/p/15561182.html

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
[转] Spring4.3.x 浅析xml配置的解析过程(6)property-placeholder和property-override的区别
Spring Security3源码分析-authentication-manager
推荐一篇关于JSTL的好文章
SpringMVC源码总结(十一)mvc:interceptors拦截器介绍
spring源码分析之——spring 事务管理实现方式 (不太清晰,不明白aop会看不懂)
springAOP入口之AopNamespaceHandler
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服