一.启动流程:(源码深度解析)
,
Springboot启动流程就是这两个核心方法,一个是new SpringApplication()构造方法,一个是上面的run()方法。
1.构造方法SpringApplication()
源码:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 初始化变量并设置默认值
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = Collections.emptySet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
this.applicationStartup = ApplicationStartup.DEFAULT;
this.resourceLoader = resourceLoader;
// 检查 primarySources 参数是否为空,如果为空则抛出异常
Assert.notNull(primarySources, "PrimarySources must not be null");
// 将主要来源(primarySources)添加到一个 LinkedHashSet 集合中
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
// 推断 web 应用程序类型(Servlet、Reactive 或无 Web 环境)
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 获取并初始化 BootstrapRegistryInitializer
this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
// 获取并设置 ApplicationContextInitializer
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 获取并设置 ApplicationListener
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
// 推断应用程序的主类
this.mainApplicationClass = this.deduceMainApplicationClass();
}
主要有一下几个主要的步骤:
1.确认web应用类型
2.加载ApplicationInitializer
3.记载ApplicationLinstener
4.记录主启动类
2.run()方法
首先看源码:
public ConfigurableApplicationContext run(String... args) {
// 获取程序启动时间
long startTime = System.nanoTime();
// 创建 BootstrapContext 对象
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
// 配置 Headless 属性
this.configureHeadlessProperty();
// 获取 SpringApplicationRunListeners 对象并执行 starting 方法,记录监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 创建 ApplicationArguments 对象并准备环境
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 打印 Banner
Banner printedBanner = this.printBanner(environment);
// 创建 ApplicationContext,声明一个容器变量context
ConfigurableApplicationContext context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
// 准备上下文,包括设置环境、初始化器、监听器等
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 刷新 ApplicationContext
this.refreshContext(context);
// 在刷新后执行其他操作
this.afterRefresh(context, applicationArguments);
// 计算启动时间
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
// 如果 logStartupInfo 为 true,则记录启动信息日志
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
}
// 执行 started 方法
listeners.started(context, timeTakenToStartup);
// 调用运行器
this.callRunners(context, applicationArguments);
} catch (Throwable var12) {
// 处理运行失败的情况
if (var12 instanceof AbandonedRunException) {
throw var12;
}
this.handleRunFailure(context, var12, listeners);
throw new IllegalStateException(var12);
}
try {
// 如果 ApplicationContext 运行中,则执行 ready 方法
if (context.isRunning()) {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
return context;
} catch (Throwable var11) {
// 处理运行失败的情况
if (var11 instanceof AbandonedRunException) {
throw var11;
} else {
this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var11);
}
}
}
总的来说,主要有如下几个主要的步骤:
1.准备环境对象,Environment,用于加载对象属性,
2.打印Banner
3.实例化一个容器Context
4.接下来准备容器,为容器设置Environment,BeanFactory,
5.刷新容器
6.最后返回
3.情景再现
HR:说一下Springboot的启动流程?
你:
Spring boot启动,其本质就是加载各种的配置信息,然后初始化容器并返回。
在启动的过程中主要有一下步骤,
首先,当我们在启动类里面执行SpringApplication.run()这行代码时候,在方法内部会做两个事情, 1.创建SpringApplication对象,
2.执行run()方法
其次在创建对象的时候,在构造方法的内部主要有3个步骤:
1.确认web的应用类型,是servlet或者是无web类型,如果是前者,会自动启动一个tomcat
2.在spring.factories中,加载默认的ApplicationInitializer和ApplicationListener等
3.记录当前应用的启动类
最后当对象创建好了之后会调用run()方法,而在run()方法中主要执行以下步骤:
1.准备Environment环境对象,它封装了一些当前应用运行的环境参数,比如环境变量,
2.实例化容器,这个步骤仅仅是创建ApplicationContext容器
3.创建好容器之后会为容器做准备工作,比如加载BeanFactoryPostProcessor后置处理器,并加 载主类对应的Definition
4.刷新容器,此时真正创建Bean实例
总结:
其实核心就两步骤,一个是创建Spring Application对象以及run方法的调用,在run方法中会实例化容器,并且创建需要的Bean实例