SpringBoot中SpringApplication.run()方法执行两遍源码

在SpringBoot中,SpringApplication.run()方法执行了两遍。具体原因是暂时不明,我们来看一下是为什么会造成这种情况。

执行两遍的起点是这行代码:

ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
1、这个方法中包含两个属性,分别是SpringApplicationRunListeners和一个我们启动的时候传入的参数,默认是没有参数传入的。

这个SpringApplicationRunListeners借鉴了Spring的ApplicationListener的方式。

传入的Listeners中只有一个Listener,就是EventPublishingRunListener,这个类的作用就是Publish SpringApplication相关的Listener

2、我们进入看看执行方法是什么样子的:

	private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		listeners.environmentPrepared(environment);
		bindToSpringApplication(environment);
		if (this.webApplicationType == WebApplicationType.NONE) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertToStandardEnvironmentIfNecessary(environment);
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
	}
这个方法中的ConfigurableEnvironment environment = getOrCreateEnvironment();这一行代码会根据是Servlet的方式选择创建不同的环境。
configureEnvironment(environment, applicationArguments.getSourceArgs());方法是做了环境的配置。默认是空的,没有配置的。

listeners.environmentPrepared(environment);

这行代码做了环境的前置配置,也是从这里开始进入SpringApplication的run()方法的。

3、EventPublishingRunListener的environmentPrepared
这个方法如下:
	@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
				this.application, this.args, environment));
	}
这个方法覆盖了父类,SpringApplicationRunLIstener类的方法,关于SpringApplicationRunListen类型,是SpringApplication的run()方法执行的过程中贯穿始终的时间监听器,有兴趣的可以去看下它的文档说明。
SpringApplicationRunLIstener的environmentPrepared(ConfigurableEnvironment environment)是在环境已经准备好,ApplicationContext还未创建的时候执行的。
这个项目中创建了ApplicationEnvironmentPreparedEvent事件,并发布了这个事件。

4、接着进入了SimpleApplicationEventMulticaster的multicastEvent方法
SimpleApplicationEventMulticaster类是查找订阅对应event的Listenr并执行Listener的类,其代码如下:
	@Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			Executor executor = getTaskExecutor();
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}
getApplicationListeners(event, type)方法就是查找了订阅这个event的listener,然后执行了invokeListener(listener, event);方法,
找到的对应这个事件的Listener为BootstrapApplicationListener.

5、然后进入到了BootstrapApplicationListener类的onApplicationEvent(ApplicationEnvironmentPreparedEvent event)方法,真正执行的是下面这行代码:
		if (context == null) {
			context = bootstrapServiceContext(environment, event.getSpringApplication(),
					configName);
		}
这个方法也是区分,为什么SpringApplication的run()方法只会进来一次的方法。也是初始化ApplicationContext的方法。其中event.getSpringApplication()方法获取到的是SpringApplicationRunListener类中的SpringApplication

6、然后在bootstrapServiceContext()方法中进行了环境的设置,在这个方法中使用到了一个类型叫做SpringApplicationBuilder,最后调用了这个Builder类型的run()方法,如下:
	public SpringApplication build(String... args) {
		configureAsChildIfNecessary(args);
		this.application.addPrimarySources(this.sources);
		return this.application;
	}
这个application是在创建SpringApplicationBuilder类型的时候载入的,如下:
	public SpringApplicationBuilder(Class<?>... sources) {
		this.application = createSpringApplication(sources);
	}
是一个新的SpringApplication。
自此就解析完了,为什么SpringApplication为什么会走两遍,同时注意的是BootstrapApplicationListener类是spring-cloud-contextjar包中的一个类型,如果没有引入spring-cloud也是不会走两遍的。

猜你喜欢

转载自blog.csdn.net/lz710117239/article/details/80444200