SpringBoot原理——启动流程

网上有一个总结非常好的图
SpringBoot原理——启动流程_第1张图片

每个SpringBoot程序都有一个主入口,也就是main方法,main里面调用SpringApplication.run()启动。

	public ConfigurableApplicationContext run(String... args) {
		//StopWatch一个用于记录人物开始和结束时间的类
   	StopWatch stopWatch = new StopWatch();
   	stopWatch.start();
   	ConfigurableApplicationContext context = null;
   	FailureAnalyzers analyzers = null;
   	configureHeadlessProperty();
   	//创造了应用监听器,并开始监听过程
   	SpringApplicationRunListeners listeners = getRunListeners(args);
   	listeners.starting();
   	
   	try {
   		ApplicationArguments applicationArguments = new DefaultApplicationArguments(
   				args);
   		//配置SpringBoot的应用环境		
   		ConfigurableEnvironment environment = prepareEnvironment(listeners,
   				applicationArguments);
   		//打印Banner(就是启动的那个图案,如果你信佛,可以自定义个如来佛祖打在启动控制台)		
   		Banner printedBanner = printBanner(environment);
   		//初始化容器
   		context = createApplicationContext();
   		//错误分析机制,只有在抛出异常时才会用到。
   		analyzers = new FailureAnalyzers(context);
   		prepareContext(context, environment, listeners, applicationArguments,
   				printedBanner);
   		//调用((AbstractApplicationContext) applicationContext).refresh();		
   		refreshContext(context);
   		afterRefresh(context, applicationArguments);
   		listeners.finished(context, null);
   		stopWatch.stop();
   		//是否打印启动信息日志,可以通过SpringApplicationBuilder进行设置。
   		if (this.logStartupInfo) {
   			new StartupInfoLogger(this.mainApplicationClass)
   					.logStarted(getApplicationLog(), stopWatch);
   		}
   		return context;
   	}
   	catch (Throwable ex) {
   		handleRunFailure(context, listeners, analyzers, ex);
   		throw new IllegalStateException(ex);
   	}
   }

SpringApplicationRunListener

这个是SpringBoot自己为Spring生态贡献的类。相当于对Spring中的ApplicationListener。

public interface SpringApplicationRunListener {

    /**
     * Called immediately when the run method has first started. Can be used for very
     * early initialization.
     */
    void starting();

    /**
     * Called once the environment has been prepared, but before the
     * {@link ApplicationContext} has been created.
     * @param environment the environment
     */
    void environmentPrepared(ConfigurableEnvironment environment);

    /**
     * Called once the {@link ApplicationContext} has been created and prepared, but
     * before sources have been loaded.
     * @param context the application context
     */
    void contextPrepared(ConfigurableApplicationContext context);

    /**
     * Called once the application context has been loaded but before it has been
     * refreshed.
     * @param context the application context
     */
    void contextLoaded(ConfigurableApplicationContext context);

    /**
     * The context has been refreshed and the application has started but
     * {@link CommandLineRunner CommandLineRunners} and {@link ApplicationRunner
     * ApplicationRunners} have not been called.
     * @param context the application context.
     * @since 2.0.0
     */
    void started(ConfigurableApplicationContext context);

    /**
     * Called immediately before the run method finishes, when the application context has
     * been refreshed and all {@link CommandLineRunner CommandLineRunners} and
     * {@link ApplicationRunner ApplicationRunners} have been called.
     * @param context the application context.
     * @since 2.0.0
     */
    void running(ConfigurableApplicationContext context);

    /**
     * Called when a failure occurs when running the application.
     * @param context the application context or {@code null} if a failure occurred before
     * the context was created
     * @param exception the failure
     * @since 2.0.0
     */
    void failed(ConfigurableApplicationContext context, Throwable exception);
}

SpringApplicationRunListener 接口的作用主要就是在springboot 启动初始化的过程中可以通过SpringApplicationRunListener接口回调来让用户在启动的各个流程中可以加入自己的逻辑。可以SpringBoot的源代码在启动流程中详细查看这些listener被触发的时间。请参考参考文献1。

prepareEnvironment

SpringApplication在初始化时,有如下,需要判断本工程是不是WEB工程。方法就是查看是否拥有Web工程所需要的所有的类。

	private boolean deduceWebEnvironment() {
		for (String className : WEB_ENVIRONMENT_CLASSES) {
			if (!ClassUtils.isPresent(className, null)) {
				return false;
			}
		}
		return true;
	}

然后,根据这个判断准备当前的运行环境

	private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		listeners.environmentPrepared(environment);
		if (isWebEnvironment(environment) && !this.webEnvironment) {
			environment = convertToStandardEnvironment(environment);
		}
		return environment;
	}

createApplicationContext

简单来说就是创建应用上下文。
根据SpringApplication的webApplicationType来实例化对应的上下文

  • 如果webApplicationType的值是SERVLET,那么实例化AnnotationConfigServletWebServerApplicationContext
  • 如果是REACTIVE则实例化AnnotationConfigReactiveWebServerApplicationContext(响应式编程,后续再看)。此时程序一般是不依赖SpringMVC,而是Spring WebFlux。
  • 如果既不是SERVLET、也不是REACTIVE,那么则是默认情况(也就是我们所说的非web应用),实例化AnnotationConfigApplicationContext。

参考文献

【1】https://www.jianshu.com/p/308534c60b11

你可能感兴趣的:(java)