我的上一篇文章说道使用dom解析加载根节点,然后根据根节点的子节点,循环调用,我们看一下源码:
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 {
delegate.parseCustomElement(ele);//针对于自定义元素进行解析
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
我们针对自定义元素解析进行跟进。
点进去我们能看到BeanDefinition parseCustomElement(Element ele) 是对parseCustomElement(Element ele, BeanDefinition containingBd)的重载,如下面代码,第一步是获取节点的uri,第二步是获取这个handler。
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);//获取namespaceUri
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);//获取handler
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));
}
这个uri就是我们写的applicationContext.xml的头文件,如果我们获取的元素是context的话,那么我们获取的对应的uri就是:http://www.springframework.org/schema/context
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
然后我们通过这个uri来进行获取对应的handler,this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri)进入resolve()方法,我们仔细了解一下。
public NamespaceHandler resolve(String namespaceUri) {
Map<String, Object> handlerMappings = getHandlerMappings();//获取key/value的map
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);//反射机制获取它的class对象
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);//获取它的java实例
namespaceHandler.init();//启动它里面的init方法
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
namespaceUri + "] not found", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
namespaceUri + "]: problem with handler class file or dependent class", err);
}
}
}
我们先看上述代码的第一行Map<String, Object> handlerMappings = getHandlerMappings()仔细分析:
private Map<String, Object> getHandlerMappings() {
if (this.handlerMappings == null) {
synchronized (this) {
if (this.handlerMappings == null) {
try {
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);//加载所有的Properties类型的配置文件
if (logger.isDebugEnabled()) {
logger.debug("Loaded NamespaceHandler mappings: " + mappings);
}
Map<String, Object> handlerMappings = new ConcurrentHashMap<String, Object>(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;
}
Properties mappings =PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader)加载的就是jar包下面的META-INF文件夹下面的配置文件,我们可以看到spring.handlers里面写的,就是一堆关于uri=java类的key/value形式的,返回一个相关的handlerMappings。
namespaceHandler.init()执行init方法,这是一个多态的写法,因为前面我们是循环的根节点下的子节点元素,我们以context举例,通过反射的机制和instantiateClass方法获取到它的实例,我们就调用到了ContextNamespaceHandler中的init()
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());
}
}
这里面我们就可以看到我们熟悉的标签:
<context:component-scan base-package=""></context:component-scan>
<context:annotation-config />
然后返回namespaceHandler,接下来我们返回之前的类handler.parse(ele, new ParserContext(this.readerContext, this, containingBd)),这个handler就是我们之前返回的namespaceHandler,也就是实例ContextNamespaceHandler。但是我们并没有发现该实例中有parse(),所以我们去它的父类NamespaceHandlerSupport去看找一找
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;
}
BeanDefinitionParser parser = this.parsers.get(localName)就是寻找我们的标签解析器,annotation-config ,component-scan,找到对应的实例,如ComponentScanBeanDefinitionParser
public BeanDefinition parse(Element element, ParserContext parserContext) {
String[] basePackages = StringUtils.tokenizeToStringArray(element.getAttribute(BASE_PACKAGE_ATTRIBUTE),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
// Actually scan for bean definitions and register them.
ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
return null;
}
}
}