SpringApplication.run执行流程

1.这个方法里面首先创建一个SpringApplication对象实例,然后调用这个创建好的SpringApplication的实例方法。在SpringApplication实例初始化的时候,它会提前做几件事情:

@SuppressWarnings({ "unchecked", "rawtypes" })
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		//把sources设置到SpringApplication的sources属性中
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		this.webApplicationType = deduceWebApplicationType();
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		this.mainApplicationClass = deduceMainApplicationClass();
	}

(1)根据classpath里面是否存在某个特征类来决定web应用类型,这个类型会用来创建相应的ApplicationContext

(2)使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer.

(3)使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener.

(4)推断并设置main方法的定义类。

public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			refreshContext(context);
			afterRefresh(context, applicationArguments);
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

 

2. SpringApplication实例初始化完成并且完成设置后,就开始执行run方法的逻辑了,首先遍历所有通过SpringFactoriesLoader加载的SpringApplicationRunListener,调用它们的started方法。

 

3. 创建并配置当前Spring Boot应用将要使用的Environment

4. 遍历调用所有SpringApplicationRunListener的environmentPrepared()的方法

5. 如果SpringApplication的showBanner属性被设置为true,则打印banner

6. 根据用户是否明确设置了applicationContextClass类型以及初始化阶段的推断结果,决定该为当前SpringBoot应用创建什么类型的ApplicationContext,然后根据条件决定是否添加ShutdownHook,决定是否使用自定义的BeanNameGenerator,决定是否使用自定义的ResourceLoader,最重要的,是将之前准备好的Environment设置给创建好的ApplicationContext使用。

7. ApplicationContext创建好之后,SpringApplication会再次借助Spring-FactoriesLoader,查找并加载classpath中所有可用的ApplicatinContext-Initializer,然后遍历调用这些ApplicationContextInitializer的initialize(applicationContext)方法对已经创建好的ApplicationContext进行进一步的处理。

8.遍历调用所有SpringApplicationRunListener的contextPrepared()方法。

9. 最核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext。

10. 遍历调用所有SpringApplicationRunListener的contextLoaded()方法。

11.调用ApplicationContext的refresh()方法,完成IoC容器可用的最后上道工序。

12. 查找当前ApplicationContext中是否注册有CommandLineRunner,如果有,则遍历执行它们。

13. 正常情况下,遍历执行SpringApplicationRunListener的方法表示启动完成(如果整个过程出现异常,会把异常信息也传给listener)

 

最后欢迎大家访问我的个人网站:1024s​​​​​​​

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值