SpringBoot - 启动过程

SpringBoot的入口是从SpringApplication.run( )方法传入我们的主启动类开始的

@SpringBootApplication
public class Web01Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(Web01Application.class, args);
    }

}

run( )方法一路点进去我们就都能得到,系统为我们创建了一个SpringBootApplication,然后把它的run( )方法跑起来了

	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).run(args);
	}

我们这次探索SpringBoot启动流程就从这里开始,我们把我们探索的步骤分为两块:

  1. SpringBootApplication对象的创建做了啥
  2. SpringBootApplication的run( )方法做了啥

SpringBootApplication对象的创建

我们就理解成SpringBoot这个应用的创建,它的构造方法如下。这里比较简单,大概做了四个事情:

  1. 把我们的web应用设置成基于Servlet实现的web应用(一个标识而已)
  2. 加载系统中引导器Bootstrapper(从系统的META-INFO/spring.factories文件中读取)
  3. 加载初始化器ApplicationContextInitializer(从系统的META-INFO/spring.factories文件中读取)
  4. 加载监听器ApplicationListener(从系统的META-INFO/spring.factories文件中读取)
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        this.resourceLoader = resourceLoader;
        Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
		//把我们的web应用设置成基于Servlet实现的web应用(一个标识而已)
        this.webApplicationType = WebApplicationType.deduceFromClasspath();

        //加载系统中引导器Bootstrapper(从系统的META-INFO/spring.factories文件中读取)
		this.bootstrapRegistryInitializers = getBootstrapRegistryInitializersFromSpringFactories();

        //加载初始化器ApplicationContextInitializer(从系统的META-INFO/spring.factories文件中读取)
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

        //加载监听器ApplicationListener(从系统的META-INFO/spring.factories文件中读取)
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

		this.mainApplicationClass = deduceMainApplicationClass();
	}

SpringBootApplication实例就创建好了,具体就是往刚刚创建的SpringBootApplication的实例中添加了一些启动器的监听、初始化器的监听、监听器,然后在下面的SpringBoot应用跑起来的过程状态、Spring的IOC容器回调出去,让编程人员做定制,做扩展

SpringBootApplication对象的run( )方法

run ( )方法内容比较多,个人总结下,这里做的事情:

  1. 通过各种的初始化器、监听器、暴露SpringBoot应用的创建过程的状态
  2. SpringBoot前期前期创建组件、环境交给Spring接管
public ConfigurableApplicationContext run(String... args) {
        //计时开始
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();

        //创建了一个DefaultBootstrapContext 对象,同时将初始化的开始的状态暴露出去
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;

        //设置成headless模式
		configureHeadlessProperty();

        //从META-INFO/spring.factories文件中获取SpringApplicationRunListener,用于暴露SpringBoot应用的运行状态
		SpringApplicationRunListeners listeners = getRunListeners(args);

        //把SpringBoot开始的状态暴露出去
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		try {

            //把main( )方法传递过来的参数封一些
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);

            //加载当前系统环境变量、和SpringBoot的配置文件的信息
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);

            //属性spring.beaninfo.ignore默认为true
			configureIgnoreBeanInfo(environment);

            //对应banner,debug的时候你放行这一步,Spring的banner就打印出来了
			Banner printedBanner = printBanner(environment);

            //返回一个基于注解的IOC容器,是AnnotationConfigServletWebServerApplicationContext类的实例
			context = createApplicationContext();

			context.setApplicationStartup(this.applicationStartup);

            //这一步做的事情主要是将刚刚加载的环境变量信息、SpringBoot的配置信息给到context、还有将一对的用于类型转换的Converter给到BeanFactory
			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
            
            //接下来就是Spring的IOC容器创建过程(就是Spring的refresh()方法),这里可以参考我之前的分析Spring的IOC容器创建过程:https://blog.csdn.net/qq_27062249/article/details/118123237
			refreshContext(context);

            //空实现,可以重写、扩展
			afterRefresh(context, applicationArguments);

            //停止计时
			stopWatch.stop();

			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}

            //调SpringApplicationRunListener的started( )方法将应用已经跑起来的状态回调出去,也是从META-INFO/spring.factories文件中获取的listener
			listeners.started(context);

            //这里调用了ApplicationRunner的实例和CommandLineRunner的实例的run()方法,这里两个类的实例都是从Spring的IOC容器中获取的
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
            //过程中出错就通过SpringApplicationRunListeners的failed( )方法将错误信息回调出去
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}

		try {
            //通过SpringApplicationRunListener将应用已经跑起来的状态回调出去
			listeners.running(context);
		}

		catch (Throwable ex) {

            //出错回调
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}

        //返回当前的Spring的IOC容器。我们在SpringBoot主启动类中可以接收试试,对应的类是:ConfigurableApplicationContext
		return context;
	}

这里需要注意的一点,如果你想自定义启动器、初始化器、监听器来监听SpringBoot的启动过程的话,一定要弄清楚SpringBoot在获取对应的实例,然后调用对应的方法的时候,是从哪里获取的。文中提到了两种方式:

  1. spring.factories文件中声明
  2. 从Spring的IOC容器中获取

猜你喜欢

转载自blog.csdn.net/qq_27062249/article/details/118398707