Spring容器系列-启动原理(上)

Spring容器系列-启动原理

    Spring 具有非常庞大的体系,但无论多大都是由一个个小的模块组合而来,不管是 SpringMVC 还是 SpringBoot,都是在Spring的基础上延伸而来,因此,看源码要找对方向。

    我们知道,在SpringBoot之前,对象的管理和配置都是通过XML的方式来实现的,那么Spring是怎么读取配置文件,并且管理我们的实体对象的呢?这就需要从Spring容器开始了解。

    一、 什么是Spring容器

    Spring 容器是 Spring 框架的核心,是用来管理对象的。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。

    二、Spring容器加载方式

    Spring 容器的加载主要有 2 种(不包括SpringBoot),一种是xml的方式ClassPathXmlApplicationContext,一种是基于注解的方式AnnotationConfigApplicationContext,实际上他们的顶级接口都是ApplicationContext。

    三、 Spring的运行原理

    Spring启动时读取应用程序提供的Bean配置信息,并在Spring容器中生成一份相应的Bean配置注册表,然后根据这张注册表实例化Bean,装配好Bean之间的依赖关系,为上层应用提供准备就绪的运行环境。

    容器启动的核心流程都是调用的父类(AbstractApplicationContext类)继承而来的refresh()。refresh()定义了一系列用来容器启动的方法,不同的上下文类在核心步骤不变的情况下, 可能重写某些方法,来完成不同的事情。比如 springboot 使用的上下文类就会重写里面的onRefresh(),启动内嵌tomcat。这是一种典型的模板设计模式。

   下面根据代码来进行说明(Spring 版本为5.2.10):

   测试类:

 1 import cn.javatv.bean.SpringXml;
 2 import org.junit.Test;
 3 import org.springframework.context.support.ClassPathXmlApplicationContext;
 4  5 public class MyTest {
 6  7     @Test
 8     public void test1() {
 9         ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
10         SpringXml bean = applicationContext.getBean(SpringXml.class);
11         System.out.println(bean.getInfo());
12     }
13 }

   ClassPathXmlApplicationContext类中:

 1     public ClassPathXmlApplicationContext(
 2             String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
 3             throws BeansException {
 4 
 5         super(parent);
 6         setConfigLocations(configLocations);
 7         if (refresh) {
 8             refresh();
 9         }
10     }

    refresh() 是 spring 容器初始化的核心方法。是 spring 容器初始化的核心流程,它读取 spring xml 配置文件,并创建和初始化 beans,所以该方法非常重要。我们先看下整体情况。

    AbstractApplicationContext#refresh

 1     public void refresh() throws BeansException, IllegalStateException {
 2         synchronized(this.startupShutdownMonitor) {
 3             //1. 刷新前的准备工作:记录下容器启动时间,标记"已启动"状态
 4             this.prepareRefresh();
 5 
 6             //***2. 创建bean工厂对象,如果已经有则销毁,没有则创建。将配置文件解析成一个个 Bean 定义,注册到 BeanFactory中。里面实现对beanDefinition的装载(说到底核心是一个 beanName-> beanDefinition 的 map)
 7             ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
 8 
 9             //***3. BeanFactory的准备工作:设置 BeanFactory 的类加载器,添加一些默认的后置处理器,注册几个特殊的 bean
10             this.prepareBeanFactory(beanFactory);
11 
12             try {
13                 //***4. 空方法-模版方法:子类覆盖方法做额外处理,在bean定义被装载后,提供一个修改容器beanFactory的入口(BeanFactory准备工作完成后进行的后置处理工作)
14                 this.postProcessBeanFactory(beanFactory);
15 
16                 //*** 5. 在Bean未开始实例化时,对Definition定义的修改入口
17                 /*
18                  * BeanDefinitionRegistryPostProcessor
19                  * BeanFactoryPostProcessor
20                  * 完成对这两个接口的调用
21                  * */
22                 this.invokeBeanFactoryPostProcessors(beanFactory);
23 
24                 //6. 把实现了BeanPostProcessor接口的类实例化,并且加入到BeanFactory中
25                 this.registerBeanPostProcessors(beanFactory);
26 
27                 //7. 国际化的支持
28                 this.initMessageSource();
29 
30                 //8. 初始化事件管理类
31                 this.initApplicationEventMulticaster();
32 
33                 //9. 模版方法:留给子类来初始化其它的Bean,这个方法着重理解模板设计模式,因为在springboot中,这个方法是用来做内嵌tomcat启动的
34                 this.onRefresh();
35 
36                 //10. 注册监听器
37                 this.registerListeners();
38 
39                 //***11. 完成容器的初始化,里面的preInstantiateSingletons()会完成单例对象的创建(初始化所有剩下的非懒加载的单例BeanFactory的预准备工作)
40                  /*
41                   * 这个方法是spring中最重要的方法,没有之一
42                   * 1、bean实例化过程
43                   * 2、ioc
44                   * 3、注解支持
45                   * 4、BeanPostProcessor的执行
46                   * 5、Aop的入口
47                  * */
48                 this.finishBeanFactoryInitialization(beanFactory);
49 
50                 //12.完成应用程序的上下文刷新:完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshedEvent通知别人
51                 this.finishRefresh();
52             } catch (BeansException var9) {
53                 if (this.logger.isWarnEnabled()) {
54                     this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
55                 }
56 
57                 this.destroyBeans();
58                 this.cancelRefresh(var9);
59                 throw var9;
60             } finally {
61                 this.resetCommonCaches();
62             }
63 
64         }
65     }


   参考链接:

   https://juejin.cn/post/7112612931199565831?searchId=20240617115705D9275C317AE7241A4667

posted @ 2024-06-17 15:16  欢乐豆123  阅读(10)  评论(0编辑  收藏  举报