在使用spring mvc时,大家经常会在spring-mvc.xml(假设的一个springmvc的配置文件)中使用一些标签,比如:
- <mvc:annotation-driven />
- <mvc:resources mapping="/style/**" location="/style/" />
那么,如果你对写上这些标签后,都发生了什么,又是谁来处理的这写标签等问题感兴趣,那么你可以看一下此文,希望对你有帮助。
本章节涉及到的类有以下:
- AnnotationDrivenBeanDefinitionParser
- DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader
- MvcNamespaceUtils
- DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver
- XmlReaderContext
当我们启动tomcat时,在调用initWebApplicationContext初始化时,会通过调用XmlWebApplicationContext中的loadBeanDefinition方法,生成XmlBeanDefinitionReader,如下:
通过生成XmlBeanDefinitionReader,将来就可以在下面用这个reader读取到的xml中的bean放到工厂DefaultListableBeanFactory中了。如下图,就是创建的代码:
通过这个类,便可以将xml中定义的bean放到这个DefaultListableBeanFactory中。XmlBeanDefinitionReader是一个代理类,它将实际的XML文档读取委托给BeanDefinitionDocumentReader接口的实现类去做。解析出的bean将注册到bean工厂DefaultListableBeanFactory(容器中)中。
从上图中可以看出,生成完beanDefinitionReader后,变通过loadBeanDefinitions方法用这个reader去读取xml中的bean了,如下图:
提示:上面的原码的方法全都是XmlWebApplicationContext这个类的。
到这便开始使用上面说的那个委托类去获取和注册xml中的bean了
上图源码中documentReader.registerBeanDefinitions(doc,createReaderContext(resource))的
documentReader的值就是BeanDefinitionDocumentReader的唯一实现类DefaultBeanDefinitionDocumentReader,通过它来实现真正的获取和注册bean
这个方法在调用前,需要先通过createReaderContext(resource)创建XmlReaderContext,在这里面将同时创建NamespaceHandlerResolver,这个类决定了哪个命名空间用哪个handler来处理,并进行了映射保存,保存在handlerMappings属性中。如下:
springmvc的jar包下的META-INF/spring.handlers中指定的handler为:
当DefaultBeanDefinitionDocumentReader去解析我们xml中的每个标签时,比如<mvc:anntation-driven/>,便会获取这个标签对应的命名空间,然后从上图的handlerMappings中以这个命名空间为key,找到对应的那个handler(这就mvc对应的handler就是MvcNamespaceHandler)。如下图:
上图中通过readerContext.getNamespaceHandlerResolver()获取到DefaultNamespaceHandlerResolver,然后通过resolve,根据namespaceUri去获取到处理标签(<mvc:annotation-driven/>)的handler(MvcNamespaceHandler),如下图:
上图中便可知道,每种标签的解析器,都是在init方法是注册的,然后当下一步开始解析某个标签时,便从解析器集合中根据注册时的第一个参数的字符串去找对应的解析器,也就是AnnotationDrivenBeanDefinitionParser,如下:
然后通过调用这个解析器的parse方法去初始化一些需要倒对象,然后放到容器中,比如AnnotationDrivenBeanDefinitionParser中parse方法中会注册RequestMappingHandlerMapping 到容器中,这也就是为什么我们写了<mvc:annotation-driven/>后,在controller中写ReqeustMapping就可以处理请求的原因了(此处划重点)
通过上面的步骤,启动时便可以把mvc配置文件中对应的<mvc:**/>标签的处理就完成了。其实每个标签主要是用来想容器中添加一些默认必备的一些对象。
启动时读取每个标签,然后找到对应的解析器去初始化那些对象。
这里我们用的是mvc来举得例子,其实如果你使用了aop,还有context等命名空间的标签,它的处理过程跟mvc标签是相同的。只不过对应的handler以及解析器不是在springmvc.jar中,而是在对应的各自的jar中而已。