Spring Boot应用的启动过程看似简单,但其中涉及了复杂的初始化和加载机制。本文将深入剖析Spring Boot的启动流程,了解其自动配置、引导启动和源码运行等 every detail。
当我们通过java -jar
命令启动Spring Boot应用时,整个启动过程经历了以下关键步骤:
org.springframework.boot.SpringApplication
SpringApplication
的静态run
方法,传入主配置类SpringApplication
对象,加载应用上下文初始化器Context
CommandLineRunner
执行接下来我们重点看一下启动的源码流程和自动配置机制。
SpringApplication
类提供了一站式服务来引导启动整个Spring Boot程序,其中封装了很多启动时的初始化和加载逻辑。
通过构造函数创建SpringApplication实例时,进行了一系列的初始化工作:
SERVLET
、REACTIVE
等SpringFactoriesLoader
加载ApplicationContextInitializer
和ApplicationListener
primary sources
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
...
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.setInitializers(this.getSpringFactoriesInstances();
this.setListeners(this.getSpringFactoriesInstances());
this.mainApplicationClass = this.deduceMainApplicationClass();
}
这样就创建好了一个可执行的SpringApplication
实例。
接着调用run(args)
方法启动整个Spring Boot程序:
public ConfigurableApplicationContext run(String... args) {
// 停止watch服务
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 声明应用上下文和异常报告集合
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters;
// 头部打印Banner
configureHeadlessProperty();
// 获取SpringApplicationRunListeners,用于监听run方法的整个流程
SpringApplicationRunListeners listeners = getRunListeners(args);
// 启动所有的监听器
listeners.starting();
try {
// 封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 准备环境 Environment
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
......
}
catch (Throwable ex) {
......
}
// 完成时长记录
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
// 发布应用启动完成事件
listeners.started(context);
// 执行所有 runners
callRunners(context, applicationArguments);
}
run
方法主要完成了以下工作:
SpringApplicationRunListeners
Environment
ApplicationContext
ApplicationContext
初始化器initializers
refresh
应用上下文使其完成加载在这段代码中,我们可以看到启动的关键步骤都出现了,包括监听器、环境、应用上下文的准备,其中隐含了复杂的加载机制。
SpringApplication
会根据web环境类型创建响应的应用上下文对象,常见的两种:
AnnotationConfigServletWebServerApplicationContext
:web环境AnnotationConfigApplicationContext
:普通应用switch (this.webApplicationType) {
case SERVLET:
contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
break;
case REACTIVE:
contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
break;
default:
contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
}
//利用反射实例化上下文
context = (ConfigurableApplicationContext)
contextClass.getConstructor(ApplicationContext.class)
.newInstance(this.applicationContext);
可以看到Spring Boot会通过应用类型选择合适的ApplicationContext
来实例化,保证后续组件的加载顺利进行。
在获得ApplicationContext
实例后,Spring Boot会继续对其进行准备工作,主要在 prepareContext()
方法中:
ApplicationContextInitializer
初始化器到上下文primarySources
到上下文contextPrepared
事件这样一系列的准备工作完成了对上下文环境的构建和初始化,为后续的 refresh
提供基础。
最后通过调用 refresh()
方法启动整个应用上下文:
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
}
}
}
public void refresh() throws BeansException, IllegalStateException {
// 初始化剩余的bean定义
finishBeanFactoryInitialization(beanFactory);
// 最后一步:发布容器刷新完成事件
finishRefresh();
}
在这里,容器会逐步完成Bean定义的加载、注入依赖、初始化等工作,是启动过程中最关键的部分。
至此,SpringApplication
的执行流程我们就解析完毕了,可以看到其包含了初始化、监听、载入、刷新等多个关键步骤,将应用启动的复杂过程进行了串联和统一。这就是Spring Boot应用启动的整体流程。
除了启动流程,Spring Boot中还包含了强大的自动配置功能,这也是其魅力所在。那么Spring Boot又是如何实现自动配置的呢?
在Spring Boot主配置类上,通常会通过 @EnableAutoConfiguration
注解开启自动配置:
@Configuration
@EnableAutoConfiguration
public class MyApplication { }
这里的 @EnableAutoConfiguration
实现了自动配置的开关。
@EnableAutoConfiguration
的关键在于向容器导入了一个 AutoConfigurationImportSelector
的组件,它实现了 DeferredImportSelector
接口。
在其中 getAutoConfigurationEntry()
方法包含了自动配置的核心;
AutoConfigurationImportSelector
通过getAutoConfigurationEntry()
方法加载自动配置类:
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
// 获取所有自动配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 去重并过滤
configurations = removeDuplicates(configurations);
// 封装并返回配置类
return new AutoConfigurationEntry(configurations, exclusions);
}
这里主要通过Spring Factories Loader机制加载META-INF/spring.factories
中的自动配置类实现EnableAutoConfiguration。
上一步加载了大量的自动配置类,但并不是所有配置都会生效,这就涉及到了条件装配。
每一个自动配置类中都定义了 @Conditional
条件注解,只有当条件匹配才会将配置添加到上下文中。
例如 @ConditionalOnClass
指定的类必须存在,@ConditionalOnMissingBean
对应类型的Bean必须不存在等。
这些条件实现了自动配置的精确控制,避免引入不必要的组件。
@Configuration
@ConditionalOnClass(DataSource.class)
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DataSource dataSource() {
// ...
}
}
Spring Boot通过条件装配实现了自动配置的优雅适配。
至此,我们剖析完了Spring Boot应用启动和自动配置的整个过程,可以看到其内部对容器上下文环境的构建进行了精心设计,使得应用能够顺利启动并加载所需的Bean。这种自动配置编程模型是Spring Boot最耀眼的设计之一。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。