spring启动流程(一):启动流程概览
创始人
2024-04-04 01:25:16
0

1. spring 启动流程概览

在前面 demo 的 main()方法中,有这么一行:

ApplicationContext context =new AnnotationConfigApplicationContext("org.springframework.learn.demo01");
复制代码

这短短的一行就是spring的整个启动流程了。上面的代码中,声明了一个ApplicationContext类型的对象context,右边使用其子类AnnotationConfigApplicationContext实例化,并在构造方法中传入了包名org.springframework.learn.demo01,这个包名就表明了接下来要扫描哪些包。

这里我们接触到了spring的第一个组件:ApplicationContext,关于ApplicationContext的分析,可以参考我的文章spring组件(一):ApplicationContext。

进入到AnnotationConfigApplicationContext,代码如下:

AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...)

public AnnotationConfigApplicationContext(String... basePackages) {// 1. 调用无参构造函数,会先调用父类GenericApplicationContext的构造函数// 2. 父类的构造函数里面就是初始化DefaultListableBeanFactory,并且赋值给beanFactory// 3. 本类的构造函数里面,初始化了一个读取器:AnnotatedBeanDefinitionReader read,//    一个扫描器ClassPathBeanDefinitionScanner scanner// 4. 这个scanner,就是下面 scan(basePackages) 调用的对象this();//对传入的包进行扫描,扫描完成后,会得到一个 BeanDefinition 的集合scan(basePackages);//启动spring,在这里完成spring容器的初始化操作,//包括bean的实例化、属性注入,将bean保存到spring容器中等refresh();
}
复制代码

这个类就三行,相关操作都已在代码中注释了,这里稍微再总结下,这段代码主要做了三件事:

  1. 调用无参构造,进行属性初始化
  2. 进行包扫描,得到BeanDefinition
  3. 启用spring容器。

接着,我们再来看看spring启动流程中,做了哪些事:

AbstractApplicationContext#refresh

public void refresh() throws BeansException, IllegalStateException {// 使用synchronized是为了避免refresh() 还没结束,再次发起启动或者销毁容器引起的冲突synchronized (this.startupShutdownMonitor) {// 做一些准备工作,记录容器的启动时间、标记“已启动”状态、检查环境变量等prepareRefresh();// 初始化BeanFactory容器、注册BeanDefinition, 最终获得了DefaultListableBeanFactoryConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 还是一些准备工作:// 1. 设置了一个类加载器// 2. 设置了bean表达式解析器// 3. 添加了属性编辑器的支持// 4. 添加了一个后置处理器:ApplicationContextAwareProcessor// 5. 设置了一些忽略自动装配的接口// 6. 设置了一些允许自动装配的接口,并且进行了赋值操作// 7. 在容器中还没有XX的bean的时候,帮我们注册beanName为XX的singleton beanprepareBeanFactory(beanFactory);try {// Spring的一个扩展点. 如果有Bean实现了BeanFactoryPostProcessor接口,// 那么在容器初始化以后,Spring 会负责调用里面的 postProcessBeanFactory 方法。// 具体的子类可以在这步的时候添加特殊的 BeanFactoryPostProcessor 的实现类,来做些事postProcessBeanFactory(beanFactory);// 调用BeanFactoryPostProcessor各个实现类的postProcessBeanFactory(factory) 方法invokeBeanFactoryPostProcessors(beanFactory);// 扩展点,注册 BeanPostProcessor 的实现类,注意不是BeanFactoryPostProcessorregisterBeanPostProcessors(beanFactory);// 初始化当前 ApplicationContext 的 MessageSource,用在国际化操作中initMessageSource();// 这个方法主要为初始化当前 ApplicationContext 的事件广播器initApplicationEventMulticaster();// 这也是spring的一个扩展点onRefresh();// Check for listener beans and register them.// 注册事件监听器registerListeners();// 初始化所有的 singleton beansfinishBeanFactoryInitialization(beanFactory);// 完成启动,finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.// 销毁已经初始化的的BeandestroyBeans();// Reset 'active' flag.// 重置 'active' 状态cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...// 清除缓存resetCommonCaches();}}
}
复制代码

