一篇SpringBoot详细图解 springboot启动流程

springboot启动过程中会用到事件发布机制 。这里先事件发布说明一下 。
Spring中的事件发布机制 。网上有一篇文章介绍得很详细,可以参考:https://www.cnblogs.com/takumicx/p/9972461.html
但是在SpringBoot中用的是事件驱动机制,和Spring中的机制有一些区别 。

一篇SpringBoot详细图解 springboot启动流程
文章插图

先来从图上整体看下springboot的启动流程 。

一篇SpringBoot详细图解 springboot启动流程
文章插图

springboot的监听机制加载执行过程如下:
1:在SpringApplication.run方法中两步:
// 加载监听器SpringApplicationRunListeners listeners = this.getRunListeners(args);// 执行listeners.starting(bootstrapContext, this.mainApplicationClass);SpringApplicationRunListeners listeners = this.getRunListeners(args);private SpringApplicationRunListeners getRunListeners(String[] args) {Class<?>[] types = new Class[]{SpringApplication.class, String[].class};// 从spring.factories中加载key为 SpringApplicationRunListener.class对应的value值并封装成返回的这个类实例注意这个spring.factoies是在spring-boot.jar里面的return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);}
一篇SpringBoot详细图解 springboot启动流程
文章插图

加载的就一个 EventPublishingRunListener 。
this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)这个方法不仅会加载spring.factories中的类 , 还会进行实例化 。而EventPublishingRunListener 只有一个构造器 。public EventPublishingRunListener(SpringApplication application, String[] args) {this.application = application;this.args = args;// 直接new了一个事件发布器this.initialMulticaster = new SimpleApplicationEventMulticaster();// 这里取的就是 上面spring.factories中加载出来的ApplicationListener 监听器Iterator var3 = application.getListeners().iterator();while(var3.hasNext()) {ApplicationListener<?> listener = (ApplicationListener)var3.next();/ /添加事件发布器中方法是在AbstractApplicationEventMulticaster中会先排除代理类再进行添加this.initialMulticaster.addApplicationListener(listener);}}
一篇SpringBoot详细图解 springboot启动流程
文章插图

然后通过 SpringApplicationRunListeners的构造器,把这个EventPublishingRunListener 赋值给了全局变量 listeners 。
SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners, ApplicationStartup applicationStartup) {this.log = log;this.listeners = new ArrayList(listeners);this.applicationStartup = applicationStartup;}listeners.starting(bootstrapContext, this.mainApplicationClass);发布事件
一篇SpringBoot详细图解 springboot启动流程
文章插图

根据事件找到匹配的监听器,执行 。异步执行就丢到线程池中执行 。同步的话就直接调用 。

一篇SpringBoot详细图解 springboot启动流程
文章插图


一篇SpringBoot详细图解 springboot启动流程
文章插图

2:在SpringApplication.run方法中下一步:准备环境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);这里面又发布了一个环境准备的事件 。
一篇SpringBoot详细图解 springboot启动流程
文章插图


一篇SpringBoot详细图解 springboot启动流程
文章插图


一篇SpringBoot详细图解 springboot启动流程
文章插图

这里发布了一个 ApplicationEnvironmentPreparedEvent 事件,这个事件对应的监听器 ConfigFileApplicationListener.

一篇SpringBoot详细图解 springboot启动流程
文章插图

List<EnvironmentPostProcessor> loadPostProcessors() {// 加载一些环境处理的后置处理器return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class, this.getClass().getClassLoader());}postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication()); 中最后会调用到加载配置文件的逻辑 。 但是spring中的监听器监听不到springboot中的事件 。
3:创建容器 context = this.createApplicationContext();
根据不同的类型,创建不同的容器

一篇SpringBoot详细图解 springboot启动流程
文章插图

4:准备上下文 this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {// 把environment设置到上下文里面context.setEnvironment(environment);this.postProcessApplicationContext(context);// 调用初始化的方法this.applyInitializers(context);// 发布一个ApplicationContextInitializedEvent 事件listeners.contextPrepared(context);if (this.logStartupInfo) {this.logStartupInfo(context.getParent() == null);this.logStartupProfileInfo(context);}ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}if (this.lazyInitialization) {context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());}Set<Object> sources = this.getAllSources();Assert.notEmpty(sources, "Sources must not be empty");this.load(context, sources.toArray(new Object[0]));// 发布一个准备完成的事件,在这一步会把springboot 中的监听器都放入到spring容器context中listeners.contextLoaded(context);}this.applyInitializers(context);protected void applyInitializers(ConfigurableApplicationContext context) {// 这里获取调用的就是SpringApplication构造函数执行时 加载的spring.factoies中 ApplicationContextInitializerfor (ApplicationContextInitializer initializer : getInitializers()) {Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),ApplicationContextInitializer.class);Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");initializer.initialize(context);}} 注意一点,如果是我们自定义的监听器 , 如果是监听的这些启动过程中的事件,需要把监听器放到spring.factories中或者yml文件中才会生效,如果是@Component放到spring 容器中是不会生效的,因为到这里spring容器还没创建好 。
这一步把springboot中的监听器都加入到spring容器中,在这一步之后,springboot中的监听器就能监听spring容器中的事件了 。
但是spring中的监听器监听不到springboot中的事件 。
public void contextLoaded(ConfigurableApplicationContext context) {for (ApplicationListener<?> listener : this.application.getListeners()) {if (listener instanceof ApplicationContextAware) {((ApplicationContextAware) listener).setApplicationContext(context);}context.addApplicationListener(listener);}this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));} 5:刷新上下文 refreshContext(context);
6: afterRefresh(context, applicationArguments); 这是一个空方法 , 可以用于扩展,重写这个方法 。
7: listeners.started(context); springboot启动后的事件,这个还没有对应的监听器,可以用于扩展,实现一个监听器监听这个事件做处理 。
public void started(ConfigurableApplicationContext context) {context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);} 8: listeners.running(context); 也是可以扩展的
public void running(ConfigurableApplicationContext context) {context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);} 通过上面的流程,可以知道,springboot中事件发布器就是 EventPublishingRunListener,它里面定义了一系列事件发布的方法 。然后靠 spring中的SimpleApplicationEventMulticaster 发布事件 。
ationContext context) {for (ApplicationListener<?> listener : this.application.getListeners()) {if (listener instanceof ApplicationContextAware) {((ApplicationContextAware) listener).setApplicationContext(context);}context.addApplicationListener(listener);}this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));}【一篇SpringBoot详细图解 springboot启动流程】 5:刷新上下文 refreshContext(context);
6: afterRefresh(context, applicationArguments); 这是一个空方法 , 可以用于扩展,重写这个方法 。
7: listeners.started(context); springboot启动后的事件,这个还没有对应的监听器,可以用于扩展,实现一个监听器监听这个事件做处理 。
public void started(ConfigurableApplicationContext context) {context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);} 8: listeners.running(context); 也是可以扩展的
public void running(ConfigurableApplicationContext context) {context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);} 通过上面的流程,可以知道 , springboot中事件发布器就是 EventPublishingRunListener , 它里面定义了一系列事件发布的方法 。然后靠 spring中的SimpleApplicationEventMulticaster 发布事件 。

经验总结扩展阅读