引言:在上一篇了解到spring的自定义标签的创建过程,接下下来我们看看自定义标签的解析原理。有不对的地方请大佬留言指出哈。
1、解析源入口:org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#parseBeanDefinitions
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
.....
}
} else {
//自定义标签解析入口
delegate.parseCustomElement(root);
}
}
2、进入parseCustomElement方法内部
org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
//1、获取命名空间url, 获取namespaceUri= http://www.spring.test.com/shema/user
String namespaceUri = this.getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
} else {
//2、根据命名空间url实例化自定义handler处理器
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
} else {
//3、handler进行bean加载注册
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
}
}
以上主要三个方法:
2.1、String namespaceUri = this.getNamespaceURI(ele);
2.2、标签处理器 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
public NamespaceHandler resolve(String namespaceUri) {
//Map<‘namespace’, 'classNamePath'>,获取缓存中的handlerMappings
Map<String, Object> handlerMappings = this.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 {
//用className进行反射获取handler
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
.....
} else {
NamespaceHandler namespaceHandler = (NamespaceHandler)BeanUtils.instantiateClass(handlerClass);
//调用init方法实例化handler
namespaceHandler.init();
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
} catch (ClassNotFoundException var7) {
......
}
}
2.2.1、获取缓存中的handlerMappings , this.getHandlerMappings()方法
org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#getHandlerMappings
此DefaultNamespaceHandlerResolver的构造方法是进行加载找到目标"META-INF/spring.handlers",因此我们可以自定义多个handler
private Map<String, Object> getHandlerMappings() {
Map<String, Object> handlerMappings = this.handlerMappings;
if (handlerMappings == null) {
synchronized(this) {
handlerMappings = this.handlerMappings;
if (handlerMappings == null) {
.....
try {
//PropertiesLoaderUti同样进行"META-INF/spring.handlers"下的handler解析
Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Loaded NamespaceHandler mappings: " + mappings);
}
handlerMappings = new ConcurrentHashMap(mappings.size());
//handlerMappings 合并
CollectionUtils.mergePropertiesIntoMap(mappings, (Map)handlerMappings);
this.handlerMappings = (Map)handlerMappings;
} catch (IOException var5) {
throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", var5);
}
}
}
}
return (Map)handlerMappings;
}
2.3、handler标签解析
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
2.3.1
org.springframework.beans.factory.xml.NamespaceHandlerSupport#parse
public BeanDefinition parse(Element element, ParserContext parserContext) {
BeanDefinitionParser parser = this.findParserForElement(element, parserContext);
return parser != null ? parser.parse(element, parserContext) : null;
}
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
String localName = parserContext.getDelegate().getLocalName(element);
BeanDefinitionParser parser = (BeanDefinitionParser)this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}
2.3.2 最终进入默认标签解析逻辑
org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parse
org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parse#parseInternal
真正实现自定义的标签解析AbstractSingleBeanDefinitionParser#parseInternal
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
//获取构建器
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
String parentName = this.getParentName(element);
if (parentName != null) {
builder.getRawBeanDefinition().setParentName(parentName);
}
//获取bean的class对象
Class<?> beanClass = this.getBeanClass(element);
if (beanClass != null) {
builder.getRawBeanDefinition().setBeanClass(beanClass);
} else {
//自定义解析器是若重写getBeanClassName,则会进行获取beanClassName
String beanClassName = this.getBeanClassName(element);
if (beanClassName != null) {
builder.getRawBeanDefinition().setBeanClassName(beanClassName);
}
}
//构建bean资源
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
BeanDefinition containingBd = parserContext.getContainingBeanDefinition();
if (containingBd != null) {
//父类资源scope属性
builder.setScope(containingBd.getScope());
}
//懒加载
if (parserContext.isDefaultLazyInit()) {
builder.setLazyInit(true);
}
//调用自定义解析器重写的doParse方法进行解析
this.doParse(element, parserContext, builder);
return builder.getBeanDefinition();
}
3、BeanDefinitionParser解析器接口的实现类,可以看出spring生态的其他解析器,如:mongo、dubbo、redis等