这个方法虽然代码不多,但包含了spring bean的整个创建过程,每个方法做了些什么,在代码中都有注释,这里就不赘述了。

实际上,refresh() 涵盖了spring整个创建bean的流程,在后面的文章中,我们也将重点展开这里面的方法来分析,在现阶段只需要大致了解这些方法做了什么事即可。

整个流程总结如下:

2. spring启动中beanFactory的变化

本文中的源码解读就到这里了,接下来我们来看看,spring启动中beanFactory有些什么变化。

beanFactory 是spring的重要组件之一,直译为spring bean工厂,是spring生产bean与保存bean的地方,关于beanFactory的详细分析,可以查看spring BeanFactory分析。

我们将断点打在AnnotationConfigApplicationContext#AnnotationConfigApplicationContext(String...)this()方法上,然后运行demo01的 main() 方法:

此时的变量中,并没有beanFactory,我们自己添加beanFactory到调度窗口的变量列表中:

这样就能看到对应的值了:

可以看到,此时的beanFactory为null,表明beanFactory并未实例化,我们继续运行:

当运行完this()后,发现beanFactory已经有值了,类型为DefaultListableBeanFactory。但是,在查看beanFactory对象时,发现beanFactory的属性太多了,我们应该重点关注啥呢?

我们这部分主要关注spring bean的创建,因此只需要关注beanFactory的两个属性就可以了:

  • beanDefinitionMap:存放beanDefinition的map.
  • singletonObjects:存放spring bean的map,spring bean创建后都存放在这里,也即直观上理解的spring 容器.

BeanDefinition 是spring重要组件之一,为‘spring bean的描述’,简单来说,就是说明了一个spring bean应该如何创建。关于BeanDefinition的详细分析,可以查看spring BeanDefinition分析。

我们手动添加变量,如下:

可以看到,此时的beanDefinitionMap中已经有4个对象了,显然是在this()方法中添加的,关于这块我们后面会分析。

接着运行,发现beanDefinitionMap又多了两个:

这里的beanObj1beanObj2就是我们自己的类了,由此可以判断出spring就是在AnnotationConfigApplicationContext#scan方法中对包进行扫描的

接下来,代码执行进入AbstractApplicationContext#refresh方法,我们一行行运行下去,发现运行到prepareBeanFactory(beanFactory);时,singletonObjects中第一次出现了对象:

可以看到,这里出现了3个类,基本都跟系统、环境相关,如environment是spring当前使用的环境(profile),systemProperties 当前系统的属性(操作系统、操作系统版本等)。

继续往下运行,发现代码运行到invokeBeanFactoryPostProcessors(beanFactory)时,又多了4个类:

关于这几个类的作用,我们后面的文章中会分析,这里先不必管。继续往下运行,发现在registerBeanPostProcessors(beanFactory);中,又多了一个对象:

org.springframework.context.annotation.internalAutowiredAnnotationProcessor
复制代码

这里我们依旧不用管这个对象,接着运行下去,可以看到在运行initMessageSource()时,又多了一个对象:

messageSource -> {DelegatingMessageSource@1847} "Empty MessageSource"
复制代码

显然,这个对象是用来处理国际化问题的,不过由于demo01中并没有用到国际化,所以这里显示Empty MessageSource。继续运行,发现运行到initApplicationEventMulticaster();时,又多了一个对象:

applicationEventMulticaster -> {SimpleApplicationEventMulticaster@1869} 
复制代码

显然,这个对象是用来处理ApplicationContext 的广播事件的,我们的demo中并没有用到,暂时不必理会。继续下去,发现在运行完finishBeanFactoryInitialization(beanFactory);singletonObjects中终于出现了我们期待的对象:

由此可见,对象就是在该方法中创建的。

总结

  1. spring 包的描述:AnnotationConfigApplicationContext#scan
  2. spring bean的创建:AbstractApplicationContext#finishBeanFactoryInitialization

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...