作者 : 玉龙小怪兽
1 | 复制代码成长的路总是伴随着艰辛,坚持,沉淀 , 分享 , 让自己和他人都有所收获 |
目录
- 一、前言
- 二、构建SpringApplication的过程
- 三、SpringBoot核心流程之run()方法
- 四、总结
一、前言
每一天都在使用Springboot , 都在 @Controller, @Service , @Configuration ,@Autowired等一系列注解的照顾下写出了一行一行代码。是的 , 我们是完成了功能的开发,我们是熟练的使用了Springboot提供给我们的注解,但却总感觉缺少了些什么。抛开这些常用的注解 , 大家想想你对Springboot还了解多少 ?
[所以我们需要去探究Springboot的设计思想 ,去看SpringBoot的代码风格 ,去基于Springboot提供给我们的接口做二次开发,从而提高对SpringBoot的整体把握,而不是局限于那些常用的注解]
二、构建SpringApplication的过程
Springboot的启动入口
1 | java复制代码@SpringBootApplication |
通过main方法调用SpringApplication的静态方法run方法, 最后返回一个容器 , 完成Springboot的整个启动过程
1 | java复制代码public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args){ |
run方法它去构建了一个SpringApplication的实例,然后调用run方法去完成Springboot的启动
1 | scss复制代码public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { |
ApplicationContextInitializer(系统初始化器) 主要是用于准备容器时applyInitializers()方法执行里面的方法给容器中做一些初始化的处理
1 | java复制代码public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> { |
加载META-INF/spring.factories下key值为org.springframework.context.ApplicationContextInitializer的实现类,Springboot默认的有如下:
1 | properties复制代码# Application Context Initializers |
这里我们也可以按照Springboot它的规范 , 自定义我们自己的初始化类,做我们自己想做的事情。
1 | properties复制代码org.springframework.context.ApplicationContextInitializer=\ |
ApplicationListener,Sping的监听器,可以对你感兴趣的事件进行监听和处理。
1 | java复制代码public interface ApplicationListener<E extends ApplicationEvent> extends EventListener { |
加载META-INF/spring.factories默认的key = org.springframework.context.ApplicationListener的实现类,同样可以自定义属于我们自己的监听器,Springboot默认的有如下:
1 | properties复制代码org.springframework.context.ApplicationListener=\ |
关于Spring的事件机制 ,后面再用一篇文章详细的说明。Spring的事件机制需要三个角色: 1.事件的发布器 2.事件的载体 3.事件的监听者
这里在介绍一下SpringFactoriesLoader这个类它的作用:
1.从classpath下的多个jar包特定的位置读取文件并初始化类(一般为 spring.factories下的)
2.文件的内容以key为全限定名(抽象类/接口),value是实现类的全类名用,分割
1 | java复制代码private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { |
三、SpringBoot核心流程之run()方法
run方法的核心做的事情如下
1.构建系统需要的环境
2.创建并配置容器
3.加载,解析class为BeanDefinitions,注册到容器中
4.实例化Bean
1 | scss复制代码public ConfigurableApplicationContext run(String... args) { |
prepareEnvironment() :准备环境的过程中, 主要做了以下几件事情
1.创建系统的运行环境,并初始化一些属性源
2.给环境设置转化器,重新排列PropertySource
3.选择激活的配置文件 dev-properties,prod-properties
4.将创建的环境与SpringApplication关联
1 | scss复制代码private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, |
prepareContext() :准备上下文主要做了以下几件事情:
1.给容器设置环境,给factoty设置转化器
2.执行所有initializers属性的初始化方法,对容器进行初始化处理
3.发布ApplicationContextInitializedEvent(容器初始化事件)
4.注册主启动类(StartApp)到BeanDefinitionMap中
5.发布 ApplicationPreparedEvent(应用程序准备事件)
1 | scss复制代码private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, |
refreshContext(context) :刷新容器的这个方法是最为核心的,要做了以下几件事情
1.准备刷新容器,给容器设置同步标识,具体方法
2.给容器中注入一些容器需要的系统bean,beanfactoryPostProcessor等
3.执行BeanFactoryPostProcessor的postProcessBeanDefinitionRegistry方法,将扫描到的注解中的所有的
BeanDefinition注册到容器中
4.注册Bean创建前后的BeanPostProcessor
5.国际化处理
6.初始化事件的发布者
7.给事件的发布者注册监听器
8.实例化非懒加载的所有的类
1 | scss复制代码@Override |
四、总结
1 | erlang复制代码坚持,沉淀 , 分享 , 让自己和他人都有所收获. |
- 有身边的朋友说,我读了源码,好像就是在背这个源码的执行流程,过几天就忘了,活生生的变成了八股文,流程只是让我们知道他到底干了点撒事情,更加需要我们去理解的是:他的类与类之间是如何面向对象设计的,框架中如何运用设计模式的,我想这样的收获肯定是大于你去记住那些流程来得更加的有意义。
- 通过上面对Spingboot的整体脉络的理解,我想大家已经可以摸索出一点心得了。 Springboot在启动时,到底都干了哪些事情,如何利用ApplicationContextInitializer,ApplicationListener去做自己的扩展,自动化配置是在哪里被加载成为BeanDefinition的等。
- 当然本篇文章只是把Springboot启动的整体脉络数理了,并没有做更深入的探究,下一篇文章将会把ApplicationContextInitializer和ApplicationListener进行实战,基于他们做一些功能的二次开发,会去构建一个属于自己的framework
- 文章基于个人的理解以及参考优秀的书籍,文章,如有错误,敬请指出!
本文转载自: 掘金