建议亲自阅读源码。
Spring Boot 项目启动分析
SpringApplication 初始化分析
SpringApplication application = new SpringApplication(XyzApplication.clsss);
关键代码如下所示:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
参数解释
- resourceLoader:资源加载器,默认设置为
null
,除非有特定的需求,否则一般不手动设置; - primarySources 主要设置为包含
@SpringApplication
注解的类;
初始化流程
- 设置
resourceLoader
以及暂存primarySources
; - 从当前 jar 包中推导出 WEB 应用类型(None:非 WEB 应用,SERVLET:基于 Servlet 的 WEB 应用,REACTIVE:响应式 WEB 应用)。后续会根据 WEB 应用类型来启动相应的 WEB 服务;
- 使用
ClassLoader
扫描所有META-INF/spring.factories
文件,并用 Properties 加载,最后缓存在org.springframework.core.io.support.SpringFactoriesLoader#cache
中; - 分别加载并实例化 Bootstrapper,ApplicationContextInitializer 和 ApplicationListener;
- 推导出主类(包含
main
方法的类)。这里利用了 Throwable 的 stackTrace 来查找的。
自定义设置
SpringApplication
中定义了不少的 set
和 add
方法,可以在执行 run 方法之前进行自定义设置。
例如:
application.setBannerNode(Banner.Mode.None);
application.addBootstrapper(xyz);
SpringApplication 启动分析
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
运行 spring application 主要目的是创建 application context 以及刷新 application context。
-
stop watch 主要用于统计创建和刷新 application context 所消耗的时间;
StopWatch stopWatch = new StopWatch(); stopWatch.start();
-
创建默认的 DefaultBootstrapContext,并对初始化所收集到的所有 bootstrappers 执行 initialize 方法,将 context 作为该方法的参数;
private DefaultBootstrapContext createBootstrapContext() { DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext(); this.bootstrappers.forEach((initializer) -> initializer.intitialize(bootstrapContext)); return bootstrapContext; }
-
设置
java.awt.headless
,如果未进行过自定义设置(如:application.setHeadless(false)、System.setProperties("java.awt.headless", false)或者 JVM 参数:java -Djava.awt.headless=true),则默认设置为 true。如果项目为非 GUI 类型的,如 console 或者 server 类型,建议设置为 true,否则设置为 false;private void configureHeadlessProperty() { System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless))); }
-
获取所有的 org.springframework.boot.SpringApplicationRunListener(从初始化过程中的
org.springframework.core.io.support.SpringFactoriesLoader#cache
中查找),并封装在 SpringApplicationRunListeners 中。该 Listener 中主要定义了 spring application 的生命周期:starting、environmentPrepared、contextPrepared、contextLoaded、started、running 以及 failed。该配置存在于 spring-boot-x.y.z.jar!/META-INF/spring.factories 中:# Run Listeners org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener
初始化 EventPublishingRunListener 过程中创建了应用初始化事件管理器,并将 SpringApplication
初始化过程中收集到的 listeners 添加进入。private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup); }
-
紧接着利用上一步所找到的 run listeners,执行生命周期的第一个方法 starting;
listeners.starting(bootstrapContext, this.mainApplicationClass);
-
解析 command line args(命令参数,如 java xyz.jar --foo=bar --debug);
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
-
各种配置的准备工作;
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) { // Create and configure the environment ConfigurableEnvironment environment = getOrCreateEnvironment(); configureEnvironment(environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach(environment); listeners.environmentPrepared(bootstrapContext, environment); DefaultPropertiesPropertySource.moveToEnd(environment); configureAdditionalProfiles(environment); bindToSpringApplication(environment); if (!this.isCustomEnvironment) { environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass()); } ConfigurationPropertySources.attach(environment); return environment; }
- 根据初始化过程中所推导的 WEB 应用类型创建不同类型的可配置 Environment(ConfigurableEnvironment);
- 创建默认的转换器,并设置到可配置的 Environment 中;
- 从自定义阶段配置的 defaultProperties 以及命令行参数中获得配置(两个 PropertySource:defaultProperties(低优先级) 和 commandLineArgs(高优先级)),并添加到可配置的 Environment 中;
- 将当前的配置用 ConfigurationPropertySource 包装,以便在未来使用 PropertySourcesPropertyResolver 解析配置名;
- 通知所有监听器,环境变量已准备就绪;
- 将名为 defaultProperties 的 PropertySource 移动到最后;
- 根据自定义阶段所配置的
additionalProfiles
追加可配置的 Environment 的 activeProfiles; - 将 SpringApplication 的配置设置到 Environment 中,配置前缀为:
spring.main.
,如spring.main.banner-mode=console
; - 如果未设置自定义环境,则会将此前创建的 Environment 复制(浅拷贝)一份,类型为 StandardEnvironment;
- 重复第 3 步。
-
配置 spring.beaninfo.ignore,默认设置为 true;
configureIgnoreBeanInfo(environment);
-
根据设置的 BannerMode 决定如何打印 banner;
Banner printedBanner = printBanner(environment);
-
根据 WEB 应用类型创建对应的 ConfigurableApplicationContext,这里仅仅是创建该实例,还并未真正准备;
protected ConfigurableApplicationContext createApplicationContext() { return this.applicationContextFactory.create(this.webApplicationType); }
switch (webApplicationType) { case SERVLET: return new AnnotationConfigServletWebServerApplicationContext(); case REACTIVE: return new AnnotationConfigReactiveWebServerApplicationContext(); default: return new AnnotationConfigApplicationContext(); }
-
将 applicationStartup 设置到 ApplicationContext 中,主要是为了统计接下来的步骤所消耗的时间;
context.setApplicationStartup(this.applicationStartup);
-
准备 BootstrapContext 和 ApplicationContext;
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { context.setEnvironment(environment); postProcessApplicationContext(context); applyInitializers(context); listeners.contextPrepared(context); bootstrapContext.close(context); if (this.logStartupInfo) { logStartupInfo(context.getParent() == null); logStartupProfileInfo(context); } // Add boot specific singleton beans 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()); } // Load the sources Set<Object> sources = getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); load(context, sources.toArray(new Object[0])); listeners.contextLoaded(context); }
-
设置此前准备好的环境到 ApplicationContext 中;
-
注册自定义 BeanNameGenerator 到 ApplicationContext 的 BeanFactory 中;
-
设置初始化所传入的 ResourceLoader;
-
添加 ConversionServices 到 ApplicationContext 的 BeanFactory 中;
-
对初始化所收集到的 ApplicationContextInitializer 执行 initialize 方法。主要是对 context 进行初始化操作(如:设置 context id、注册后续操作所需要的 bean)。例如,spring-boot.jar!/META-INF/spring.factories 文件中包含该 Initializer 的配置(我们可以重点关注这几个 context initializer):
org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\ org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
-
利用事件机制通知 ApplicationContext 已准备就绪(contextPrepared);
-
利用事件机制通知 BootstrapContext 已关闭;
-
打印启动日志
-
注册
springApplicationArguments
和springBootBanner
到 bean factory 中; -
如果未自定义 context 中的 bean factory,则默认为
org.springframework.beans.factory.support.DefaultListableBeanFactory
,这里会根据自定义配置阶段所配置的allowBeanDefinitionOverriding
设置到该 bean factory 中; -
添加懒加载处理器;
-
从 context 中获取
BeanDefinitionRegistry
,并创建BeanDefinitionLoader
,装载初始化传入的 primaryClasses;
-
-
刷新 context 信息
protected void refresh(ConfigurableApplicationContext applicationContext) { applicationContext.refresh(); }
- 尝试注册 shutdownHook,保证在线程停止后停止掉 context;
- 刷新准备;
- 刷新 BeanFactory;
- 对 BeanFactory 进行初始化设置;
- 调用 BeanFactoryPostProcessor。该处理器可访问并修改 BeanDefinition,如修改某一个 bean 所依赖的 bean 的 name;
- 添加 BeanPostProcessor。该处理器可在初始化前后访问到 bean;
- 初始化 MessageSource,为未来的参数化和国际化做好准备;
- 初始化 ApplicationEventMulticaster,默认会采用
org.springframework.context.event.SimpleApplicationEventMulticaster
; - 将主动权交给子类,如果为 WEB 应用类型为 Servlet,则会启动 WebServer;
- 将所有的 ApplicationListener (刷新前设置到 context 中的 listeners 以及用户自定义的 listeners)设置到 ApplicationEventMulticaster 中。并顺便将 earlyApplicationEvents 分发到刚刚设置的 listener 上;
- 初始化剩余的 bean(非懒加载,单例);
- 清理资源缓存;
- 初始化 LifecycleProcessor;
- 调用 LifecycleProcessor#onRefresh;
- 触发
org.springframework.context.event.ContextRefreshedEvent
事件; - 清理各种缓存,如反射工具的缓存、注解工具的缓存等等。
-
打印启动日志。这一步主要展示启动事件等信息;
-
通知
org.springframework.boot.SpringApplicationRunListener
服务已经启动完成; -
调用用户自定义的 ApplicationRunner 以及 CommandLineRunner;
-
通知
org.spring.SpringApplicationRunListener
服务正在运行。
至此,Spring 项目启动完毕。