Spring有两种方式加载配置,分别为xml文件、注解的方式,对于xml配置的方式相信大家都不陌生,往往通过new ClassPathXmlApplicationContext("*.xml")就能启动容器了,下面让我们来看看Spring的容器启动都做了哪些事情。

1、ClassPatchXmlApplicationContext的类图结构

如何在istoreos内启动容器_加载

从类图我们可以得到的信息:

  1,ClassPatchXmlApplicationContext是一个容器 ,是BeanFactory的子类;

  2,ClassPatchXmlApplicationContext是一个资源加载器,是ResourceLoader的子类。

2、ClassPatchXmlApplicationContext构造器

如何在istoreos内启动容器_初始化_02

1 public ClassPathXmlApplicationContext(
 2       String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
 3       throws BeansException {
 4    // 调用父类构造方法
 5    super(parent);
 6    // 资源路径设置到当前上下文中
 7    setConfigLocations(configLocations);
 8    // 刷新容器
 9    if (refresh) {
10       refresh();
11    }
12 }

如何在istoreos内启动容器_初始化_02

2.1、调用父类构造器

  最终会调用到父类AbstractApplicationContext的构造方法。

  1、初始化AbstractApplicationContext的资源路径解析器resourcePatternResolver 属性;

  2、为当前上下文设置父上下文环境,若父上下文环境不为空,将父上下文环境合并到当前上下文环境中。

如何在istoreos内启动容器_初始化_02

1 // 构造器
 2 public AbstractApplicationContext(@Nullable ApplicationContext parent) {
 3    this();
 4    setParent(parent);
 5 }
 6 // 初始化资源路径解析器
 7 public AbstractApplicationContext() {
 8    // 创建资源模式处理器
 9    this.resourcePatternResolver = getResourcePatternResolver();
10 }
11 // 设置父容器
12 public void setParent(@Nullable ApplicationContext parent) {
13    this.parent = parent;
14    // 若父容器不为空,则将父容器的环境配置合并到当前容器中
15    if (parent != null) {
16       Environment parentEnvironment = parent.getEnvironment();
17       if (parentEnvironment instanceof ConfigurableEnvironment) {
18          getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
19       }
20    }
21 }

如何在istoreos内启动容器_初始化_02

2.2、设置资源路径

对父类AbstractRefreshableConfigApplicationContext的configLocations做赋值,将配置资源配置文件位置设置到当前应用程序上下文中。

如何在istoreos内启动容器_初始化_02

1 // 设置资源路径
 2 public void setConfigLocations(@Nullable String... locations) {
 3    if (locations != null) {
 4       Assert.noNullElements(locations, "Config locations must not be null");
 5       this.configLocations = new String[locations.length];
 6       for (int i = 0; i < locations.length; i++) {
 7          this.configLocations[i] = resolvePath(locations[i]).trim();
 8       }
 9    }
10    else {
11       this.configLocations = null;
12    }
13 }

如何在istoreos内启动容器_初始化_02

2.3、刷新容器 - Spring的IOC容器的核心启动流程

如何在istoreos内启动容器_初始化_02

1 // 刷新容器的流程
 2 @Override
 3 public void refresh() throws BeansException, IllegalStateException {
 4    synchronized (this.startupShutdownMonitor) {
 5       // 容器刷新前的准备工作
 6       prepareRefresh();
 7       // 创建容器对象DefaultListableBeanFactory,加载xml配置文件的属性值到当前工厂中
 8       ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 9       // beanFactory的准备工作,对各种属性进行填充
10       prepareBeanFactory(beanFactory);
11 
12       try {
13          // 子类覆盖方法做额外的处理,web中的代码有具体实现
14          postProcessBeanFactory(beanFactory);
15 
16          // 调用各种beanFactory处理器
17          invokeBeanFactoryPostProcessors(beanFactory);
18 
19          // 注册bean处理器,这里只是注册功能,真正调用的地方在getBean方法
20          registerBeanPostProcessors(beanFactory);
21 
22          // 为上下文初始化message源,即不同语言的消息体,国际化处理,在springmvc的有实际应用
23          initMessageSource();
24 
25          // 初始化事件监听多路广播器
26          initApplicationEventMulticaster();
27 
28          // 留给子类来初始化其他的bean
29          onRefresh();
30 
31          // 在所有注册的bean中查找listener bean,注册到消息广播器中
32          registerListeners();
33 
34          // 初始化剩下的单实例(非懒加载的)
35          finishBeanFactoryInitialization(beanFactory);
36 
37          // 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知
38          finishRefresh();
39       }
40 
41       catch (BeansException ex) {
42          if (logger.isWarnEnabled()) {
43             logger.warn("Exception encountered during context initialization - " +
44                   "cancelling refresh attempt: " + ex);
45          }
46 
47          // 为防止bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件bean
48          destroyBeans();
49 
50          // 重置active标志
51          cancelRefresh(ex);
52 
53          throw ex;
54       }
55       finally {
56          // 重置缓存
57          resetCommonCaches();
58       }
59    }
60 }

如何在istoreos内启动容器_初始化_02

综上可见,Spring容器启动的核心方法,这些方法后序会做详细介绍

1、prepareRefresh()

 刷新容器前的准备工作

2、obtainFreshBeanFactory()

  创建容器,并加载配置并生成BeanDefinition,加载至缓存。为后续创建bean对象做准备工作。

3、prepareBeanFactory(beanFactory)

  beanFactory的准备工作,主要是用来为容器填充属性

4、postProcessBeanFactory(beanFactory)

  beanFactory容器的后置处理器

5、invokeBeanFactoryPostProcessors(beanFactory)

  调用各种BeanFactoryPostProcessors的后置处理器,实例化BeanFactoryPostProcessor类型的bean对象,包括ConfigurationClassPosyProcessor类对注解的处理,也是SpringBoot自动配置的基础。

6、registerBeanPostProcessors(beanFactory)

 调用各种BeanPostProcessor的后置处理器,实例化BeanPostProcessor类型的bean对象,包括对Spring AOP的自动代理创建器AspectJAwareAdvisorAutoProxyCreator的实例的创建。

7、finishBeanFactoryInitialization(beanFactory)

  初始化定义的bean实例。

8、finishRefresh()

  完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程