springboot启动流程的总结
近期闲暇时间在了解springboot应用的启动流程,毕竟玩springboot也这么久了,读读springboot的源码也是应该的,而且,从1.5.9到2.5.x的版本,我发现大体的源码是没什么变化的,这东西读懂了,很实用啊!
springboot包下的类:org.springframework.boot.SpringApplication
run方法
入口就是此类,调用run方法
1 | public ConfigurableApplicationContext run(String... args) { |
启动的各个阶段此方法已囊括,细节需要扒开每个函数具体看。
今天学了画图,画个试试看
![](https://huanghedidi-img-repository.oss-cn-shenzhen.aliyuncs.com/springApplication.run.png)
吐槽下:画图虽然梳理起来舒服,但是真的太耗时间了,就这个流程图,倒腾了1个多小时…..
还是直接分点记录来的快,虽然没那么好看….
refreshContext(context)
spring容器启动生命周期中最核心的部分就是这块,没有之一
先看看官方对此方法的注释
Load or refresh the persistent representation of the configuration, which might an XML file, properties file, or relational database schema.
As this is a startup method, it should destroy already created singletons if it fails, to avoid dangling resources. In other words, after invocation of that method, either all or no singletons at all should be instantiated.调用完此方法,成功的话所有单例被实例化放到容器中;失败则摧毁所有实例!
记录refresh过程的几个节点:
注:围绕的是web环境,即applicationContext的具体实现类为AnnotationConfigEmbeddedWebApplicationContext
// Prepare this context for refreshing. prepareRefresh(); // 看完发现干的事很少,不用重点关注
1
2
3
4
5
- ```java
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 注意这个beanFactory在ApplicationContext中自从构造开始就有,想考究可以看类:GenericApplicationContext// Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); // 对beanFactory做准备的工作,比如设置各种组件; //忽略哪些依赖:EnvironmentAware.class ApplicationContextAware.class 等 // 马上注入些context中已经实例化的对象,如:BeanFactory ResourceLoader ApplicationEventPublisher ApplicationContext等 //。。。。等等不详细写了
1
2
3
4
5
6
7
8
- ```java
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
//看看官方的注释
//Modify the application context's internal bean factory after its standard initialization. All bean definitions will have been loaded, but no beans will have been instantiated yet. This allows for registering special BeanPostProcessors etc in certain ApplicationContext implementations.
//这个阶段beanFactory中的bean定义已就绪,但没有实例化,applicationContext的某些子类可以注入些特定的BeanPostProcessors来进行些个性化的改造,这说的不就是EmbeddedWebApplicationContext吗?
//这家伙注入了一个WebApplicationContextServletContextAwareProcessor// Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); //直接看官方注释吧,写的挺好的! //Instantiate and invoke all registered BeanFactoryPostProcessor beans, respecting explicit order if given. //Must be called before singleton instantiation. //把context中所有BeanFactoryPostProcessor全部注册并实例化,并表示这些东西必须在其他单例之前先实例化,行吧! //看看调用的方法 // invokeBeanFactoryPostProcessors(beanFactory); ----->start // 首先,调用类型为 BeanDefinitionRegistryPostProcessors 的beanFactoryPostProcessor // 这里的首先是调用context中已经有的beanFactoryPostProcessors registryProcessor.postProcessBeanDefinitionRegistry(registry); // 方法的参数是registry(beanFactory实现了相关接口) // ......... 这里很多看不懂 ......... // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered. // 先实例化实现了PriorityOrdered接口的BeanDefinitionRegistryPostProcessors然后再调用其postProcessBeanDefinitionRegistry方法 // 这里有一个很重要的BeanDefinitionRegistryPostProcessors接口实现类:ConfigurationClassPostProcessor // 在processConfigBeanDefinitions(registry)方法中将完成对整个容器bean定义的初始化 // 其使用ConfigurationClassParser对配置类Main做parse,此步将引发整个应用的连锁搜索,将componentScan能扫描到的组件定义放入容器中,将import到的类型为configClass的对象放入到parser的ConfigurationClasses中,供后续扫描搜索bean定义信息 // 使用reader(ConfigurationClassBeanDefinitionReader)扫描搜索剩余的configClasses中需要注入的bean // 至此,完成所有bean定义信息注入到beanFactory的过程 //然后实现了ordered接口的BeanDefinitionRegistryPostProcessors然后再调用其postProcessBeanDefinitionRegistry方法,最后就是啥都没有实现的相关接口的处理 // 接下来调用的是BeanFactoryPostProcessor接口的方法postProcessBeanFactory // 还是重点关注类ConfigurationClassPostProcessor // 其postProcessBeanFactory会对容器中所有的@configuration定义的组件进行enhance,调试的时候会显示xxx$$EnhancerBySpringCGLIB // invokeBeanFactoryPostProcessors(beanFactory); ----->end
1
2
3
4
5
- ```java
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// 注册beanPostProcessor,没啥好说的,也会按照优先级处理// Initialize message source for this context. initMessageSource(); // 初始化实例化messageSource对象
1
2
3
4
5
- ```java
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
//将多播器设置到context中// Initialize other special beans in specific context subclasses. onRefresh(); // 在这个阶段,EmbeddedWebApplicationContext会初始化servlet容器!
1
2
3
4
5
- ```java
// Check for listener beans and register them.
registerListeners();
// 将context中的applicationListener和factory中的applicationListener都注入进多播器applicationListener中// Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); // 看注释就知道,这个阶段实例化所有单例定义的bean到容器中 // 细节很复杂,想复习的时候自己看代码更实在,没法记录呀! //getBean的过程后续会进行梳理
1
2
3
4
5
6
7
8
9
- ```java
// Last step: publish corresponding event.
finishRefresh();
// 1 lifecycleProcessor组件的作用暂时无法理解
// 2 发布ContextRefreshedEvent事件
// 3 启动embeddedServletContainer
// 4 发布EmbeddedServletContainerInitializedEvent事件
getBean
调用factory的getBean获取组件,此过程会实例化组件对象,并存放到factory中,其中的过程很复杂,在此记录下。
同样的,基于的是web环境下的上下文,那么核心逻辑在:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
instanceWrapper = createBeanInstance(beanName, mbd, args); // 实例化bean对象并将其包裹到BeanWrapper中 // 1 applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); // 2 invokeInitMethods(beanName, wrappedBean, mbd);
1
2
3
4
- ```java
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
// 调用MergedBeanDefinitionPostProcessor 其可修改beanDefinitionpopulateBean(beanName, mbd, instanceWrapper); // 在这个过程会调用些postProcessor //populateBean -->start // 1调用InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the // state of the bean before properties are set. This can be used, for example, // to support styles of field injection. // 2调用InstantiationAwareBeanPostProcessor的postProcessPropertyValues //populateBean -->end
1
2
3
4
5
6
7
8
9
10
11
- ```java
exposedObject = initializeBean(beanName, exposedObject, mbd);
//initializeBean(beanName, exposedObject, mbd); -->start
// 1 invokeAwareMethods(beanName, bean);
// bean如果实现了aware接口,则在这里会回调
// 2 applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
// 3 invokeInitMethods(beanName, wrappedBean, mbd);
// 包括调用实现了InitializingBean接口的afterPropertiesSet方法和自定义注解时使用的@init-method方法
// 4 applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
//initializeBean(beanName, exposedObject, mbd); -->end
最核心的getBean过程就是如上,当然很多细节没记录,感觉无法记录,包括解析组件的依赖这一块。
applicationContext组件
这个组件实在太重要了,spring容器指的就是这玩意,其包含了太多的成员变量,看代码debug了几遍都晕头转向的,还是要好好梳理下它,巧了,最近学了画图,用图画来梳理吧,比较明了!