SpringBoot启动流程深度解析
深入分析SpringBoot应用的启动过程,理解从main方法到应用就绪的完整流程,掌握SpringApplication的工作原理和设计思想。
📋 启动流程概览
SpringBoot应用的启动过程可以分为以下几个关键阶段:
🎯 一、SpringApplication初始化
1.1 构造方法分析
SpringApplication的构造方法是启动流程的入口,让我们看看它的实现:
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.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}关键步骤分析:
- primarySources设置:保存主配置类(通常是启动类)
- 推断应用类型:
WebApplicationType.deduceFromClasspath()推断应用类型- SERVLET:传统Web应用
- REACTIVE:响应式Web应用
- NONE:非Web应用
- 加载初始化器:从
spring.factories加载ApplicationContextInitializer - 加载监听器:从
spring.factories加载ApplicationListener - 推断主类:通过堆栈信息推断main方法所在的类
1.2 应用类型推断
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler",
null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet",
null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer",
null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}推断逻辑:
1.3 加载初始化器和监听器
从spring.factories加载:
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}加载过程:
- 读取spring.factories:从类路径下的
META-INF/spring.factories读取配置 - 实例化:通过反射创建实例
- 排序:按照
@Order注解或Ordered接口排序
🎯 二、run方法执行流程
2.1 run方法签名
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;
}2.2 关键步骤详解
步骤1:创建BootstrapContext
private DefaultBootstrapContext createBootstrapContext() {
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
this.bootstrapRegistryInitializers.forEach((initializer) ->
initializer.initialize(bootstrapContext));
return bootstrapContext;
}BootstrapContext用于在ApplicationContext创建之前进行一些初始化工作。
步骤2:准备环境(prepareEnvironment)
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext,
ApplicationArguments applicationArguments) {
// 创建或获取环境
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置环境属性源
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 发布环境准备事件
ConfigurationPropertySources.attach(environment);
listeners.environmentPrepared(bootstrapContext, environment);
// 将默认属性源移动到末尾
DefaultPropertiesPropertySource.moveToEnd(environment);
// 绑定到SpringApplication
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}环境准备流程图:
步骤3:创建ApplicationContext
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", ex);
}
};根据应用类型创建不同的ApplicationContext:
- SERVLET:
AnnotationConfigServletWebServerApplicationContext - REACTIVE:
AnnotationConfigReactiveWebServerApplicationContext - NONE:
AnnotationConfigApplicationContext
步骤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.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 添加单例Bean
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 = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
// 发布上下文加载事件
listeners.contextLoaded(context);
}准备上下文的关键操作:
- 设置环境:将准备好的Environment设置到Context
- 应用初始化器:执行
ApplicationContextInitializer - 注册单例Bean:注册
ApplicationArguments、Banner等 - 加载源:加载主配置类(启动类)
步骤5:刷新上下文(refreshContext)
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
refresh(context);
}
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}刷新上下文实际上是调用 AbstractApplicationContext.refresh() 方法,这是Spring框架的核心方法。
refresh方法的完整流程:
关键子流程解析:
invokeBeanFactoryPostProcessors(处理BeanFactory后置处理器):
这是自动配置的关键步骤,让我们详细分析:
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory,
getBeanFactoryPostProcessors());
// ...
}public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory,
List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// 先处理BeanDefinitionRegistryPostProcessor
Set<String> processedBeans = new HashSet<>();
// 1. 处理PriorityOrdered类型的
// 2. 处理Ordered类型的
// 3. 处理其他的
// ...
// 再处理BeanFactoryPostProcessor
// ...
}在这个步骤中:
- 处理
@Configuration类 - 处理
@Import注解 - 处理自动配置类:这是自动配置生效的关键
finishBeanFactoryInitialization(完成Bean工厂初始化):
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// 初始化ConversionService
if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
beanFactory.setConversionService(
beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
}
// 注册默认的嵌入式值解析器
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal ->
getEnvironment().resolvePlaceholders(strVal));
}
// 初始化LoadTimeWeaverAware Bean
String[] weaverAwareNames = beanFactory.getBeanNamesForType(
LoadTimeWeaverAware.class, false, false);
for (String weaverAwareName : weaverAwareNames) {
getBean(weaverAwareName);
}
// 停止使用临时类加载器进行类型匹配
beanFactory.setTempClassLoader(null);
// 允许缓存所有Bean定义元数据
beanFactory.freezeConfiguration();
// 实例化所有剩余的单例Bean
beanFactory.preInstantiateSingletons();
}preInstantiateSingletons(预实例化单例Bean):
public void preInstantiateSingletons() throws BeansException {
// ...
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
// ...
} else {
getBean(beanName);
}
}
}
// ...
}🎯 三、事件发布机制
3.1 启动事件体系
SpringBoot在启动过程中发布一系列事件,让我们了解这些事件:
事件发布时机:
- ApplicationStartingEvent:
listeners.starting()- 启动开始 - ApplicationEnvironmentPreparedEvent:
listeners.environmentPrepared()- 环境准备完成 - ApplicationContextInitializedEvent:
listeners.contextPrepared()- 上下文初始化完成 - ApplicationPreparedEvent:
listeners.contextLoaded()- 上下文加载完成 - ContextRefreshedEvent:
refreshContext()- 上下文刷新完成 - ApplicationStartedEvent:
listeners.started()- 应用启动完成 - ApplicationReadyEvent:
listeners.running()- 应用就绪
3.2 事件监听器实现
监听器注册:
public class MyApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
System.out.println("应用已就绪!");
}
}通过注解方式:
@Component
public class MyApplicationListener {
@EventListener
public void onApplicationReady(ApplicationReadyEvent event) {
System.out.println("应用已就绪!");
}
}🎯 四、Bean加载过程
4.1 Bean定义加载
自动配置类的加载:
// AutoConfigurationImportSelector.selectImports
@Override
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationEntry autoConfigurationEntry =
getAutoConfigurationEntry(annotationMetadata);
return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations.removeAll(exclusions);
configurations = getConfigurationClassFilter().filter(configurations);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}4.2 Bean实例化流程
Bean实例化步骤:
🎯 五、Web服务器启动
5.1 Servlet Web服务器启动
对于Servlet类型的应用,SpringBoot会启动嵌入式Web服务器:
// ServletWebServerApplicationContext.onRefresh
@Override
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();
}Tomcat服务器启动:
// TomcatServletWebServerFactory.getWebServer
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory
: createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);
}🎯 六、启动流程完整时序图
📋 关键源码位置
核心类
| 类名 | 作用 | 包路径 |
|---|---|---|
| SpringApplication | 启动入口 | org.springframework.boot |
| ApplicationContext | 应用上下文 | org.springframework.context |
| AbstractApplicationContext | 上下文抽象实现 | org.springframework.context.support |
| ConfigurableApplicationContext | 可配置的上下文接口 | org.springframework.context |
| BeanFactory | Bean工厂 | org.springframework.beans.factory |
关键方法
SpringApplication.run():启动入口方法SpringApplication.prepareEnvironment():准备环境SpringApplication.createApplicationContext():创建上下文SpringApplication.prepareContext():准备上下文AbstractApplicationContext.refresh():刷新上下文(核心方法)
📋 调试技巧
1. 断点设置
关键断点位置:
// 1. 启动入口
SpringApplication.run(MyApplication.class, args);
// 2. 环境准备
prepareEnvironment(...)
// 3. 上下文创建
createApplicationContext()
// 4. 上下文刷新
AbstractApplicationContext.refresh()
// 5. Bean定义处理
invokeBeanFactoryPostProcessors(...)
// 6. Bean实例化
finishBeanFactoryInitialization(...)2. 日志配置
开启调试日志:
# application.yml
logging:
level:
org.springframework.boot: DEBUG
org.springframework.context: DEBUG
org.springframework.beans.factory: DEBUG📖 学习资源
视频教程
书籍推荐
- 《Spring Boot实战》 - 汪云飞
- 《Spring Boot 2精髓》 - 李家智
- 《深入理解Spring Boot》 - 张卫滨
- 《Spring源码深度解析》 - 郝佳
网站资源
✅ 学习检查清单
- [ ] 已理解SpringApplication的初始化过程
- [ ] 已理解应用类型推断机制
- [ ] 已理解环境准备流程
- [ ] 已理解ApplicationContext的创建过程
- [ ] 已理解上下文刷新流程
- [ ] 已理解Bean定义加载过程
- [ ] 已理解Bean实例化流程
- [ ] 已理解事件发布机制
- [ ] 已理解Web服务器启动过程
- [ ] 已绘制启动流程时序图
上一章节:SpringBoot源码深度解析概览
下一章节:自动配置原理
返回目录:源码阅读