• 0

  • 点赞

  • 收藏

Spring详解-IoC Container(下)

1个月前

上篇我们详细说明了创建bean的过程,bean的创建都是依赖于BeanDefinition,那么BeanDefinition是在哪里被注册到BeanFactory的?还有一系列的BeanProcessor是什么时候被初始化的? 我们标注了@Configuration的注解又是什么时候执行的?

context

ApplicationContext

我们之前说过Spring Framework为了解耦,bean的解析定义和创建是分离的,还记得在没有SpringBoot的时候,我们写第一个Spring Framework的demo是怎么写的吗:

    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
        Object bean = ctx.getBean("testBean");
    }
复制代码

可以看到ClassPathXmlApplicationContext的一个构造方法的参数是spring的配置文件,然后通过getBean方法就可以获取到bean对象了,从上面两行代码我们最少可以知道:ClassPathXmlApplicationContext可以从配置文件中读取bean配置,然后再对所有的bean进行初始化。并且它上层接口ApplicationContext也继承了BeanFactory接口(getBean)。我们先看一下ApplicationContext的类图:

可以看到ApplicationContext除了BeanFactory外,还继承了大量的接口,它实际上提供了一个组合的功能,ApplicationContext组合了所有应用层级的操作并统一对外提供:

  • BeanFactory 对bean容器的操作接口
  • EnvironmentCapable 可以获取到Environment对象
  • ApplicationEventPublisher 可以提供事件发布功能
  • ResourcePatternResolver 可以通过规则匹配从classpath或文件系统加载资源(Resource)
  • MessageSource 提供国际化接口

它的子接口有两个:ConfigurableApplicationContextWebApplicationContext,主要对应两类应用,一类是为标准应用提供操作/配置,一类为是web应用(SpringMVC)提供操作/配置。最终不同的实现类的差异对应的是从不同的配置来源获取bean的实现差异。

Context我们一般称为上下文对象,一般是某个限定范围内的共享数据集合,我们可以在进行数据传递时都通过这个对象来操作共享数据。ApplicationContext其实也是一样的,它实际上就是整个应用的共享对象,通过它,我们可以获取/操作整个应用层级的(部分)共享数据。

初始化

我们下面以ClassPathXmlApplicationContext为例来说明ApplicationContext的核心流程。ClassPathXmlApplicationContext所有构造方法最终都会走到ApplicationContext实现类的一个最核心的方法refresh

  1. 在refresh之前,先设置了我们传入的配置文件

  1. 然后进入refresh方法,refresh方法由抽象父类AbstractApplicationContext实现,里面定义了整个refresh的流程和步骤

这里主要讨论几个关键的步骤

一是obtainFreshBeanFactory,这个方法用于获取实际的BeanFactory,最终返回的BeanFactory都是DefaultListableBeanFactory,也就是我们上一部分提到的,所有BeanFactory的最终实现类。这里还有一个比较重要的抽象方法,由AbstractRefreshableApplicationContext提供的loadBeanDefinitions方法,不同的实现类实现自己的BeanDefinition获取方式并注册到BeanFactory中。

还有另一个比较重要的步骤是invokeBeanFactoryPostProcessors,在此时,BeanFactory已经准备完毕,这里会调用所有的BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor实现,这两个后置处理器实际上就是给出两个扩展点,前者让我们有机会可以修改BeanFactory,后者让我们可以有机会修改BeanDefinition,它们有两个重要的实现:

  • ConfigurationClassPostProcessor 解析所有的@Configuration配置类
  • PropertyResourceConfigurer 替换placeholder

最后就是finishBeanFactoryInitialization了,这里完成了所有非延迟加载的单例对象的初始化。遍历所有beanName并调用getBean方法。

refresh方法定义了整个ApplicatonContext的初始化流程,子类负责实现某些步骤的具体流程。是不是很眼熟,这里应用的就是标准的模板方法设计模式。

总结

最后,我们总结一下初始化一个bean的简单流程:

  1. 加载beanDefinition,可以通过文件、注解或手动创建BeanDefinitnion并加载到BeanFactory
  2. 可以通过BeanFactoryPostProcessor修改beanFactory或BeanDefinitionRegistryPostProcessor修改beanDefinition
  3. 通过getBean方法来初始化所有的bean
  4. 将所有初始化完成的bean放入缓存中(Map)
免责声明:文章版权归原作者所有,其内容与观点不代表Unitimes立场,亦不构成任何投资意见或建议。

java

0

相关文章推荐

未登录头像

暂无评论