spring解析applicationContext.xml配置文件的document對(duì)象的過程,大體分為默認(rèn)標(biāo)簽的解析和自定義標(biāo)簽的解析
默認(rèn)標(biāo)簽有import標(biāo)簽明郭、alias標(biāo)簽慈俯、bean標(biāo)簽和beans標(biāo)簽豪墅。如下:
//這個(gè)就是bean
public static final String BEAN_ELEMENT = BeanDefinitionParserDelegate.BEAN_ELEMENT;
public static final String NESTED_BEANS_ELEMENT = "beans";
public static final String ALIAS_ELEMENT = "alias";
public static final String IMPORT_ELEMENT = "import";
public static final String RESOURCE_ATTRIBUTE = "resource";
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
自定義標(biāo)簽的解析代碼如下
@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);
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));
}
過程
- 獲取元素(Element)的(命名空間uri)namespaceUri第股。每個(gè)命名空間uri,都會(huì)有一個(gè)默認(rèn)的解析器
- 根據(jù)namespaceUri獲取該元素的處理器(NameSpaceHandler)
- 使用獲取到的處理器處理該標(biāo)簽
該過程中吼拥,我認(rèn)為比較需要注意的是第二步倚聚,即獲取該標(biāo)簽的處理器的過程。下面做一下詳細(xì)解釋
每次獲取標(biāo)簽的處理器的時(shí)候凿可,都會(huì)調(diào)用如下的方法.
//org.springframework.beans.factory.xml.DefaultNamespaceHandlerResolver#resolve
public NamespaceHandler resolve(String namespaceUri) {
Map<String, Object> handlerMappings = 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<?> 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.init();
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
"] for namespace [" + namespaceUri + "]", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
className + "] for namespace [" + namespaceUri + "]", err);
}
}
}
看一下該方法的第一行代碼惑折,獲取handlerMapping。
/**
* Load the specified NamespaceHandler mappings lazily.
*/
private Map<String, Object> getHandlerMappings() {
Map<String, Object> handlerMappings = this.handlerMappings;
if (handlerMappings == null) {
synchronized (this) {
handlerMappings = this.handlerMappings;
if (handlerMappings == null) {
if (logger.isTraceEnabled()) {
logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
}
try {
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (logger.isTraceEnabled()) {
logger.trace("Loaded NamespaceHandler mappings: " + mappings);
}
handlerMappings = new ConcurrentHashMap<>(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 handlerMappings;
}
查看方法
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
public static Properties loadAllProperties(String resourceName, @Nullable ClassLoader classLoader) throws IOException {
Assert.notNull(resourceName, "Resource name must not be null");
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = ClassUtils.getDefaultClassLoader();
}
Enumeration<URL> urls = (classLoaderToUse != null ? classLoaderToUse.getResources(resourceName) :
ClassLoader.getSystemResources(resourceName));
Properties props = new Properties();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
URLConnection con = url.openConnection();
ResourceUtils.useCachesIfNecessary(con);
try (InputStream is = con.getInputStream()) {
if (resourceName.endsWith(XML_FILE_EXTENSION)) {
if (shouldIgnoreXml) {
throw new UnsupportedOperationException("XML support disabled");
}
props.loadFromXML(is);
}
else {
props.load(is);
}
}
}
return props;
}
這里傳入的resouceName的值是
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
所以該方法的最終目的是從classpath下去獲取resources/META-INF/spring.handlers文件中的鍵值對(duì)值枯跑,放入到props中惨驶。
例如spring-mvc模塊中,resources/META-INF/spring.handlers文件中的內(nèi)容是:
http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler
spring-beans模塊中敛助,resources/META-INF/spring.handlers文件的內(nèi)容是:
http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
spring-aop模塊中粗卜,resources/META-INF/spring.handlers文件的內(nèi)容是:
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
spring-context模塊中,resources/META-INF/spring.handlers文件的內(nèi)容是:
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler
spring-tx模塊中纳击,resources/META-INF/spring.handlers文件的內(nèi)容是:
http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler
spring-oxm模塊中续扔,resouces/META-INF/spring.handlers文件的內(nèi)容是:
http\://www.springframework.org/schema/oxm=org.springframework.oxm.config.OxmNamespaceHandler
在我自己的測(cè)試模塊中,走到這一步焕数,handlerMappings里面的值為
當(dāng)然纱昧,這里的模塊中的值跟你依賴的spring的模塊有關(guān),你也可以在自己的項(xiàng)目中的resources/META-INF/spring.handlers文件中定義自己的標(biāo)簽處理器堡赔。
handlerMappings這個(gè)map中识脆,key為namespaceUri。value為標(biāo)簽處理器善已。
這樣我們就可以通過namespaceUri灼捂,來獲取各自的標(biāo)簽處理器