我们对SpringApplication中的run()方法内部进行一些简单的分析
1.
//记录一下程序启动开始的事件,用于之后的统计耗时
long startTime = System.nanoTime();
//通过调用SpringApplication的**createBootstrapContext()**方法,创建**bootstrapContext**对象
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
//配置系统属性**java.awt.headless**,适用于没有显示器的服务器配置
this.configureHeadlessProperty();
//创建启动监听器
//starting方法通知所有的监听器,Spring Boot项目将启动,其实底层是调用EventPublishingRunListener通过多播机制来触发多个监听器的回调,意思就是一个事件可以通知多个监听器的执行
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
扩展:然后我们在对 SpringApplication的createBootstrapContext()方法进行底层分析
//创建上下文context对象,遍历**bootstrapRegistryInitializers**中的每一个初始化器来对**bootstrapContext**进行初始化构造
private DefaultBootstrapContext createBootstrapContext() {DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();this.bootstrapRegistryInitializers.forEach((initializer) -> {initializer.initialize(bootstrapContext);});return bootstrapContext;
}
2.
//将args封装成ApplicationArguments主要是处理一些带前缀的选项参数(以--或-开头的参数,例如--port=8080)和非选项参数(没有前缀,例 如config.txt),就可以不用我们自己解析
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//主要是准备并配置Spring Boot程序的环境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
this.configureIgnoreBeanInfo(environment);
Banner printedBanner = this.printBanner(environment);
//- 创建ApplicationContext上下文,启动监听器,收集应用启动过程中的数据
- prepareContext方法底层配置环境,注入依赖,调用初始化器,发布事件监听等功能
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//启动Spring核心容器,完成Bean的初始化,然后进行回调,执行一些自定义的逻辑
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
}
//通知监听器,应用程序启动完成
listeners.started(context, timeTakenToStartup);
扩展:其中 看一下prepareEnvironment方法
-
通过getOrCreateEnvironment方法 创建ConfigurableEnvironment,配置环境属性
-
attach底层实现就是确保数据源的一致性和更新,然后将最新的数据源放到优先的位置
-
之后listeners会发布(触发)一个环境准备完毕的事件
-
然后将新的配置源附加到Spring的环境中
3.最后条用实现CommandLineRunner和ApplicationRunner接口的Bean,两个接口在应用程序启动完成后执行一些初始化逻辑