上篇我们详细说明了创建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提供国际化接口
它的子接口有两个:ConfigurableApplicationContext和WebApplicationContext,主要对应两类应用,一类是为标准应用提供操作/配置,一类为是web应用(SpringMVC)提供操作/配置。最终不同的实现类的差异对应的是从不同的配置来源获取bean的实现差异。
Context我们一般称为上下文对象,一般是某个限定范围内的共享数据集合,我们可以在进行数据传递时都通过这个对象来操作共享数据。ApplicationContext其实也是一样的,它实际上就是整个应用的共享对象,通过它,我们可以获取/操作整个应用层级的(部分)共享数据。
初始化
我们下面以ClassPathXmlApplicationContext为例来说明ApplicationContext的核心流程。ClassPathXmlApplicationContext所有构造方法最终都会走到ApplicationContext实现类的一个最核心的方法refresh
-
在refresh之前,先设置了我们传入的配置文件
-
然后进入refresh方法,refresh方法由抽象父类
AbstractApplicationContext实现,里面定义了整个refresh的流程和步骤
这里主要讨论几个关键的步骤
一是obtainFreshBeanFactory,这个方法用于获取实际的BeanFactory,最终返回的BeanFactory都是DefaultListableBeanFactory,也就是我们上一部分提到的,所有BeanFactory的最终实现类。这里还有一个比较重要的抽象方法,由AbstractRefreshableApplicationContext提供的loadBeanDefinitions方法,不同的实现类实现自己的BeanDefinition获取方式并注册到BeanFactory中。
还有另一个比较重要的步骤是invokeBeanFactoryPostProcessors,在此时,BeanFactory已经准备完毕,这里会调用所有的BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor实现,这两个后置处理器实际上就是给出两个扩展点,前者让我们有机会可以修改BeanFactory,后者让我们可以有机会修改BeanDefinition,它们有两个重要的实现:
ConfigurationClassPostProcessor解析所有的@Configuration配置类PropertyResourceConfigurer替换placeholder
最后就是finishBeanFactoryInitialization了,这里完成了所有非延迟加载的单例对象的初始化。遍历所有beanName并调用getBean方法。
refresh方法定义了整个ApplicatonContext的初始化流程,子类负责实现某些步骤的具体流程。是不是很眼熟,这里应用的就是标准的模板方法设计模式。
总结
最后,我们总结一下初始化一个bean的简单流程:
- 加载beanDefinition,可以通过文件、注解或手动创建
BeanDefinitnion并加载到BeanFactory - 可以通过
BeanFactoryPostProcessor修改beanFactory或BeanDefinitionRegistryPostProcessor修改beanDefinition - 通过
getBean方法来初始化所有的bean - 将所有初始化完成的bean放入缓存中(Map)