springboot启动流程
SpringBoot
的启动很简单,通用的代码如下:
@SpringBootApplication
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
}
SpringApplication.run
方法实际执行的方法如下:
public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}
初始化SpringApplication
SpringApplication
的构造函数中调用了initialize
方法来初始化SpringApplication
:
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
- 调用
deduceWebEnvironment
来判断当前的应用是否是web应用,并设置到webEnvironment
属性中。deduceWebEnvironment
方法通过获取
javax.servlet.Servlet
org.springframework.web.context.ConfigurableWebApplicationContext
这两个类来判断,如果能获得这两个类则说明是web应用,否则不是。
- 调用
getSpringFactoriesInstances
从spring.factories文件中找出key为ApplicationContextInitializer的类并实例化,然后调用setInitializers
方法设置到SpringApplication
的initializers
属性中。这个过程就是找出所有的应用程序初始化器。
当前的初始化器有如下几个:
DelegatingApplicationContextInitializer
ContextIdApplicationContextInitializer
ConfigurationWarningsApplicationContextInitializer
ServerPortInfoApplicationContextInitializer
SharedMetadataReaderFactoryContextInitializer
AutoConfigurationReportLoggingInitializer
- 调用
getSpringFactoriesInstances
从spring.factories文件中找出key为ApplicationListener的类并实例化,然后调用setListeners
方法设置到SpringApplication
的listeners
属性中。这个过程就是找出所有的应用程序事件监听器。
当前的事件监听器有如下几个:
ConfigFileApplicationListener
AnsiOutputApplicationListener
LoggingApplicationListener
ClasspathLoggingApplicationListener
BackgroundPreinitializer
DelegatingApplicationListener
ParentContextCloserApplicationListener
ClearCachesApplicationListener
FileEncodingApplicationListener
LiquibaseServiceLocatorApplicationListener
- 调用
deduceMainApplicationClass
方法找出main类,就是这里的SpringBootDemoApplication
类
运行SpringApplication
SpringApplicationRunListeners和SpringApplicationRunListener类
SpringApplicationRunListeners
内部持有SpringApplicationRunListener
集合和1
个Log
日志类。用于SpringApplicationRunListener
监听器的批量执行。
SpringApplicationRunListener
用于监听SpringApplication
的run
方法的执行,它定义了5
个步骤:
- starting:
run
方法执行的时候立马执行,对应的事件类型是ApplicationStartedEvent
- environmentPrepared:
ApplicationContext
创建之前并且环境信息准备好的时候调用,对应的事件类型是ApplicationEnvironmentPreparedEvent
- contextPrepared:
ApplicationContext
创建好并且在source
加载之前调用一次,没有具体的对应事件 - contextLoaded:
ApplicationContext
创建并加载之后并在refresh
之前调用,对应的事件类型是ApplicationPreparedEvent
- finished:
run
方法结束之前调用,对应事件的类型是ApplicationReadyEvent
或ApplicationFailedEvent
SpringApplicationRunListener
目前只有一个实现类EventPublishingRunListener
,它把监听的过程封装成了SpringApplicationEvent
事件并让内部属性ApplicationEventMulticaster
接口的实现类SimpleApplicationEventMulticaster
广播出去,广播出去的事件对象会被SpringApplication
中的listeners
属性进行处理。
所以说SpringApplicationRunListener
和ApplicationListener
之间的关系是通过ApplicationEventMulticaster
广播出去的SpringApplicationEvent
所联系起来的。
run方法
初始化SpringApplication
完成之后,调用run
方法运行:
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch(); // 构造一个任务执行观察者
stopWatch.start(); // 开始执行,记录开始时间
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();
// 获取SpringApplicationRunListeners,内部只有一个EventPublishingRunListener
SpringApplicationRunListeners listeners = getRunListeners(args);
// 封装成SpringApplicationEvent事件然后广播出去给SpringApplication中的listeners所监听
// 这里接受ApplicationStartedEvent事件的listener会执行相应的操作
listeners.starting();
try {
// 构造一个应用程序参数持有类
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 准备并配置环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
// 打印banner图形
Banner printedBanner = printBanner(environment);
// 创建Spring容器
context = createApplicationContext();
analyzers = new FailureAnalyzers(context);
// 配置Spring容器
prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 容器上下文刷新,详见Spring的启动分析
refreshContext(context);
// 容器创建完成之后调用afterRefresh方法
afterRefresh(context, applicationArguments);
// 调用监听器,广播Spring启动结束的事件
listeners.finished(context, null);
// 停止任务执行观察者
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
run
方法执行完成之后,Spring
容器也已经初始化完成,各种监听器和初始化器也做了相应的工作。具体步骤的分析见下文。
配置并准备环境:
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// 创建应用程序的环境信息。如果是web程序,创建StandardServletEnvironment;否则,创建StandardEnvironment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置环境信息。比如profile,命令行参数
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 广播出ApplicationEnvironmentPreparedEvent事件给相应的监听器执行
listeners.environmentPrepared(environment);
// 环境信息的校对
if (!this.webEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
return environment;
}
创建Spring容器上下文:
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
// 判断是否是web应用,
// 如果是则创建AnnotationConfigEmbeddedWebApplicationContext,否则创建AnnotationConfigApplicationContext
contextClass = Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}
配置Spring容器上下文:
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置Spring容器上下文的环境信息
context.setEnvironment(environment);
// Spring容器创建之后做一些额外的事
postProcessApplicationContext(context);
// SpringApplication的初始化器开始工作
applyInitializers(context);
// 遍历调用SpringApplicationRunListener的contextPrepared方法。目前只是将这个事件广播器注册到Spring容器中
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// 把应用程序参数持有类注册到Spring容器中,并且是一个单例
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// 加载sources,sources是main方法所在的类
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 将sources加载到应用上下文中。最终调用的是AnnotatedBeanDefinitionReader.registerBean方法
load(context, sources.toArray(new Object[sources.size()]));
// 广播出ApplicationPreparedEvent事件给相应的监听器执行
// 执行EventPublishingRunListener.contextLoaded方法
listeners.contextLoaded(context);
}
Spring容器创建之后回调方法postProcessApplicationContext:
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
// 如果SpringApplication设置了实例命名生成器,则注册到Spring容器中
if (this.beanNameGenerator != null) {
context.getBeanFactory().registerSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
this.beanNameGenerator);
}
// 如果SpringApplication设置了资源加载器,设置到Spring容器中
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context)
.setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context)
.setClassLoader(this.resourceLoader.getClassLoader());
}
}
}
初始化器开始工作:
protected void applyInitializers(ConfigurableApplicationContext context) {
// 遍历每个初始化器,调用对应的initialize方法
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
首先调用getInitializers
方法获取之前取得的初始化器。之后调用初始化器的initialize
方法。
Spring容器创建完成之后会调用afterRefresh方法:
protected void afterRefresh(ConfigurableApplicationContext context,
ApplicationArguments args) {
callRunners(context, args);
}
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
// 找出Spring容器中ApplicationRunner接口的实现类
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
// 找出Spring容器中CommandLineRunner接口的实现类
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
// 对runners进行排序
AnnotationAwareOrderComparator.sort(runners);
// 遍历runners依次执行
for (Object runner : new LinkedHashSet<Object>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
一些细节
获取初始化器
初始化器的获取由SpringApplication.getSpringFactoriesInstances
方法完成:
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
// 读取ApplicationContextInitializer的实现类
Set<String> names = new LinkedHashSet<String>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 实例化ApplicationContextInitializer的实现类
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
SpringFactoriesLoader.loadFactoryNames
方法获取ApplicationContextInitializer
接口实现的类:
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
// 获取接口类的名称
String factoryClassName = factoryClass.getName();
try {
// 获取FACTORIES_RESOURCE_LOCATION(META-INF/spring.factories)的多个位置
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
List<String> result = new ArrayList<String>();
/**
* urls有
* spring-boot/META-INF/spring.factories
* spring-beans/META-INF/spring.factories
* spring-boot-autoconfigure/META-INF/spring.factories
*
*/
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
// 从META-INF/spring.factories文件中加载配置
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
// 从配置中读取ApplicationContextInitializer的实现类
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
"] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
获取监听器
获取监听器的方法与获取初始化器的方法一致,唯一的区别在于获取org.springframework.context.ApplicationListener
接口的实现类
获取SpringApplicationRunListeners
首先看getRunListeners
方法:
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
可以看到通过调用构造函数来实例化SpringApplicationRunListeners
,传入的参数有logger以及调用getSpringFactoriesInstance
获得的SpringApplicationRunListener
集合。
再看getSpringFactoriesInstance
方法,它和获取初始化器的方法一样,获取的接口类型是org.springframework.boot.SpringApplicationRunListener
。获取到的实现类为org.springframework.boot.context.event.EventPublishRunListener
。
SpringApplicationRunListeners的工作原理
以启动过程中的listeners.starting()
方法为例:
public void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
this.listeners
中只有一个元素:EventPublishingRunListener
。它的starting
方法如下:
public void starting() {
this.initialMulticaster
.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
}
其中this.initialMulticaster
是SimpleApplicationEventMulticaster
的实例。multicastEvent
方法如下:
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
if (executor != null) {
executor.execute(new Runnable() {
@Override
public void run() {
invokeListener(listener, event);
}
});
}
else {
invokeListener(listener, event);
}
}
}
首先调用getApplicationListeners
方法,根据event的type获得ApplicationListener
列表,其中type为ApplicationStartedEvent
。getApplicationListeners
方法中调用retrieveApplicationListeners
获取支持eventType的listener:
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ResolvableType eventType, Class<?> sourceType, ListenerRetriever retriever) {
LinkedList<ApplicationListener<?>> allListeners = new LinkedList<ApplicationListener<?>>();
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.retrievalMutex) {
// 获取所有的listener
listeners = new LinkedHashSet<ApplicationListener<?>>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<String>(this.defaultRetriever.applicationListenerBeans);
}
// 遍历listeners,调用supportsEvent判断listener是否支持eventType
for (ApplicationListener<?> listener : listeners) {
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
// 遍历listenerBeans,调用supportsEvent判断listener是否支持eventType
if (!listenerBeans.isEmpty()) {
BeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
try {
Class<?> listenerType = beanFactory.getType(listenerBeanName);
if (listenerType == null || supportsEvent(listenerType, eventType)) {
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListenerBeans.add(listenerBeanName);
}
allListeners.add(listener);
}
}
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}
AnnotationAwareOrderComparator.sort(allListeners);
return allListeners;
}
ApplicationStartedEvent
事件返回的是4个listener:
- LoggingApplicationListener
- BackgroundPreinitializer
- DelegatingApplicationListener
- LiquibaseServiceLocatorApplicationListener
回到multicastEvent
方法,调用getTaskExecutor
获取executor。executor为空,调用invokeListener
:
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
获取errorHandler,errorHandler为空,调用doInvokeListener
方法:
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || msg.startsWith(event.getClass().getName())) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
Log logger = LogFactory.getLog(getClass());
if (logger.isDebugEnabled()) {
logger.debug("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
可以看到,doInvokeListener
方法直接调用了listener的onApplicationEvent
方法。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器