本章节主要学习spring中xml的解析过程。
一、入口
在web.xml配置文件中可以看到springmvc配置了DispatcherServlet,说明入口是该类。一般我们知道初始化方法大概是init()之类的,但是在DispatcherServlet中并没有找到该方法,我们可以查找他的父类,最终在HttpServletBean中找到初始化方法init()。从这里也可以看出DispatcherServlet也是一个servlet。
DispatcherServlet类-->FrameworkServlet类-->HttpServletBean类-->init()方法。
init() ->initWebApplicationContext() ->configureAndRefreshWebApplicationContext(cwac);
跟着截图标记,一步步往下走。
进入configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac)方法中,可以看到最后一行wac.refresh()。点进去
在子类AbstractApplicationContext中实现了refresh()方法。这里类与接口等之间的关系比较复杂,在这里就不一一列举出来。(列出来感觉也没什么用。。)
这里就不截图了。。直接列出跟踪路径。 进入上面截图中的(ConfigurableListableBeanFactory类)obtainFreshBeanFactory() ----》 (AbstractRefreshableApplicationContext类)refreshBeanFactory() 方法中的 loadBeanDefinitions(beanFactory); 通过该方法加载xml配置文件。
继续跟踪代码,loadBeanDefinitions(XmlBeanDefinitionReader reader) ---》reader.loadBeanDefinitions(configResources)
---》loadBeanDefinitions(resource); 进入该方法的子类 XmlBeanDefinitionReader的实现。这里会将一个 new EncodedResource(resource) 传入
encodedResource是将Resource进行封装(封装编码等信息)。每一个xml文件对应一个Resource。
继续跟踪代码
这里通过doLoadDocument(inputSource, resource),得到document。到这里大家是不是有点熟悉了,拿到了每个xml的上下文对象。
得到Document之后将它注册到beandefinitions中。
registerBeanDefinitions(Document doc, XmlReaderContext readerContext) --》doRegisterBeanDefinitions(root); doRegisterBeanDefinitions(Element root) --》parseBeanDefinitions(root, this.delegate);
如上截图,在这里开始解析xml文件中的元素。parseDefaultElement(ele, delegate) 解析默认元素(import、alias、bean、beans),delegate.parseCustomElement(ele)解析自定义元素。这里可以先重点看解析默认元素方法中解析bean元素的代码。
processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) --》delegate.parseBeanDefinitionElement(ele) --》parseBeanDefinitionElement(ele, null) --》parseBeanDefinitionElement(ele, beanName, containingBean);
这里主要看下parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) 这个方法
截图的代码大家可以点进去看下,这里创建beandefinition后,再将标签bean的一些信息(属性等)保存到beandefinition中。
跟踪代码可以看到spring 将解析的元素封装到BeanDefinition 对象中(spring中的注解也会封装成BeanDefinition )
BeanDefinition会把xml里面的标签封装成BeanDefinition对象,以及annotation注解(@Service、@Controller等)封装成BeanDefinition(面后会讲到)
大致流程: xml -> ResourceLoader ->Resoucre ->xxxReader ->BeanDefinition -> 注册
以上就是spring对默认元素的解析,现在我们看下对自定义元素的解析:
上面截图中的 delegate.parseCustomElement(ele); 就是对自定义元素的解析。我们点进去查看具体的解析过程。
getNamespaceHandlerResolver().resolve(namespaceUri);
上面截图中,getHandlerMappings()方法 ,将所有配置文件(各组件下META-INF下的文件)中的 命名空间以及对应的uri (xmlns:context="http://www.springframework.org/schema/context")存入map中。每个uri对应了一个类(namespace),通过handlerMappings.get(namespaceUri); 得到对应的namespace(类名,后面通过反射得到对应的实例).
调用对应namespace的init()方法(这里举例context),可以看到spring会将对应命名空间的解析器进行注册,这样后面就可以解析对应的标签了,用解析器解析对应的标签这里就不给列出来了。
spring解析对应的xml文件一个大致的流程就是这样。