上文说到在解析具体的bean时候,会走到不同的分支,可能是parseDefaultElement,也可能是parseCustomElement,接下来看parseCustomElement的加载机制.
自定义标签
- 自定义标签的使用方法(参考<Spring源码深度解析>)
- 创建一个POJO对象,
- 创建一个xsd文件描述组件内容, 注意在xsd文件中描述新的namespace( what's xsd)
- 创建一个类实现BeanDefinitioParser接口
- 创建一个hanlder文件, 该类实现了NameSpaceHanlderSupport接口, 目的是将组件注册到Spring容器中
- 编写Spring.handlers 和 Spring.schema 文件, 这两个文件分别是注册hanlder类的所在包名以及xsd文件所在的位置
private Map<String, Object> getHandlerMappings() {
if(this.handlerMappings == null) {
synchronized(this) {
if(this.handlerMappings == null) {
try {
// 在此处先进行校验, 如果当前的handlerMappings为空,则从hanlderMappingsLocation中读取文件, 然后再把k,v写到mapper中
Properties ex = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if(this.logger.isDebugEnabled()) {
this.logger.debug("Loaded NamespaceHandler mappings: " + ex);
}
ConcurrentHashMap handlerMappings = new ConcurrentHashMap(ex.size());
CollectionUtils.mergePropertiesIntoMap(ex, handlerMappings);
this.handlerMappings = handlerMappings;
} catch (IOException var5) {
throw new IllegalStateException("Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", var5);
}
}
}
}
return this.handlerMappings;
}
- 根据namespace拿到hanlderOrClassName
2.1 由于加载器不一定是bean, 所以可能尚未加载, hanlderOrClassName可能是对象也可能是class name, 如果是class name, 则还需要加载类并且初始化
public NamespaceHandler resolve(String namespaceUri) {
Map 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 {
Class err = ClassUtils.forName(className, this.classLoader);
if(!NamespaceHandler.class.isAssignableFrom(err)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri + "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
} else {
NamespaceHandler namespaceHandler = (NamespaceHandler)BeanUtils.instantiateClass(err); // 初始化bean对象
namespaceHandler.init();
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
} catch (ClassNotFoundException var7) {
throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "] not found", var7);
} catch (LinkageError var8) {
throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" + namespaceUri + "]: problem with handler class file or dependent class", var8);
}
}
}
- 解析自定义标签
- findParserForElement
1.1 使用delegategetLocalName
1.2 拿到BeanDefinitioParser, (根据上文的nameSpaceSupport中的实现, 可以知道是如何实现的)
- parse函数
2.1 调用parseInternal函数拿到bean definition
2.2 解析id
2.3 获得alias
2.4 根据definition, id, aliases构建一个BeandefinitionHolder, 并且注册到context中
- 在parseInternal函数中执行了什么逻辑?
3.1 判断在beanParser中是不是重写了getBeanClass函数
3.2 判断在beanParser中是不是重写了getBeanClassName
3.3 可能会复用父类的scope等属性
3.4 调用自定义的beanParser的doParse函数