一 、過程
1.1 根據schema獲取對應的處理器
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
">
<!-- Enables the Spring MVC @Controller programming model -->
<mvc:annotation-driven/>
</beans>
在上面的時候我們使用了mvc的schema,那麼對於spring,是由哪個類來處理這個schema的呢?又是根據什麼來查找到這個對應的處理類呢?
我們知道mvc的schema是由MvcNamespaceHandler這個類進行處理的。那麼spring是如何將mvc的schema映射到對應的處理類的呢。
在spring 中存在一個NamespaceHandlerResolver接口,只有一個方法,根據schema來解析到對應的處理器。同時有一個默認的實現類。我們來看一下默認的實現類。
public NamespaceHandler resolve(String namespaceUri) {
// 1、獲取所有的映射
Map<String, Object> handlerMappings = getHandlerMappings();
// 獲取映射對應的類名稱
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
else if (handlerOrClassName instanceof NamespaceHandler) {
// 2、如果類是NamespaceHandler的實現類,直接返回
return (NamespaceHandler) handlerOrClassName;
}
else {
// 3、根據類名稱實例化NamespaceHandler的類,並存儲到映射的map。
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("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);
}
}
}
從中我們可以看到最重要的方法是getHandlerMappings();深入到該方法中
if (this.handlerMappings == null) {
synchronized (this) {
if (this.handlerMappings == null) {
try {
// 1、載入所有的Properties
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (logger.isDebugEnabled()) {
logger.debug("Loaded NamespaceHandler mappings: " + mappings);
}
// 2、將Properties合併爲Map
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;
我們看一下載入的時候handlerMappingsLocation的值。
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";
由此,我們確定到xml的schema和對schema的映射關係是寫死在spring.handlers文件中的。我們可以再看一下spring.handlers文件中是如何進行存儲的。
http\://www.springframework.org/schema/mvc=org.springframework.web.servlet.config.MvcNamespaceHandler
現在我們確定了schema和處理器的關係,那麼處理器又是如何對schema中的內容進行處理的呢?
1.2 處理器處理信息
對於NamespaceHandler,我們可以看到有三個方法,初始化、解析元素信息、包裝信息。init()方法在類初始化後被調用(參考上方對於Handler的查找和初始化)。
public class MvcNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("default-servlet-handler", new DefaultServletHandlerBeanDefinitionParser());
registerBeanDefinitionParser("interceptors", new InterceptorsBeanDefinitionParser());
registerBeanDefinitionParser("resources", new ResourcesBeanDefinitionParser());
registerBeanDefinitionParser("view-controller", new ViewControllerBeanDefinitionParser());
}
}
我們可以看一下對於mvc的handler處理器。可以看到建立了一級元素和Parser的映射關係。那麼我們可以看一下Parser的處理,Parser是對xml的硬編碼解析。
1.3 硬編碼解析xml文件
對於BeanDefinitionParser接口,只有一個方法parse,返回信息爲BeanDefinition。