【Spring】IoC容器实现

IoC容器 初始化过程

定位

BeanDefinition的资源定位,由ResourceLoader通过统一的Resource接口完成,这个Resource对各种形式的BeanDefinition的使用都提供了统一的接口。

大致分为三步:super(parent) 、setConfigLocations 、refresh

super(parent)
调用父类构造函数的作用是为容器设置Bean资源加载器

setConfigLocations
作用是设置Bean定义资源文件的路径,实际是由其父类AbstractRefreshableConfigApplicationContext完成设置

refresh
refresh函数是一个模板方法,执行多个方法,而且提供了各(protected)方法的(默认)实现,其子类可以重写它们

refresh()核心调用方法:obtainFreshBeanFactory函数调用,完成了容器初始化的最重要最基础的功能,Bean定义资源的Resource定位、载入解析和注册。

  1. obtainFreshBeanFactory使用了委派设计模式,定义了算法骨架,具体的行为交给子类AbstractRefreshableApplicationContext来实现
  2. 在AbstractRefreshableApplicationContext子类实现中调用了loadBeanDefinitions抽象方法,这里也是用到了委派模式,具体的实现调用子类容器AbstractXmlApplicationContext来实现
  3. 子类容器AbstractXmlApplicationContext调用了重载函数loadBeanDefinitions,委托给XmlBeanDefinitionReader来实现
  4. XmlBeanDefinitionReader调用父类AbstractBeanDefinitionReader的loadBeanDefinitions
  5. AbstractBeanDefinitionReader中ResourceLoader resourceLoader = getResourceLoader() 得到的是FileSystemXmlApplicationContext(AbstractApplicationContext)
  6. 实际上调用的是DefaultResourceLoader的getResource方法获取Resource,这样完成了Resource定位

载入

把用户定义好的Bean表示成IoC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition。

  1. 在定位过程的构造函数中,调用的refresh方法,在其核心方法obtainFreshBeanFactory中第4步,XmlBeanDefinitionReader的loadBeanDefinitions中调用doLoadDocument方法
  2. DocumentLoader将得到的Resource转换为document对象
  3. 转换成Document对象后,XmlBeanDefinitionReader委派DefaultBeanDefinitionDocumentReader进行实际的解析工作
  4. BeanDefinitionDocumentReader接口通过registerBeanDefinitions方法调用其实现类DefaultBeanDefinitionDocumentReader对Document对象进行解析
  5. 在DefaultBeanDefinitionDocumentReader具体的解析是用BeanDefinitionParserDelegate完成,解析过程中,只是根据元素的配置信息创建了相应的定义类BeanDefinition,没有创建和实例化Bean对象,依赖注入才会使用这些记录信息创建和实例化具体的Bean对象

注册

通过调用BeanDefinitionRegistry接口,把解析得到的BeanDefinition向IoC容器进行注册。在IoC内部就是将BeanDefinition注入到一个HashMap中,IoC通过这个HashMap来持有BeanDefinition数据。

  1. 载入解析完成后,返回封装BeanDefinition的BeanDefinitionHold对象,然后调用BeanDefinitionReaderUtils的registerBeanDefinition方法向IoC容器注册解析的Bean
  2. 最后把BeanDefinition放在了定义的Map beanDefinitionMap中,则完成注册

 

IoC容器 依赖注入

依赖注入是用户第一次向IoC容器索要Bean时触发的,如果定义了BeanDefinition中的lazy-init属性可以让容器完成Bean的预实例化。

getBean() 触发依赖注入

  1. 从缓存中取得Bean,如果是创建过的单例Bean,则不重复创建
  2. 如果不存在Bean则检查BeanDefinition是否存在,是否能在当前BeanFactory中取到或在双亲工厂取到
  3. 对创建的Bean进行类型检查,没问题则返回新创建的 包含了依赖关系的Bean

createBean()

  1. 调用createBeanInstance,通过工厂、构造函数或者BeanWrapper对Bean实例化
  2. 调用populateBean,处理autowire注入,对属性进行注入
  3. 通过resolveReference对BeanReference进行解析
  4. 通过resolveValueIfNecessary对所有注入类型进行处理
  5. 准备条件完成后,BeanWrapper的setPropertyValues完成依赖注入

 

小结

IoC容器通过定位、载入和注册,就完成了IoC容器的初始化过程。这时,IoC容器中DefaultListableBeanFactory中建立了整个Bean的配置信息,这些BeanDefinition可以被容器使用,它们都在beanDefinitionMap里被检索和使用。

在IoC容器初始化完成了BeanDefinition的数据映射后,用户第一次向容器索要Bean时,开始对Bean依赖关系进行注入。

在Bean创建和对象依赖注入的过程中,需要依据BeanDefinition中的信息来递归地完成依赖注入,这些递归都是以getBean为入口。

在Bean创建和依赖注入完成以后,在IoC容器中建立起一系列依靠依赖关系联系的Bean,通过IoC容器的相关接口,可以方便地供上层应用使用。

 
 

参考:
https://blog.csdn.net/u013887236/article/details/51474964
https://blog.csdn.net/u013887236/article/details/51503031
https://blog.csdn.net/u013887236/article/details/51507523

你可能感兴趣的:(【,Java,】,………Spring)