Spring源码--IOC的初始化过程--02

Spring源码--IOC的初始化过程--02

一、前言

  1. 最近开始重温Spring,觉得只知道会用是不行的,所以想尝试着结合资料观摩一下源码
  2. 由于Spring源码非常的多,一步步都看完明显是不现实的,所以只记录自己觉得重要的步骤,其它细枝末节不去纠结
  3. 本人才疏学浅,以下的总结完全主观,在逐渐学习的过程中也会不断更新表述不合适的地方,如果有错误希望能包涵并指出!

二、源码阅读

  1. 接着01博客,到refresh()方法执行了
    在这里插入图片描述
  2. 进入了AbstractApplicationContext中的refresh()方法,首先调用的方法是prepareRefresh()
    在这里插入图片描述
    1. prepareRefresh
      1. 设置了一些基本属性值,跳过到initPropertySources()方法
      在这里插入图片描述
      2. 进入该方法,发现里面什么也没做,由注释我们可以得知该方法是留给子类作扩展的
      在这里插入图片描述
      3. 回到prepareRefresh,调用getEnvironment().validateRequiredProperties();方法,同样由注释我们可以得知该方法用来验证已经读入的属性是否可以被解析,getEnvironment方法获得的对象实际上是我们在setConfigLocations步骤中在AbstractApplicationContext中创建的environment对象
      在这里插入图片描述
      4. 后面都没什么可注意的,回到refresh中,调用ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();去获得ConfigurableListableBeanFactory工厂实例,ConfigurableListableBeanFactory是一个接口
      在这里插入图片描述
    2. obtainFreshBeanFactory()
      1. 进入该方法,里面执行了2个语句,先进入refreshBeanFactory();
        在这里插入图片描述
      2. 该方法的执行在AbstractRefreshableApplicationContext中,首先判断了下当前是否存在工厂对象,如果存在则销毁,下一步
        在这里插入图片描述
      3. 执行createBeanFactory()创建DefaultListableBeanFactory工厂实例,DefaultListableBeanFactory实现了ConfigurableListableBeanFactory接口,进入createBeanFactory方法
        在这里插入图片描述
      4. 里面调用了DefaultListableBeanFactory的构造方法,传入通过getInternalParentBeanFactory()获得的参数,由该方法名我们可知是得到父工厂对象,但显然我们从来没有指定或创建过父工厂对象,所以传入的实际参数为null,下一步
        在这里插入图片描述
      5. 调用父类的构造方法
        在这里插入图片描述
      6. 最上层初始化的是AbstractBeanFactory,里面只初始化了一些基本属性
        在这里插入图片描述
      7. 之后初始化的是AbstractAutowireCapableBeanFactory类,里面也初始化了一些基本属性,下面的3条语句主要是将对应的接口类对象放入ignoredDependencyInterfaces属性中,但该属性是做什么,这里的语句有什么用我目前还不是很明白…
        在这里插入图片描述
      8. 初始化完AbstractBeanFactory和AbstractAutowireCapableBeanFactory后,DefaultListableBeanFactory就初始化完毕了,回到refreshBeanFactory,进入下一步
        在这里插入图片描述
      9. beanFactory.setSerializationId(getId()),为beanFactory设置id
        在这里插入图片描述
      10. customizeBeanFactory(beanFactory),进入该方法,由注释我们可以知道该方法是用来给用户扩展的,可以通过该方法对创建好的工厂对象做一些修改
        在这里插入图片描述
      11. 工厂创建好了,接下来就是解析配置文件了,进入loadBeanDefinitions(beanFactory);
        在这里插入图片描述
        1. 进入到了AbstractXmlApplicationContext类中执行方法,首先创建xml解析器实例,并对其中的一些基本属性赋值(Environment,ResourceLoader,EntityResolver),往下走到达initBeanDefinitionReader,进入该方法
          在这里插入图片描述
        2. 由上面的注释我们知道这个方法又是留给子类作扩展使用的,用来自定义解析器。
          在这里插入图片描述
        3. 回到loadBeanDefinitions,发现最后一步调用的是loadBeanDefinitions的重载方法,传入的是我们刚创建好的xml解析器
          在这里插入图片描述
        4. 进入该方法后首先是获得一个Resource[]数组对象,由名称configResources我们可以推断这里面包含的就是配置文件相关的Resource信息,进入该方法
          在这里插入图片描述
        5. 此时回到了ClassPathXmlApplicationContext类中,需要返回类中的configResources对象,但此时该对象显然为空,我们之前通过setConfigLocations(configLocations);语句设置的是AbstractRefreshableApplicationContext类中的configLocations属性,不要搞混了
          在这里插入图片描述
        6. 因为此时configResources为null,所以进入下面的String[] configLocations = getConfigLocations();获得configLocations属性,这个属性显然我们之前设置过,进入该方法
          在这里插入图片描述
        7. 进入到了AbstractRefreshableApplicationContext类中,将configLocations属性返回
          在这里插入图片描述
        8. 因为成功获取到了对象,所以进入if,调用reader.loadBeanDefinitions(configLocations);此时我们已经是第三次调用loadBeanDefinitions了,第一次调用传入工厂对象,第二次调用传入xml解析对象,这一次传入配置文件路径数组
          在这里插入图片描述
        9. 与前面2次的loadBeanDefinitions返回的void不同,这一次loadBeanDefinitions的执行在AbstractBeanDefinitionReader中,而且返回的是int,粗略判断返回的是配置文件个数,进入for循环中,又调用了loadBeanDefinitions,传入String字符串
          在这里插入图片描述
        10. 还是loadBeanDefinitions,多了一个actualResources参数,不知道什么,继续走
          在这里插入图片描述
        11. 首先获得resourceLoader对象,该对象是我们在实例化xml解析器时配置的,为ClassPathXmlApplicationContext
          在这里插入图片描述
        12. 由于ClassPathXmlApplicationContext和ResourcePatternResolver有关系(在类图里面可以看到,远房亲戚…)所以进入到了下面的if里
          在这里插入图片描述
        13. 里面调用了getResource方法,将我们的配置文件路径传了进去,进入该方法发现到了AbstractApplicationContext类里面,调用了该类中的resourcePatternResolver解析器去解析,该解析器是我们在第一步super(parent)里创建的,实例为PathMatchingResourcePatternResolver,继续进入
          在这里插入图片描述
        14. 进入到了PathMatchingResourcePatternResolver类中,判断了传入的location对象是否包含一些前缀,但我们传入的applicationContext.xml明显没有包含前缀,所以进入下面的else中,根据传入的字符串生成Resource数组并返回
          在这里插入图片描述
        15. 返回到loadBeanDefinitions中,里面居然还继续调用loadBeanDefinitions,这套娃…整理一下,一开始的loadBeanDefinitions传入的是我们创建的工厂对象,后来是创建的xml解析对象,后来是存有所有配置文件信息的configLocations对象,后来是单个配置文件的String对象,到现在是单个配置文件解析的Resource对象,不说了,继续进入
          在这里插入图片描述
        16. 还是loadBeanDefinitions…遍历Resource数组
          在这里插入图片描述
        17. loadBeanDefinitions(new EncodedResource(resource));里面new 的对象由名字我们可以推测是用来解析编码的,继续进入
          在这里插入图片描述
        18. 到这终于不是loadBeanDefinitions了,而是doLoadBeanDefinitions了,代表要真正开始解析了,但是解析肯定需要读取,所以这里通过一系列的操作获取到了用于解析资源的InputStream对象,跳过,到达doLoadBeanDefinitions
          在这里插入图片描述
        19. 经过一系列loadBeanDefinitions后终于要开始解析文件了,doLoadBeanDefinitions就留到下一篇博客把~

三、图像总结

在这里插入图片描述
https://pan.baidu.com/s/1_3dNVCsFp7o1_KzS9FYdPA
7wt8

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值