Spring IoC的细节–DefaultNamespaceHandlerResolver.resolve(String namespaceUri)

  • Post author:
  • Post category:其他


BeanDefinitionParserDelegate:

	@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);  //代码1 
		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)); //代码2
	}

代码1,执行获取当前命名空间的命名空间处理器

DefaultNamespaceHandlerResolver:

public NamespaceHandler resolve(String namespaceUri) {
		//获取所有的handlerMapping,即命名空间与对应NamespaceHandler实现的映射
		Map<String, Object> handlerMappings = getHandlerMappings();  //代码2
		// 我们案例中则为ContextNamespaceHandler
		// http://www.springframework.org/schema/context -> org.springframework.context.config.ContextNamespaceHandler
		Object handlerOrClassName = handlerMappings.get(namespaceUri);
		if (handlerOrClassName == null) {
			return null;
		}
		else if (handlerOrClassName instanceof NamespaceHandler) {
			//假如获取到的对象为NamespaceHandler,则直接返回,不过一般获取的为类路径信息,即下面的分支
			return (NamespaceHandler) handlerOrClassName;
		}
		else {
			//获取到NamespaceHandler实现的类路径,下面通过反射实例化
			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();  //代码3
				handlerMappings.put(namespaceUri, namespaceHandler);
				return namespaceHandler;
			}
			catch (ClassNotFoundException ex) {
				...
			}
			
		}
	}

代码2中获取handlerMappings,我们来看看实现细节:

	private Map<String, Object> getHandlerMappings() {
		Map<String, Object> handlerMappings = this.handlerMappings;
		//double check 避免直接加锁
		if (handlerMappings == null) {
			synchronized (this) {
				handlerMappings = this.handlerMappings;
				if (handlerMappings == null) {
					try {
						//从META-INF/spring.handlers获取属性,在spring源码的resource下都有META-INF文件夹,里面有个spring.handlers配置文件
						//下面将会加载全部(所有模块,包括我们自定义的)的spring.handlers文件
						Properties mappings =
								PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader); //代码4
						if (logger.isDebugEnabled()) {
							logger.debug("Loaded NamespaceHandler mappings: " + mappings);
						}
						Map<String, Object> mappingsToUse = new ConcurrentHashMap<>(mappings.size());
						CollectionUtils.mergePropertiesIntoMap(mappings, mappingsToUse);
						handlerMappings = mappingsToUse;
						this.handlerMappings = handlerMappings;
					}
					catch (IOException ex) {
						throw new IllegalStateException(
								"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
					}
				}
			}
		}
		return handlerMappings;
	}

上述代码使用double check来检查handlerMappings的值,当handlerMappings为空后,加锁并重新判断其值是否为空,在空的情况下,开始加载所有的META-INF/spring.handlers配置文件,这里的所有是指原先spring项目中所有的spring.handlers配置,再包括用户自定义的,会将其全部加载,然后把值读取到handlerMappings 中去。

在这里插入图片描述

我们回到DefaultNamespaceHandlerResolver的resolve方法:

DefaultNamespaceHandlerResolver:

public NamespaceHandler resolve(String namespaceUri) {
		//获取所有的handlerMapping,即命名空间与对应NamespaceHandler实现的映射
		Map<String, Object> handlerMappings = getHandlerMappings();  //代码2
		// 我们案例中则为ContextNamespaceHandler
		// http://www.springframework.org/schema/context -> org.springframework.context.config.ContextNamespaceHandler
		Object handlerOrClassName = handlerMappings.get(namespaceUri);
		if (handlerOrClassName == null) {
			return null;
		}
		else if (handlerOrClassName instanceof NamespaceHandler) {
			//假如获取到的对象为NamespaceHandler,则直接返回,不过一般获取的为类路径信息,即下面的分支
			return (NamespaceHandler) handlerOrClassName;
		}
		else {
			//获取到NamespaceHandler实现的类路径,下面通过反射实例化
			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();  //代码3
				handlerMappings.put(namespaceUri, namespaceHandler);
				return namespaceHandler;
			}
			catch (ClassNotFoundException ex) {
				...
			}
			
		}
	}

在代码2获取了handlerMappings 后,根据传入的namespaceUri命名空间获取对应的handlerOrClassName,打开一下上述META-INF/spring.handlers配置的内容,看看与命名空间映射的值是什么。

在这里插入图片描述

我们可以看到第一个就是本案例,

<context:component-scan>

标签的命名空间为http://www.springframework.org/schema/context,因此此时获取到一个字符串:org.springframework.context.config.ContextNamespaceHandler

好,接下来呢,程序会判断handlerOrClassName 是不是NamespaceHandler对象,如果是则直接返回,但是本案例获取到的为字符串,因此会走下面的分支,强转为String,然后利用反射技术,实例化。再调用代码3进行初始化。当前对象为ContextNamespaceHandler,我们看看ContextNamespaceHandler的init方法:

ContextNamespaceHandler:

	public class ContextNamespaceHandler extends NamespaceHandlerSupport {

	@Override
	public void init() {
		registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
		registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
		registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
		registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
		registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
		registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
		registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
	}

}

ContextNamespaceHandler的init方法将默认context命名空间相关的解析器全部初始化,注册到NamespaceHandlerSupport对象的成员变量parsers中,在接下来BeanDefinitionParserDelegate的

parseCustomElement的最后一步

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

将会用到。

至此,DefaultNamespaceHandlerResolver.resolve(String namespaceUri)的源码解析分析完毕,请

关闭当前选项卡

,回到主线,查看handler.parse(ele, new ParserContext(this.readerContext, this, containingBd))解析的过程吧。



版权声明:本文为aidaowuqiong原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。