SpringBoot启动过程详解
main()├─ 创建 SpringApplication 实例│ ├─ 确定应用类型│ ├─ 加载 ApplicationContextInitializer│ └─ 加载 ApplicationListener├─ 执行 run() 方法│ ├─ 准备环境│ ├─ 创建应用上下文│ ├─ 准备上下文│ ├─ 刷新上下文(核心)│ │ ├─ 准备刷新│ │ ├─ 获取 BeanFactory│
SpringBoot启动过程详解
Spring Boot 的启动过程是一个精心设计的流程,下面我将结合源码详细解释这一过程。
1. 入口点:main 方法和 SpringApplication 初始化
Spring Boot 应用的启动通常从包含 @SpringBootApplication 注解的类的 main 方法开始:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
SpringApplication 构造过程
SpringApplication.run() 方法内部会创建一个新的 SpringApplication 实例:
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return new SpringApplication(primarySources).run(args);
}
SpringApplication 的构造函数主要完成以下工作:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
关键步骤:
- 确定应用类型(WebApplicationType):根据类路径判断是 SERVLET、REACTIVE 还是非 WEB 应用
- 加载
BootstrapRegistryInitializer实例 - 加载并初始化
ApplicationContextInitializer - 加载并初始化
ApplicationListener - 推断主应用类
2. run 方法执行流程
run() 方法是 Spring Boot 启动的核心:
public ConfigurableApplicationContext run(String... args) {
// 1. 创建启动计时器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 2. 创建引导上下文
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
// 3. 准备环境
ConfigurableEnvironment environment = prepareEnvironment(bootstrapContext, applicationArguments);
// 4. 打印 banner
Banner printedBanner = printBanner(environment);
// 5. 创建应用上下文
context = createApplicationContext();
// 6. 准备应用上下文
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 7. 刷新上下文
refreshContext(context);
// 8. 刷新后处理
afterRefresh(context, applicationArguments);
// 9. 停止计时器
stopWatch.stop();
// 10. 发布启动完成事件
listeners.started(context);
listeners.running(context);
return context;
}
2.1 创建引导上下文 (BootstrapContext)
private DefaultBootstrapContext createBootstrapContext() {
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
this.bootstrapRegistryInitializers.forEach(initializer -> initializer.initialize(bootstrapContext));
return bootstrapContext;
}
2.2 准备环境 (prepareEnvironment)
private ConfigurableEnvironment prepareEnvironment(DefaultBootstrapContext bootstrapContext,
SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
// 创建环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置环境
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 发布环境准备事件
listeners.environmentPrepared(bootstrapContext, environment);
// 将环境绑定到SpringApplication
bindToSpringApplication(environment);
// 如果是自定义环境,转换为标准环境
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
deduceEnvironmentClass());
}
// 配置属性源
ConfigurationPropertySources.attach(environment);
return environment;
}
2.3 创建应用上下文 (createApplicationContext)
根据应用类型创建不同的应用上下文:
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
// 默认的工厂实现
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
try {
switch (webApplicationType) {
case SERVLET:
return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE:
return new AnnotationConfigReactiveWebServerApplicationContext();
default:
return new AnnotationConfigApplicationContext();
}
} catch (Exception ex) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, "
+ "you may need a custom ApplicationContextFactory", ex);
}
};
2.4 准备应用上下文 (prepareContext)
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);
// 注册关闭钩子
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
// 将bootstrapContext添加到上下文
context.getBeanFactory().registerResolvableDependency(
BootstrapContext.class, bootstrapContext);
// 将printedBanner添加到上下文
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// 配置bean定义生成器
if (context instanceof BeanDefinitionRegistry) {
configureBeanDefinitionRegistry((BeanDefinitionRegistry) context);
}
// 发布上下文加载事件
listeners.contextLoaded(context);
}
2.5 刷新上下文 (refreshContext)
这是启动过程中最关键的步骤,调用了 AbstractApplicationContext.refresh() 方法:
protected void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
AbstractApplicationContext.refresh() 方法的主要步骤:
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 准备刷新上下文
prepareRefresh();
// 2. 获取新的BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3. 准备BeanFactory
prepareBeanFactory(beanFactory);
try {
// 4. 后处理BeanFactory
postProcessBeanFactory(beanFactory);
// 5. 调用BeanFactory后处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 6. 注册Bean后处理器
registerBeanPostProcessors(beanFactory);
// 7. 初始化消息源
initMessageSource();
// 8. 初始化事件广播器
initApplicationEventMulticaster();
// 9. 初始化特殊bean
onRefresh();
// 10. 注册监听器
registerListeners();
// 11. 完成BeanFactory初始化
finishBeanFactoryInitialization(beanFactory);
// 12. 完成刷新
finishRefresh();
} catch (BeansException ex) {
// 处理异常...
}
}
}
Spring Boot 通过 SpringApplication.refreshContext() 方法调用了这个标准 Spring 刷新过程,并添加了一些 Boot 特有的功能。
2.6 自动配置的实现
自动配置的核心是 @EnableAutoConfiguration 注解,它引入了 AutoConfigurationImportSelector:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
// ...
}
AutoConfigurationImportSelector 负责加载 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件中定义的自动配置类:
public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware,
ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
List<String> configurations = ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())
.getCandidates();
Assert.notEmpty(configurations,
"No auto configuration classes found in META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. "
+ "If you are using a custom packaging, make sure that file is correct.");
return configurations;
}
}
2.7 内嵌Web服务器启动
对于Web应用,内嵌服务器是在 onRefresh() 阶段启动的。以Tomcat为例:
// ServletWebServerApplicationContext
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
} catch (Throwable ex) {
throw new ApplicationContextException("Unable to start web server", ex);
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = getWebServerFactory();
this.webServer = factory.getWebServer(getSelfInitializer());
} else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
} catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}
3. 启动后处理
启动完成后,Spring Boot 会发布一些事件:
// SpringApplication.java
listeners.started(context);
listeners.running(context);
这些事件包括:
ApplicationStartedEvent:应用已启动但命令执行器未运行ApplicationReadyEvent:应用已准备好服务请求
4. 总结流程图
Spring Boot 启动过程可以简化为以下流程图:
main()
└─ SpringApplication.run()
├─ 创建 SpringApplication 实例
│ ├─ 确定应用类型
│ ├─ 加载 ApplicationContextInitializer
│ └─ 加载 ApplicationListener
├─ 执行 run() 方法
│ ├─ 准备环境
│ ├─ 创建应用上下文
│ ├─ 准备上下文
│ ├─ 刷新上下文(核心)
│ │ ├─ 准备刷新
│ │ ├─ 获取 BeanFactory
│ │ ├─ 准备 BeanFactory
│ │ ├─ 执行 BeanFactoryPostProcessor
│ │ ├─ 注册 BeanPostProcessor
│ │ ├─ 初始化消息源
│ │ ├─ 初始化事件广播器
│ │ ├─ onRefresh()(启动Web服务器)
│ │ ├─ 注册监听器
│ │ ├─ 完成Bean初始化
│ │ └─ 完成刷新
│ ├─ 刷新后处理
│ └─ 发布启动完成事件
└─ 返回应用上下文
整个启动过程充分利用了Spring框架的基础设施,同时通过自动配置、starter机制等简化了开发者的配置工作,实现了约定优于配置的理念。
更多推荐


所有评论(0)