SpringBoot项目引入SpringClouds时run方法被执行的两次解析
在没用引入SpringCloud之前,可以看到environment资源实例是:StandardServletEnvironment
引入SpringClound之后,会发现第一次environment资源实例是:StandardEnvironment,第二次资源实例才是StandardServletEnvironment
疑惑: 为什么会出现这种情况呢?
让我们来一步步分析:
1.首先将断点定格在
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
2.查看prepareEnvironment方法中
listeners.environmentPrepared(environment);
3.此刻会调用SpringApplicationRunListeners类中environmentPrepared方法
void environmentPrepared(ConfigurableEnvironment environment) {
//this.listeners只存在一个值,那就是EventPublishingRunListener
for (SpringApplicationRunListener listener : this.listeners) {
listener.environmentPrepared(environment);
}
}
4.从上得知,最终实际是调用了EventPublishingRunListener中的environmentPrepared
public void environmentPrepared(ConfigurableEnvironment environment) {
//initialMulticaster为SimpleApplicationEventMulticaster实例
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));}
5.那我们接着进入SimpleApplicationEventMulticaster的multicastEvent方法
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
//此方法getApplicationListeners会获取到创建SpringApplication实例时设置的listener属性,参照setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
//首先会调用BootstrapApplicationListener中的onApplicationEvent方法
invokeListener(listener, event);
}
}
}
6.此刻进入到BootstrapApplicationListener类中的onApplicationEvent方法
context = bootstrapServiceContext(environment, event.getSpringApplication(),
configName);
7.经过一顿操作后执行bootstrapServiceContext方法,关键是下面一段代码
final ConfigurableApplicationContext context = builder.run();
8.执行了builder.run()方法,即重新执行了SpringApplication中的run方法(类似递归调用,但实际是不同对象)
9.在启动参数中添加-Dspring.cloud.bootstrap.enabled = false来关闭引导类启动(操作如下图),该参数不能放在配置文件中,因为在启动bootstrap时,还未对配置文件进行加载
至此分享到这。。。