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))解析的过程吧。