SpringBoot源码学习之路(十六、启动原理(运行流程分析、自定义事件监听回调机制)))

运行流程分析、自定义事件监听回调机制

一、运行流程分析

1、启动流程:

首先观察SpringBoot启动类源码:

SpringApplication.run(SpringbootDemoApplication.class, args);

//进入run方法===》发现:

     public static ConfigurableApplicationContext run(Object source, String... args) {
            return run(new Object[]{source}, args);
        }

        //再进入run方法===》发现:

        public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
                return (new SpringApplication(sources)).run(args);
            }

由最后的方法可以发现,启动应用主要做了两件事:①、创建SpringApplication对象;②、运行run方法。
对此进行分析:


①、创建SpringApplication对象:(initialize(sources))

private void initialize(Object[] sources) {
    /* 1、保存主配置类 */
    if (sources != null && sources.length > 0) {
        this.sources.addAll(Arrays.asList(sources));
    }
    /*2、判断当前是否一个web应用*/
    this.webEnvironment = deduceWebEnvironment();
    //3、从依赖包类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来
    setInitializers((Collection) getSpringFactoriesInstances(
        ApplicationContextInitializer.class));
    //4、从依赖包类路径下找到META-INF/spring.factories配置的所有ApplicationListener
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //5、从多个配置类中找到有main方法的主配置类
    this.mainApplicationClass = deduceMainApplicationClass();
}

通过源码可以发现其有两个关键点:(附断点调试截图)
保存所有的ApplicationContextInitializer:
这里写图片描述
保存所有的ApplicationListener
这里写图片描述

到此SpringApplication对象就创建完了,接下来就运行其run方法。


②、运行run方法:

public ConfigurableApplicationContext run(String... args) {
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   //1、声明一个空的IOC容器
   ConfigurableApplicationContext context = null;
   FailureAnalyzers analyzers = null;
   configureHeadlessProperty();

   //2、获取SpringApplicationRunListeners;从类路径下META-INF/spring.factories
   SpringApplicationRunListeners listeners = getRunListeners(args);
    //3、回调所有的获取SpringApplicationRunListener.starting()方法
   listeners.starting();
   try {
       //4、封装传入的命令行参数
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      //5、准备环境:创建环境完成后回调SpringApplicationRunListener.environmentPrepared(),表示环境准备完成
      ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);

      //6、打印banner信息(就是spring的图标,可以自己替换)
      Banner printedBanner = printBanner(environment);

       //7、创建ApplicationContext;决定创建web的IOC还是普通的IOC
      context = createApplicationContext();

      //8、用来处理异常错误报告的,【catch】模块中使用
      analyzers = new FailureAnalyzers(context);


       //9、准备上下文环境;将【environment】对象保存到IOC中;
       //回调第一步中保存的所有的【ApplicationContextInitializer】的【initialize()】方法
       //回调所有第一步中保存的【SpringApplicationRunListener】的【contextPrepared()】方法;
      prepareContext(context, environment, listeners, applicationArguments,printedBanner);
       //10、【prepareContext()】运行完成以后回调所有的第一步中保存的【SpringApplicationRunListener】的【contextLoaded()】方法;

       //11、刷新容器:既开始IOC容器初始化(如果是web应用还会创建嵌入式的Tomcat);
       //12、扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
       refreshContext(context);

       //13、从IOC容器中获取所有的【ApplicationRunner】和【CommandLineRunner】进行回调
       //【ApplicationRunner】先回调,【CommandLineRunner】再回调
      afterRefresh(context, applicationArguments);

       //14、所有的【SpringApplicationRunListener】回调【finished()】方法
      listeners.finished(context, null);


      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass)
               .logStarted(getApplicationLog(), stopWatch);
      }
       //15、整个SpringBoot应用启动完成以后返回IOC容器;
      return context;
   }
   catch (Throwable ex) {
      handleRunFailure(context, listeners, analyzers, ex);
      throw new IllegalStateException(ex);
   }
}

2、事件回调机制:

由上述源码run()方法中发现几个重要的事件回调机制:

类型 描述 获取方式
ApplicationContextInitializer IOC容器初始化时被回调 需要配置在META-INF/spring.factories,因为SpringBoot启动流程中是从spring.factories中获取的
SpringApplicationRunListener SpringBoot启动过程中多次被回调 需要配置在META-INF/spring.factories,因为SpringBoot启动流程中是从spring.factories中获取的
ApplicationRunner 容器启动完成后被回调 需要放在IOC容器中,因为SpringBoot启动流程中是从IOC容器中取出的
CommandLineRunner ApplicationRunner之后被回调 需要放在IOC容器中,因为SpringBoot启动流程中是从IOC容器中取出的

二、自定义事件监听机制

1、ApplicationContextInitializer(配置在META-INF/spring.factories)

①、创建自定义ApplicationContextInitializer:

public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    @Override
    /* 初始化时会执行,并传入容器 */
    public void initialize(ConfigurableApplicationContext applicationContext) {
        System.out.println("【初始化时】 -------  ApplicationContextInitializer...initialize..."+applicationContext);
    }
}

②、配置META-INF/spring.factories
resources文件夹下创建文件夹META-INF,而后在创建文件spring.factories

#仿照依赖包中配置方式,第一行【接口】第二行【实现类】
org.springframework.context.ApplicationContextInitializer=\
com.wangcw.springboot.listener.MyApplicationContextInitializer

2、SpringApplicationRunListener(配置在META-INF/spring.factories)

①、创建自定义SpringApplicationRunListener:

public class MySpringApplicationRunListener implements SpringApplicationRunListener {

    //必须有的构造器,否则启动会报错
    public MySpringApplicationRunListener (SpringApplication application, String[] args){

    }

    /* 有启动流程分析可知,其执行顺序是由上至下的 */
    @Override
    public void starting() {
        System.out.println("【应用运行监听】----------SpringApplicationRunListener...starting...");
    }

    /* 参数传入环境信息 */
    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        Object o = environment.getSystemProperties().get("os.name");
        System.out.println("【应用运行监听】----------SpringApplicationRunListener...environmentPrepared.."+o);
    }

    /* 参数传入容器 */
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("【应用运行监听】----------SpringApplicationRunListener...contextPrepared...");
    }

    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("【应用运行监听】----------SpringApplicationRunListener...contextLoaded...");
    }

    @Override
    public void finished(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("【应用运行监听】----------SpringApplicationRunListener...finished...");
    }
}

②、配置META-INF/spring.factories

扫描二维码关注公众号,回复: 2717193 查看本文章
#仿照依赖包中配置方式,第一行【接口】第二行【实现类】
org.springframework.context.ApplicationContextInitializer=\
com.wangcw.springboot.listener.MyApplicationContextInitializer

org.springframework.boot.SpringApplicationRunListener=\
com.wangcw.springboot.listener.MySpringApplicationRunListener

3、ApplicationRunner(只需要放在ioc容器中)

创建ApplicationRunner并加入到容器即可。

@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("【容器启动完成后被回调】--------------ApplicationRunner...run....");
    }
}

4、CommandLineRunner(只需要放在ioc容器中)

创建CommandLineRunner并加入到容器即可。

@Component
public class HelloCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("【容器启动完成后被回调】--------------CommandLineRunner...run..."+ Arrays.asList(args));
    }
}

启动验证即可!

猜你喜欢

转载自blog.csdn.net/qq_33404395/article/details/81203107
今日推荐