spring BeanDefinition的加载

以FileSystemXmlApplicationContext.java为例加载xml文件

一、resource的定位

1、FileSystemXmlApplicationContext.java类的refresh()方法为入口,因为此方法为此类的构造器调用

2、进入AbstractApplicationContext.java类的refresh()方法,主要调用ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

3、进入AbstractApplicationContext.java类的obtainFreshBeanFactory()方法,主要调用refreshBeanFactory();

4、进入AbstractRefreshableApplicationContext.java类的refreshBeanFactory(),接着调用loadBeanDefinitions(beanFactory);  此beanFactory为DefaultListableBeanFactory。

5、回调AbstractRefreshableApplicationContext类的子类的AbstractXmlApplicationContext.java的loadBeanDefinitions(DefaultListableBeanFactory beanFactory)方法,接着调用loadBeanDefinitions(beanDefinitionReader);

6、进入AbstractXmlApplicationContext.java类的loadBeanDefinitions(XmlBeanDefinitionReader reader),接着调用reader.loadBeanDefinitions(configLocations);

7、进入AbstractBeanDefinitionReader.java类的loadBeanDefinitions(String... locations)方法,调用counter += loadBeanDefinitions(location);

8、进入AbstractBeanDefinitionReader.java类的loadBeanDefinitions(String location, Set actualResources)方法,第一句ResourceLoader resourceLoader = getResourceLoader();  因为AbstractXmlApplicationContext.java类的loadBeanDefinitions(DefaultListableBeanFactory beanFactory)方法中有句beanDefinitionReader.setResourceLoader(this);  所以resourceLoader 不为null。 接着调用Resource resource = resourceLoader.getResource(location);

resourceLoader.getResource(location)调用DefaultResourceLoader.java类的public Resource getResource(String location) 方法,会进入异常调用return getResourceByPath(location);  此句回调FileSystemXmlApplicationContext.java类的protected Resource getResourceByPath(String path) 方法。返回FileSystemResource的对象。


9、回到AbstractBeanDefinitionReader.java类的loadBeanDefinitions(String location, Set actualResources)方法。进入int loadCount = loadBeanDefinitions(resource);此行。调用XmlBeanDefinitionReader.java类的loadBeanDefinitions(Resource resource)。


10、进入XmlBeanDefinitionReader.java类的loadBeanDefinitions(EncodedResource encodedResource)方法,进入到InputStream inputStream = encodedResource.getResource().getInputStream();此行, 此行调用FileSystemResource.java类的getInputStream()方法,因为第8步最后返回的是FileSystemResource的对象。这样就得到了文件的inputStream。


以上10步完成了resource的定位


二、BeanDefinition的加载


1、接着XmlBeanDefinitionReader.java类的loadBeanDefinitions(EncodedResource encodedResource)方法,进入


2、调用XmlBeanDefinitionReader.java类的


通过查看Document doc = this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());的源码可以知道spring加载xml文件是采用dom方式,将文件流一次性加载到内存中,这样解析是最快的,


3、进入XmlBeanDefinitionReader.java类的registerBeanDefinitions(Document doc, Resource resource)方法,


主要分析documentReader.registerBeanDefinitions(doc, createReaderContext(resource));


4、进入DefaultBeanDefinitionDocumentReader.java类的

5、进入DefaultBeanDefinitionDocumentReader.java类的


6、进入DefaultBeanDefinitionDocumentReader.java类的

7、进入DefaultBeanDefinitionDocumentReader.java类的


先分析红色圈1标记:这个非常重要,是解析xml文件的配置的所有bean以及各种bean的属性的方法,先看BeanDefinitionHolder,是包含BeanDefinition的组合类。


进入BeanDefinitionParserDelegate.java类的parseBeanDefinitionElement(Element ele, BeanDefinition containingBean)方法。主要查看



进入public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) 方法,主要查看


以上一系列方法是将解析出来的xml里节点的属性的值赋给AbstractBeanDefinition对象的属性。最后调用return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); 将AbstractBeanDefinition对象复制给 BeanDefinitionHolder对象。此代码在BeanDefinitionParserDelegate.java类的parseBeanDefinitionElement(Element ele, BeanDefinition containingBean)方法最后面。

经过上面的多个方法后,xml里节点的各属性值已经解析到BeanDefinitionHolder类的对象了。 


以上各步完成了BeanDefinition的载入。



三、BeanDefinition在IOC中的注册



下面进入第7步截图的圆圈2标记。


1、进入BeanDefinitionReaderUtils.java类的registerBeanDefinition()方法。


2、进入DefaultListableBeanFactory.java类的registerBeanDefinition()方法。



此方法为将xml的每一个bean(按id区分,方法中的beanName为每个bean的Id)加入到beanDefinitionMap中,beanName为map的key,beanDefinition为map的value。加入前先判断是不是已经存在,然后根据allowBeanDefinitionOverriding的值来判断是否抛出异常。如果不抛出异常,则替换!


这样整个IOC的初始化工作就做完了!

你可能感兴趣的:(spring BeanDefinition的加载)