Spring(四) 自定义标签解析

Posted by ZhouJ000 on September 6, 2018
最后更新于:2018-09-06

Spring(一) IOC核心类
Spring(二) Resource定位与载入
Spring(三) BeanDefinition解析与注册
Spring(四) 自定义标签解析
Spring(五) 其他初始化步骤
Spring(六) bean的加载01
Spring(七) bean的加载02
Spring(八) SpringBean的生命周期
Spring(九) IOC时序图
Spring(十) AOP 01
Spring(十一) AOP 02
Spring(十二) spring事务

回顾

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 {
					// 对自定义元素标签处理,<tx:annotation-driven/>
					delegate.parseCustomElement(ele);
				}
			}
		}
	}
	else {
		// 对自定义元素标签处理
		delegate.parseCustomElement(root);
	}
}

自定义标签解析

扩展spring自定义标签

  1. 创建一个需要扩展的组件
  2. 定义一个XSD文件描述组件内容
  3. 创建一个文件,实现BeanDefinitionParser接口,用来解析XSD文件中的定义和组件定义
  4. 创建一个Handler文件,扩展自NamespaceHandlerSupport,目的是将组件注册到Spring容器
  5. 编写Spring.handlers和Spring.schemas文件
  6. 配置文件引入对应的命名空间以及XSD后,可以使用自定义标签了

源码跟踪

1 . 获取对应的命名空间处理器,执行解析

public BeanDefinition parseCustomElement(Element ele) {
	return parseCustomElement(ele, null);
}

// containingBd为父类bean,对顶层元素的解析应设为null
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
	// 获取对应的命名空间
	String namespaceUri = getNamespaceURI(ele);
	if (namespaceUri == null) {
		return null;
	}
	// 2:根据命名空间找到对应的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;
	}
	// 3:调用自定义的NamespaceHandler进行解析
	return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

2 . 获取自定义标签处理器

public NamespaceHandler resolve(String namespaceUri) {
	// 缓存中获取所有已经配置的handler映射	:META-INF/spring.handlers
	Map<String, Object> handlerMappings = getHandlerMappings();
	// 根据命名空间找到对应信息
	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.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);
		}
	}
}

比如TxNamespaceHandler的初始化方法,用来注册多个标签解析器

public void init() {
	this.registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
	this.registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
	this.registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}

3 . 将解析工作委托给自定义解析器去解析,handler.parse在父类(NamespaceHandlerSupport)中实现

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) {
	// 获取元素名称 :annotation-driven
	String localName = parserContext.getDelegate().getLocalName(element);
	// 根据名称找到对应解析器,也就是初始化时候注册的AnnotationDrivenBeanDefinitionParser
	BeanDefinitionParser parser = this.parsers.get(localName);
	if (parser == null) {
		parserContext.getReaderContext().fatal(
				"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
	}
	return parser;
}

4 . 进入具体的解析器进行解析,本例为AnnotationDrivenBeanDefinitionParser

public BeanDefinition parse(Element element, ParserContext parserContext) {
	this.registerTransactionalEventListenerFactory(parserContext);
	String mode = element.getAttribute("mode");
	if("aspectj".equals(mode)) {
		this.registerTransactionAspect(element, parserContext);
	} else {
		AnnotationDrivenBeanDefinitionParser.AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
	}

	return null;
}

补充

对于继承AbstractSingleBeanDefinitionParser的子类,实现了doParse(Element element, BeanDefinitionBuilder builder)方法和getBeanClass方法

1 . 调用父类AbstractBeanDefinitionParser的parse方法

public final BeanDefinition parse(Element element, ParserContext parserContext) {
	// 真正的解析委托给parseInternal函数
	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;
}

2 . 调用父类AbstractSingleBeanDefinitionParser的parseInternal方法

protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
	BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
	String parentName = getParentName(element);
	if (parentName != null) {
		builder.getRawBeanDefinition().setParentName(parentName);
	}
	// 获取自定义标签的class,会调用子类实现的方法
	Class<?> beanClass = getBeanClass(element);
	if (beanClass != null) {
		builder.getRawBeanDefinition().setBeanClass(beanClass);
	}
	// 没有重写方法,尝试检查是否重写getBeanClassName方法
	else {
		String beanClassName = getBeanClassName(element);
		if (beanClassName != null) {
			builder.getRawBeanDefinition().setBeanClassName(beanClassName);
		}
	}
	builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
	BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
	if (containingBd != null) {
		// 若有父类,使用父类scope属性 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方法
	doParse(element, parserContext, builder);
	return builder.getBeanDefinition();
}