spring源码深度解析(笔记三)--自定义标签的解析

来源:互联网 发布:电视怎么弄成网络电视 编辑:程序博客网 时间:2024/05/12 17:20

扩展spring自定义标签配置大致需要以下几个步骤:

创建一个需要扩展的组件.

定义一个XSD文件描述组件的内容.

创建一个文件,实现BeanDefinitionParser接口,用来解析XSD文件中的定义和组件定义.

创建一个Handler文件,扩展自NamespaceHandlerdSupport,目的是将组件注册到Spring容器.

编写Spring.handlers、Spring.schemas文件.


在spring中自定义标签非常有用,事务标签tx就是自定义标签.


自定义标签的解析:

public class BeanDefinitionParserDelegate {public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {//获取对应的命名空间String namespaceUri = getNamespaceURI(ele);//根据命名空间找到对应的NamespaceHandlerNamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);if (handler == null) {error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);return null;}//调用自定义的NamespaceHandler进行解析return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));}


//获取标签的命名空间

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

//提取自定义标签处理器

public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver {public NamespaceHandler resolve(String namespaceUri) {//获取所有已经配置的handler映射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的初始化方法namespaceHandler.init();//记录在缓存handlerMappings.put(namespaceUri, namespaceHandler);return namespaceHandler;}

private Map<String, Object> getHandlerMappings() {if (this.handlerMappings == null) {synchronized (this) {if (this.handlerMappings == null) {try {Properties mappings =PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);if (logger.isDebugEnabled()) {logger.debug("Loaded NamespaceHandler mappings: " + mappings);}Map<String, Object> handlerMappings = new ConcurrentHashMap<>(mappings.size());CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);this.handlerMappings = handlerMappings;}catch (IOException ex) {throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);}}}}return this.handlerMappings;}
getHandlerMappings的主要功能就是读取Spring.Handlers配置文件并将配置文件缓存在map中.
借助了工具类PropertiesLoaderUtils进行了对配置文件的读取.


//标签解析

handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));

public abstract class NamespaceHandlerSupport implements NamespaceHandler {public BeanDefinition parse(Element element, ParserContext parserContext) {//寻找解析器并进行解析操作return findParserForElement(element, parserContext).parse(element, parserContext);}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;}}

@Overridepublic 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;if (shouldParseNameAsAliases()) {String name = element.getAttribute(NAME_ATTRIBUTE);if (StringUtils.hasLength(name)) {aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));}}//将AbstractBeanDefinition包装成BeanDefinitionHolderBeanDefinitionHolder 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) {parserContext.getReaderContext().error(ex.getMessage(), element);return null;}}return definition;}


在parseInternal函数中,做了一系列数据准备,包括对beanClass、scope、lazyInit等属性的准备,然后调用了自定义的doParse函数..


到此为止,spring将bean从配置文件加载到内存的过程已经结束了;接下来的任务便是如何使用这些bean,即bean的加载.



0 0
原创粉丝点击