本文共 4293 字,大约阅读时间需要 14 分钟。
SpringApplication的run方法的实现是我们本次旅程的主要线路,该方法的主要流程大体可以归纳如下:
org.springframework.web.context.ConfigurableWebApplicationContext
来决定是否应该创建一个为Web应用使用的ApplicationContext类型。 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationContextInitializer
。 使用SpringFactoriesLoader在应用的classpath中查找并加载所有可用的ApplicationListener
。 推断并设置main方法的定义类。public class SpringApplication { // ... public SpringApplication(ResourceLoader resourceLoader, Class ... primarySources) { this.resourceLoader = resourceLoader; Assert.notNull(primarySources, "PrimarySources must not be null"); this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); this.webApplicationType = deduceWebApplicationType(); // 查找并加载所有可用的ApplicationContextInitializer setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 查找并加载所有可用的ApplicationListener setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = deduceMainApplicationClass(); }}
SpringFactoriesLoader
可以查找到并加载的SpringApplicationRunListener
。调用它们的started()方法,告诉这些SpringApplicationRunListener
,“嘿,SpringBoot应用要开始执行咯!”。Environment
(包括配置要使用的PropertySource以及Profile)。SpringApplicationRunListener
的environmentPrepared()
的方法,告诉他们:“当前SpringBoot应用使用的Environment准备好了咯!”。SpringApplication
的showBanner
属性被设置为true
,则打印banner
。applicationContextClass
类型以及初始化阶段的推断结果,决定该为当前SpringBoot应用创建什么类型的ApplicationContext并创建完成,然后根据条件决定是否添加ShutdownHook
,决定是否使用自定义的BeanNameGenerator
,决定是否使用自定义的ResourceLoader
,当然,最重要的,将之前准备好的Environment设置给创建好的ApplicationContext使用。SpringFactoriesLoader
,查找并加载classpath中所有可用的ApplicationContextInitializer
,然后遍历调用这些ApplicationContextInitializer的initialize(applicationContext)
方法来对已经创建好的ApplicationContext进行进一步的处理。SpringApplicationRunListener
的contextPrepared()
方法。@EnableAutoConfiguration
获取的所有配置以及其他形式的IoC容器配置加载到已经准备完毕的ApplicationContext。SpringApplicationRunListener
的contextLoaded()
方法。ApplicationContext
的refresh()
方法,完成IoC容器可用的最后一道工序。ApplicationContext
中是否注册有CommandLineRunner
,如果有,则遍历执行它们。SpringApplicationRunListener
的finished()
方法、(如果整个过程出现异常,则依然调用所有SpringApplicationRunListener的finished()方法,只不过这种情况下会将异常信息一并传入处理)Spring 源码:
public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; CollectionexceptionReporters = new ArrayList<>(); configureHeadlessProperty(); // SpringFactoriesLoader => META-INF/spring.factories SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args); // 环境配置 None(非WEB), Servlet, Reactive(响应式) ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); configureIgnoreBeanInfo(environment); // Banner Banner printedBanner = printBanner(environment); context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); prepareContext(context, environment, listeners, applicationArguments, printedBanner); // IOC容器的最后一步 refreshContext(context); afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } listeners.started(context); // 查找 CommandLineRunner, ApplicationRunner, ... 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; }
转载地址:http://lvxzb.baihongyu.com/