SpringBoot 启动流程
SpringBoot启动流程
整个启动流程包含,推断 WEB 应用类型,设置初始化器,设置 ApplicationListener 监听器,获取并启动 SpringApplicationRunListener 类,准备 Spring 环境,创建并执行 banner 打印类,创建应用上下文,准备应用上下文,刷新应用上下文,刷新应用上下文之后的调用,执行所有的 Runner 运行器。
Spring Boot 的入口程序
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
创建 SpringApplication 对象
- 初始化主要加载资源类到集合中
- 推断当前 WEB 应用类型(NONE、SERVLET、REACTIVE)
- 设置应用上下文初始化器
- 设置 ApplicationListener 监听器
- 推断主入口应用类
// 创建一个新的实例,这个应用上下文将从指定的来源加载 Bean
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 初始化资源加载器,默认 null
this.resourceLoader = resourceLoader;
// 断言主资源不能为空
Assert.notNull(primarySources, "PrimarySources must not be null");
// 初始化主要加载资源类集合并去重
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推断当前 WEB 应用类型,NONE、SERVLET、REACTIVE
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 加载引导程序(2.4.0增加的功能)
this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
// 设置初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 设置监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断主入口应用类
this.mainApplicationClass = deduceMainApplicationClass();
}
run 方法启动
- 创建引导上下文
- 获取并启动所有 SpringApplicationRunListener 对象
- 创建默认的应用参数类
- 准备 Spring 应用环境
- 创建并执行 banner 打印类
- 创建应用上下文
- 准备应用上下文
- 刷新应用上下文
public ConfigurableApplicationContext run(String... args) {
// 创建并启动计时监控类
StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 创建引导上下文
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 设置系统属性“java.awt.headless”的值,默认为 true
configureHeadlessProperty();
// 创建所有 Spring 运行监听器并发布应用启动事件,
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 初始化默认应用参数类
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 根据运行监听器、引导上下文、应用参数来准备 Spring 环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 将要忽略的 bean 参数打开
configureIgnoreBeanInfo(environment);
// 创建并执行 banner 打印类
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);
// 执行所有的 Runner 运行器
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.4.0 之后的版本增加的新功能
private DefaultBootstrapContext createBootstrapContext() {
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
this.bootstrappers.forEach((initializer) -> initializer.intitialize(bootstrapContext));
return bootstrapContext;
}
获取所有 SpringApplicationRunListener 对象并启动
// 从 META-INF/spring.factories 中获取所有的配置类,并将其封装到 SpringApplicationRunListeners 对象中去,主要创建的对象为 EventPublishingRunListener
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);
}
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
(step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}
// 广播事件
public void starting(ConfigurableBootstrapContext bootstrapContext) {
this.initialMulticaster
.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}
// applicationStartingEvent 是 SpringBoot 框架最早执行的监听器,在该监听器执行 started 方法时,会继续发布事件,主要是基于 Spring 的事件机制
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
// 如果线程池为空,则同步发送事件,否则异步发送事件
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
// 返回与给定事件匹配的监听器
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// Potential new retriever to populate
CachedListenerRetriever newRetriever = null;
// Quick check for existing entry on ConcurrentHashMap
CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
if (existingRetriever == null) {
// Caching a new ListenerRetriever if possible
if (this.beanClassLoader == null ||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
newRetriever = new CachedListenerRetriever();
existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
if (existingRetriever != null) {
newRetriever = null; // no need to populate it in retrieveApplicationListeners
}
}
}
if (existingRetriever != null) {
Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
if (result != null) {
return result;
}
// If result is null, the existing retriever is not fully populated yet by another thread.
// Proceed like caching wasn't possible for this current local attempt.
}
return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
创建默认的应用参数类
Source 继承自 SimpleCommandLinePropertySource,用于解析简单的命令行参数
public DefaultApplicationArguments(String... args) {
Assert.notNull(args, "Args must not be null");
this.source = new Source(args);
this.args = args;
}
准备 Spring 应用环境
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 环境准备,广播 ApplicationEnvironmentPreparedEvent
listeners.environmentPrepared(bootstrapContext, environment);
// 附加配置源
DefaultPropertiesPropertySource.moveToEnd(environment);
// 配置其他激活文件
configureAdditionalProfiles(environment);
// 将环境绑定给当前应用程序
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
// 配置 propertySource 对它自己的递归依赖
ConfigurationPropertySources.attach(environment);
return environment;
}
创建 banner 打印类并执行
打印 banner 的详细操作过程
private Banner printBanner(ConfigurableEnvironment environment) {
if (this.bannerMode == Banner.Mode.OFF) {
return null;
}
ResourceLoader resourceLoader = (this.resourceLoader != null) ? this.resourceLoader
: new DefaultResourceLoader(null);
SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter(resourceLoader, this.banner);
if (this.bannerMode == Mode.LOG) {
return bannerPrinter.print(environment, this.mainApplicationClass, logger);
}
return bannerPrinter.print(environment, this.mainApplicationClass, System.out);
}
创建应用上下文
根据不同的应用类型初始化不同的山下文应用类
protected ConfigurableApplicationContext createApplicationContext() {
return this.applicationContextFactory.create(this.webApplicationType);
}
准备应用上下文
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
// 设置应用上下文的 environment
context.setEnvironment(environment);
// 应用山下文的后置处理
postProcessApplicationContext(context);
// 为上下文应用所有初始化器,执行前面设置的 ApplicationContextInitializer 类
applyInitializers(context);
// 触发所有 SpringApplicationRunListener 监听器的 contextPrepared 事件方法。添加所有的事件监听器
listeners.contextPrepared(context);
bootstrapContext.close(context);
// 记录启动日志
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans
// 注册启动参数bean,将容器指定的参数封装成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());
}
// Load the sources
// 加载所有资源
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
// 将 bean 加载到上下文中
load(context, sources.toArray(new Object[0]));
// 触发所有 SpringApplicationRunListener 监听器的 contextLoaded 事件方法
listeners.contextLoaded(context);
}
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
}
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
// 后续会使用其将主资源加载到上下文中去,供后续解析使用
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
Assert.notNull(registry, "Registry must not be null");
Assert.notEmpty(sources, "Sources must not be empty");
this.sources = sources;
this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
this.xmlReader = (XML_ENABLED ? new XmlBeanDefinitionReader(registry) : null);
this.groovyReader = (isGroovyPresent() ? new GroovyBeanDefinitionReader(registry) : null);
this.scanner = new ClassPathBeanDefinitionScanner(registry);
this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}
void load() {
for (Object source : this.sources) {
load(source);
}
}
private void load(Object source) {
Assert.notNull(source, "Source must not be null");
if (source instanceof Class<?>) {
// Class 的方式加载
load((Class<?>) source);
return;
}
if (source instanceof Resource) {
// Resource 资源的方式加载
load((Resource) source);
return;
}
if (source instanceof Package) {
load((Package) source);
return;
}
if (source instanceof CharSequence) {
load((CharSequence) source);
return;
}
throw new IllegalArgumentException("Invalid source type " + source.getClass());
}
private void load(Class<?> source) {
if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
((GroovyBeanDefinitionReader) this.groovyReader).beans(loader.getBeans());
}
if (isEligible(source)) {
// 将符合条件的类注册到应用上下文
this.annotatedReader.register(source);
}
}
// 不是常规的闭包并且不是匿名类,即可
private boolean isEligible(Class<?> type) {
return !(type.isAnonymousClass() || isGroovyClosure(type) || hasNoConstructors(type));
}
刷新应用上下文
最终会调用到 AbstractApplicationContext 抽象类中的 refresh() 方法中去
refreshContext(context);
刷新后应用上下文调用
空方法,用于扩展
执行所有的 Runner 运行器
执行所有 Runner 执行器,执行所有 ApplicationRunner 和 CommandLineRunner 两种运行器。
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}