4 自定义标签的解析

felix.shao2025-02-23

4 自定义标签的解析

前述

 之前介绍到了以下部分,本小节主要介绍自定义标签相关内容。

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
    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) {
					Element ele = (Element) node;
					if (delegate.isDefaultNamespace(ele)) {
						// SPRING 对 默认标签 beans 的处理
						parseDefaultElement(ele, delegate);
					}
					else {
						// SPRING 对 自定义标签 beans 的处理
						delegate.parseCustomElement(ele);
					}
				}
			}
		}
		else {
			// SPRING 对 自定义标签 beans 的处理
			delegate.parseCustomElement(root);
		}
	}
}

4.1 自定义标签的使用

自定义标签的使用

 我们先了解下自定义标签的使用,主要是为系统提供可配置化支持,拓展 Spring 自定义标签配置大致需要以下几个步骤。

  1. 创建一个需要扩展的组件(Bean)。
  2. 定义一个 XSD 文件描述组件内容。
  3. 创建一个文件,实现 BeanDefinitionParse 接口,用来解析 XSD 文件中的定义和组件定义。
  4. 创建一个 Handle 文件,扩展自 NamespaceHandleSupport,目的是将组件注册到 Spring 容器。
  5. 编写 Spring.handlersSpring.schemas 文件。

 使用示例代码见 com.stu.spring.context.chapter04.CustomTagBeanTest

4.2 自定义标签的解析

自定义标签的解析
public class BeanDefinitionParserDelegate {
	public BeanDefinition parseCustomElement(Element ele) {
		return parseCustomElement(ele, null);
	}

	public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
		// 1 获取对应的命名空间
		String namespaceUri = getNamespaceURI(ele);
		if (namespaceUri == null) {
			return null;
		}
		// 2 根据命名空间找到对应的 NamespaceHandler
		// readerContext 初始化时其属性 namespaceHandleResolver 已经被初始化为了 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;
		}
		// 3 调用自定义的 NamespaceHandler 进行解析
		// 调用的 NamespaceHandlerSupport.parse 方法
		return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
	}
}

parseCustomElement 方法主要步骤如下。

  1. 获取对应的命名空间。
  2. 根据命名空间找到对应的 NamespaceHandler
  3. 调用自定义的 NamespaceHandler 进行解析。

4.2.1 获取标签的命名空间

 这里是直接使用的 org.w3c.dom.Node 中已经提供的方法。

public String getNamespaceURI(Node node) {
    return node.getNamespaceURI();
}

4.2.2 提取自定义标签处理器

提取自定义标签处理器
public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver {
	public NamespaceHandler resolve(String namespaceUri) {
		// 获取所有已经配置的 handler 映射
		Map<String, Object> handlerMappings = getHandlerMappings();
		// 根据命名空间找到对应的信息,Spring.handlers 配置的映射关系
		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);
				// 调用自定义的 NamespaceHandler 的初始化方法
				namespaceHandler.init();
				// 记录在缓存
				handlerMappings.put(namespaceUri, 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);
			}
		}
	}

	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 {
						// this.handlerMappingsLocation 在构造函数中已经被初始化为:META-INF/Spring.handlers
						Properties mappings =
								PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
						if (logger.isTraceEnabled()) {
							logger.trace("Loaded NamespaceHandler mappings: " + mappings);
						}
						handlerMappings = new ConcurrentHashMap<>(mappings.size());
						// 将 Properties 格式文件合并到 Map 格式的 handlerMappings 中。
						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;
	}
}

4.2.3 标签解析

标签解析
public abstract class NamespaceHandlerSupport implements NamespaceHandler {
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		// 寻找解析器并进行解析操作
		BeanDefinitionParser parser = findParserForElement(element, parserContext);
		// 会跟踪到 AbstractBeanDefinitionParser.parse 方法,我们通过 AbstractSingleBeanDefinitionParser 往父类开始找
		return (parser != null ? parser.parse(element, parserContext) : null);
	}

	private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
		// 获取元素名称,也就是<customTag:customTagBean ...> 中的 customTagBean
		String localName = parserContext.getDelegate().getLocalName(element);
		// 根据 customTagBean 找到对应的解析器,是由开发配置的解析器,可以查看 chapter04 的 CustonTagBeanBeanDefinitionParser
		BeanDefinitionParser parser = this.parsers.get(localName);
		if (parser == null) {
			parserContext.getReaderContext().fatal(
					"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
		}
		return parser;
	}
}

public abstract class AbstractBeanDefinitionParser implements BeanDefinitionParser {
	public final BeanDefinition parse(Element element, ParserContext parserContext) {
		// 核心逻辑 跟踪到了 AbstractSingleBeanDefinitionParser
		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;
				if (shouldParseNameAsAliases()) {
					String name = element.getAttribute(NAME_ATTRIBUTE);
					if (StringUtils.hasLength(name)) {
						aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
					}
				}
				// 将 AbstractBeanDefinition 转换为 BeanDefinitionHolder 并注册
				BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
				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;
	}
}

public abstract class AbstractSingleBeanDefinitionParser extends AbstractBeanDefinitionParser {
	protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
		BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
		String parentName = getParentName(element);
		if (parentName != null) {
			builder.getRawBeanDefinition().setParentName(parentName);
		}
		// 获取自定义标签中的 class,此时会调用自定义解析器如 CustonTagBeanBeanDefinitionParser 的 getBeanClass 方法
		Class<?> beanClass = getBeanClass(element);
		if (beanClass != null) {
			builder.getRawBeanDefinition().setBeanClass(beanClass);
		}
		else {
			// 若子类没有重写 getBeanClass 方法则尝试检查子类是否重写 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.
			// 配置延迟加载
			builder.setLazyInit(true);
		}
		// 调用子类重写的 doParse 方法进行解析,模板模式
		doParse(element, parserContext, builder);
		return builder.getBeanDefinition();
	}
}
Last Updated 2/23/2025, 10:08:46 PM