原理解析
Spring Boot 启动过程
1、示例
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
SpringApplication.run(MainApplication.class, args);
}
}
2、SpringApplication 类
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
//创建SpringApplication -> 运行SpringApplication
return new SpringApplication(primarySources).run(args);
}
创建 SpringApplication
1、构造器
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
2、保存信息到 Spring Boot
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//保存资源加载器
this.resourceLoader = resourceLoader;
//断言primarySources(主配置类)不为null,否则发送错误信息
Assert.notNull(primarySources, "PrimarySources must not be null");
//保存主配置类
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//判断Web应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//获取初始启动器,若spring.factories存在BootstrapRegistryInitializer,则创建实例
this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
//获取初始化器,若spring.factories存在ApplicationContextInitializer,则创建实例
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//获取监听器,若spring.factories存在ApplicationListener,则创建实例
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//获取主程序类
this.mainApplicationClass = deduceMainApplicationClass();
}
(1)判定当前应用的类型
static WebApplicationType deduceFromClasspath() {
//判断是否为响应式编程
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
//返回Servlet
return WebApplicationType.SERVLET;
}
(2)获取初始启动器
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();
//SpringFactoriesLoader加载META-INF/spring.factories,默认扫描当前系统中所有包的META-INF/spring.factories
Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
(3)获取主程序类
private Class<?> deduceMainApplicationClass() {
try {
//获取堆栈
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
//遍历堆栈
for (StackTraceElement stackTraceElement : stackTrace) {
//若存在main方法,则为主程序类
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
运行 SpringApplication
//args:命令行参数
public ConfigurableApplicationContext run(String... args) {
//获取应用启动时间(纳秒)
long startTime = System.nanoTime();
//创建引导上下文环境
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
//让当前应用进入headless模式
configureHeadlessProperty();
//获取所有RunListener(运行监听器),方便所有Listener进行事件感知
SpringApplicationRunListeners listeners = getRunListeners(args);
//遍历listeners调用starting方法,通知项目正在starting
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
//保存命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
//配置忽略的Bean信息
configureIgnoreBeanInfo(environment);
//打印Banner
Banner printedBanner = printBanner(environment);
//创建IOC容器
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
//准备IOC容器的基本信息(ApplicationContext)
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//刷新IOC容器
refreshContext(context);
afterRefresh(context, applicationArguments);
//统计启动所需时间
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
//所有监听器调用started(),通知所有监听器启动完成
listeners.started(context, timeTakenToStartup);
//呼叫所有Runner
callRunners(context, applicationArguments);
}
//捕获以上执行流程抛出异常
catch (Throwable ex) {
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
//调用所有监听器ready方法,通知所有监听器进入就绪状态
listeners.ready(context, timeTakenToReady);
}
//捕获ready抛出异常
catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
return context;
}
1、创建引导上下文环境
private DefaultBootstrapContext createBootstrapContext() {
//创建默认引导上下文环境
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
//遍历在创建SpringApplication时获取的bootstrapRegistryInitializers,调用其intitialize(),完成对引导启动器上下文环境设置
this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
return bootstrapContext;
}
2、让当前应用进入headless模式
private void configureHeadlessProperty() {
System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}
private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";
3、获取所有运行监听器
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger,
//从spring.factories查找SpringApplicationRunListener
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
this.applicationStartup);
}
4、遍历 listeners 调用 starting 方法
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
(step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
Consumer<StartupStep> stepAction) {
StartupStep step = this.applicationStartup.start(stepName);
//listenerAction事件信息,即starting
this.listeners.forEach(listenerAction);
if (stepAction != null) {
stepAction.accept(step);
}
step.end();
}
5、准备环境
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
//返回已存在的环境信息对象,或创建基础环境信息对象
ConfigurableEnvironment environment = getOrCreateEnvironment();
//获取命令行参数,配置环境信息对象
configureEnvironment(environment, applicationArguments.getSourceArgs());
//绑定环境信息
ConfigurationPropertySources.attach(environment);
//监听器调用environmentPrepared(),通知所有监听器当前环境准备完成
listeners.environmentPrepared(bootstrapContext, environment);
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties.");
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
ConfigurationPropertySources.attach(environment);
return environment;
}
(1)返回已存在的环境信息对象,或创建基础环境信息对象
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
switch (this.webApplicationType) {
case SERVLET:
return new ApplicationServletEnvironment();
case REACTIVE:
return new ApplicationReactiveWebEnvironment();
default:
return new ApplicationEnvironment();
}
}
(2)配置环境信息对象
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
//使用类型转换器
environment.setConversionService(new ApplicationConversionService());
}
//读取所有配置源的配置属性值
configurePropertySources(environment, args);
//激活Profiles环境内容
configureProfiles(environment, args);
}
(3)监听器调用 environmentPrepared(),通知所有监听器当前环境准备完成
void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
//遍历所有listener调用environmentPrepared
doWithListeners("spring.boot.application.environment-prepared",
(listener) -> listener.environmentPrepared(bootstrapContext, environment));
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
doWithListeners(stepName, listenerAction, null);
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
Consumer<StartupStep> stepAction) {
StartupStep step = this.applicationStartup.start(stepName);
this.listeners.forEach(listenerAction);
if (stepAction != null) {
stepAction.accept(step);
}
step.end();
}
6、创建 IOC 容器
protected ConfigurableApplicationContext createApplicationContext() {
//根据项目类型创建容器
return this.applicationContextFactory.create(this.webApplicationType);
}
7、准备 IOC 容器的基本信息
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
//保存环境信息到IOC容器
context.setEnvironment(environment);
//IOC容器的后置处理
postProcessApplicationContext(context);
//应用初始化器
applyInitializers(context);
//监听器准备上下文环境
listeners.contextPrepared(context);
//引导关闭上下文
bootstrapContext.close(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
//获取Bean工厂
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//注册命令行参数组件:springApplicationArguments
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
//注册Banner组件:springBootBanner
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory) beanFactory)
.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
// Load the sources
Set<Object> sources = getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[0]));
//监听器加载上下文环境
listeners.contextLoaded(context);
}
(1)应用初始化器
@SuppressWarnings({ "rawtypes", "unchecked" })
protected void applyInitializers(ConfigurableApplicationContext context) {
//遍历所有ApplicationContextInitializer,调用initialize(),对IOC容器进行初始化扩展功能
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
(2)监听器准备上下文环境
void contextPrepared(ConfigurableApplicationContext context) {
//遍历所有listener,调用contextPrepared;EventPublishRunListenr:通知所有的监听器contextPrepared
doWithListeners("spring.boot.application.context-prepared", (listener) -> listener.contextPrepared(context));
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
doWithListeners(stepName, listenerAction, null);
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
Consumer<StartupStep> stepAction) {
StartupStep step = this.applicationStartup.start(stepName);
this.listeners.forEach(listenerAction);
if (stepAction != null) {
stepAction.accept(step);
}
step.end();
}
(3)监听器加载上下文环境
void contextLoaded(ConfigurableApplicationContext context) {
//遍历所有监听器,调用contextLoaded,通知所有监听器contextLoaded
doWithListeners("spring.boot.application.context-loaded", (listener) -> listener.contextLoaded(context));
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
doWithListeners(stepName, listenerAction, null);
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
Consumer<StartupStep> stepAction) {
StartupStep step = this.applicationStartup.start(stepName);
this.listeners.forEach(listenerAction);
if (stepAction != null) {
stepAction.accept(step);
}
step.end();
}
8、刷新 IOC 容器
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
shutdownHook.registerApplicationContext(context);
}
refresh(context);
}
protected void refresh(ConfigurableApplicationContext applicationContext) {
applicationContext.refresh();
}
(1)创建容器中的所有组件
finishBeanFactoryInitialization(beanFactory);
9、呼叫所有Runner
private void callRunners(ApplicationContext context, ApplicationArguments args) {
//保存所有Runner
List<Object> runners = new ArrayList<>();
//从IOC容器中获取所有ApplicationRunner
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
//从IOC容器中获取所有CommandLineRunner
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
//合并所有Runner,且按照@Order进行排序
AnnotationAwareOrderComparator.sort(runners);
//遍历所有Runner
for (Object runner : new LinkedHashSet<>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
(1)调用 run 方法
private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
try {
(runner).run(args);
}
catch (Exception ex) {
throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
}
}
10、处理抛出的异常
private void handleRunFailure(ConfigurableApplicationContext context, Throwable exception,
SpringApplicationRunListeners listeners) {
try {
try {
handleExitCode(context, exception);
if (listeners != null) {
//调用Listener的failed方法
listeners.failed(context, exception);
}
}
finally {
reportFailure(getExceptionReporters(context), exception);
if (context != null) {
context.close();
shutdownHook.deregisterFailedApplicationContext(context);
}
}
}
catch (Exception ex) {
logger.warn("Unable to close ApplicationContext", ex);
}
ReflectionUtils.rethrowRuntimeException(exception);
}
核心组件
1、需要 spring.factories 配置
(1)ApplicationContextInitializer
(2)ApplicationListener
(3)SpringApplicationRunListener
2、合并 Runner
(1)ApplicationRunner
(2)CommandLineRunner
3、全流程
(1)ApplicationListener:onApplicationEvent()
(2)SpringApplicationRunListener:starting()
(3)ApplicationListener:onApplicationEvent()
(4)SpringApplicationRunListener:environmentPrepared()
(5)ApplicationContextInitializer:initialize()
(6)ApplicationListener:onApplicationEvent()
(7)SpringApplicationRunListener:contextPrepared
(8)ApplicationListener:onApplicationEvent()
(9)SpringApplicationRunListener:contextLoaded()
(10)ApplicationListener:onApplicationEvent() * 4
(11)ApplicationRunner + CommandLineRunner:根据 @Order 排序,调用 run()
(12)ApplicationListener:onApplicationEvent() * 2
(13)SpringApplicationRunListener:ready()
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战