[笔记迁移][SpringBoot]Spring Boot启动配置原理[6]

15 篇文章 0 订阅

主配置类(标注了@SpringBootApplication)的main中,SpringApplication.run(主配置类名.class,args)就是分析入口。
总体来说,SpringBoot启动流程分为了两步:

  • 创建SpringApplication对象。
  • 调用这个对象的run方法。
	//SpringApplication.java
    public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
        return (new SpringApplication(sources)).run(args);
    }

1. SpringApplication的创建

由SpringApplication构造器调用的核心方法initialize。

//SpringApplication.java
	private void initialize(Object[] sources) {
      //1. 保存主配置类
        if (sources != null && sources.length > 0) {
            this.sources.addAll(Arrays.asList(sources));
        }

      //2. 判断当前应用是否为WebApplication,源码中的逻辑:是否导入"javax.servlet.Servlet"和"org.springframework.web.context.ConfigurableWebApplicationContext",存在便是WebApplication
        this.webEnvironment = this.deduceWebEnvironment();
       
 	  //3. 从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer后保存起来。(getSpringFactoriesInstance底层的核心调用是SpringFactoriesLoader.loadFactoryNames)【保存的结果见图一】
      this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
 	  //4. 从类路径下找到META-INF/spring.factories配置的所有ApplicationListener(与第三步的操作是相同的)【保存的结果见图二】      
      this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
      //5. 从多个配置类中找到带main()的主配置类
        this.mainApplicationClass = this.deduceMainApplicationClass();
    }

ApplicationContextInitializer
ApplicationListener

2. 创建好的SpringApplication调用run()启动

   public ConfigurableApplicationContext run(String... args) {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        
      	//1. IoC引用声明
        ConfigurableApplicationContext context = null;
        
        FailureAnalyzers analyzers = null;
        this.configureHeadlessProperty();
      	
      	//2. 获取SpringApplicationListeners,还是通过getSpringFactoriesInstance从类路径下找到META-INF/spring.factories配置的所有ApplicationListener。
        SpringApplicationRunListeners listeners = this.getRunListeners(args);
         
        //3. 回调所有SpringApplicationRunListeners的starting()=====
      	listeners.starting();

        try {
        
          	//4. 封装命令行参数
            ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            
          	//5.准备环境
          	/*
          	 * 5.1 getOrCreateEnvironment()创建IoC容器运行环境(包括activeProfiles、defaultProfiles、propertySources、propertyResolver)完成后
          	 * 5.2 回调所有SpringApplicationRunListener的environmentPrepared(),表示环境准备完成
          	 */
            ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
          	
          	//6. 控制台图标打印
            Banner printedBanner = this.printBanner(environment);
            
          	//7. 反射创建对应的IoC容器(Web的IoC还是普通的IoC?)
            context = this.createApplicationContext();
            
            analyzers = new FailureAnalyzers(context);
          	
          	//8. 准备上下文
          	/*
          	 * 8.1 保存Environment到IoC容器  context.setEnvironment(environment);
          	 * 8.2 applyInitializers(),回调ApplicationContextInitilizer(在创建SpringApplication阶段保存的所有初始化器)的initialize()
          	 * 8.3 listeners.contextPrepared(),回调所有SpringApplicationRunListener(在创建SpringApplication阶段保存的所有listeners)的contextPrepared()
          	 * 8.4 最后一步listeners.contextLoad()将回调所有SpringApplicationRunListener.contextLoaded()
          	 */
            this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);


          	//9. 刷新容器:IoC容器初始化(扫描、加载、创建IoC容器中所有组件,包括所有普通配置类、自动配置类、所有@Bean...) -> Sping原理refresh
          	//如果是Web应用,那嵌入式的Tomcat创建与启动在这一步完成
            this.refreshContext(context);
            
          	//10. 从IoC容器中获取所有的ApplicationRunner和CommandLineRunner,先后回调callRunner(),也就是具备优先级
            this.afterRefresh(context, applicationArguments);
            
          	//11. 回调所有SpringApplicationRunListener(在创建SpringApplication阶段保存的所有listeners)的finish()
            listeners.finished(context, (Throwable)null);
            
            stopWatch.stop();
            if (this.logStartupInfo) {
                (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
            }
		   
		   //12. 整个Spring Boot应用启动完成后返回IoC容器
            return context;
        } catch (Throwable var9) {
            this.handleRunFailure(context, listeners, (FailureAnalyzers)analyzers, var9);
            throw new IllegalStateException(var9);
        }
    }

3. 添加自定义的事件监听

  1. 实现接口之后,还要配置在类路径下的META-INF/spring.factories中(需要手动创建目录和文件,文件的编写参考spring-boot-autoconfigure包下的META-INF/spring.factories)

    (1)ApplicationContextInitializer。
    (2)SpringApplicationRunListener,必须声明一个有参构造器(两个参数的类型:SpringApplication,String[])。

  2. 实现接口之后, 只需要放在IoC容器中(@Component)
    (1)ApplicationRunner
    (2)CommandLineRunner

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值