在我们使用Spring+SpringMvc+MyBatis项目时候,现在几乎没人在Spring的配置文件中写标签在注册bean了,但是我们还是要明白使用配置文件的解析流程,废话不多说,开始吧。在我开始研究Spring源码的时候最困难的就是不知道从哪开始,但是我们应该都明白大致流程就是
读取配置文件--->解析配置文件--->将解析得到的Bean注册到注册表中
虽然大致流程知道了但还是不知道从哪开始,我们现在DefaultBeanDifinitionDocumentReader类的doRegistryBeanDefinition(Element root)方法中打个断点,然后debug启动我们的SpringMvc项目。
中间这里就是方法的调用栈,一直拉到底可以看到contextInitailized()方法,
这个方法就是初始化WEB项目的应用上下文。这里有个ServletContextEvent参数,
可以看到这里可以得到我们在web.xml文件配置的spring核心配置文件的路径。
我们可以按照调用栈一步一步执行到蓝条的这个方法,源码实现如下
该方法的String location = “classpath*:applicationContext.xml”
这里有几个类需要特别解释一下:
这里补充点知识:http:www.123.com:8080 http是协议,Spring会根据协议的不同使用不同的类来处理资源的获取逻辑
1:ResourceLoader:这个接口是获取相关的资源的,在这里也就是获取Spring的核心配置文件。为什么需要做这一步呢??因为用户输入的相对路径,但是Spring需要使用文件的实际路径,比如:/User/local/srping.xml类似这样的,所以ResourceLoader这个接口就是做这个处理的。
可以看到通过ResourceLoader获取到资源的实际路径。
2:BeanDefinitionReader:它的作用主要是为了加载Bean,然后将spring.xml转换成Document文档,它有三个实现,我们最常规的就是XmlBeanDefinitionReader,因为我们使用的是xml配置的。其余还有二个实现PropertiesBeanDefinitionReader和GroovyBeanDefinitionReader二个实现类。这二个有兴趣可以自己去了解下。 在XmlBeanDefinitionReader类中的loadBeanDefinitions(EncodedResource encodedResource)方法,它的作用是通过之前获得到的文件Resource获取该文件的文件流,并设置编码,然后封装到一个InputSource对象中。 3:BeanDefinitionDocumentReader:该接口作用有二个,第一:解析Document文件。2:将xml配置的Bean属性保存到BeanDefinition中,然后保存到BeanDefinitionHolder中。看看源码的实现,在XmlBeanDefinitionReader类的registerBeanDefinition(Document doc, Resource resource);方法
我们跟进documentReader.registerBeanDefinitions(doc, createReaderContext(resource));这个方法,BeanDefinitionDocumentReader的实现类只有一个就是DefaultBeanDefinitionDocumentReader类。
获取Document文件的根目录,然后开始进行解析:
跟着调用方法一直进来就可以发现parseBeanDefinitionElement方法就是解析Bean标签和各个属性,然后将属性设置到AbstractBeanDefinition对象中,最后将BeanDefinition和beanname和实例别名都保存到BeanDefinitionHolder对象中返回。 3:BeanDefinitionRegistry:它的功能主要是注册实例到注册表中
返回的beanDefinitionHolder对象之后通过BeanDefinitionRegistry的registerBeanDefinition()方法注册,具体实现是在DefaultListAbleBeanFactory类的registerBeanDefinition方法中,具体就是保存在一个beanDefinitionMap的Map中。至此依赖配置文件的容器初始化就到这里了。