一 、过程
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。