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