springboot 启动分析六

2018-10-21  本文已影响8人  0爱上1

承接启动分析五,本文继续探索springboot的启动之旅

该文主要分析上下文刷新完成之后做了哪些工作

public ConfigurableApplicationContext run(String... args) {

    // 声明并实例化一个跑表,用于计算springboot应用程序启动时间
    StopWatch stopWatch = new StopWatch();

    // 启动跑表
    stopWatch.start();

    // 声明一个应用程序上下文,注意这里是一个接口声明
    ConfigurableApplicationContext context = null;

    // 声明一个集合,用于记录springboot异常报告
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();

    // 配置不在意的属性 java.awt.headless
    configureHeadlessProperty();

    // 获取用于监听spring应用程序run方法的监听器实例
    SpringApplicationRunListeners listeners = getRunListeners(args);

    // 循环启动用于run方法的监听器
    listeners.starting();
    try {
        // 封装应用参数
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(
                args);

        // 根据SpringApplication实例化时候推断出来的应用类型 webApplicationType,
        // 去获取不同的环境,然后获取配置要适用的PropertySource以及激活哪个Profile
        ConfigurableEnvironment environment = prepareEnvironment(listeners,
                applicationArguments);

        // 根据环境配置需要忽略的bean的信息
        configureIgnoreBeanInfo(environment);

        // 根据环境配置打印banner,即根据bannerMode 枚举值,决定是否打印banner和banner打印的位置
        Banner printedBanner = printBanner(environment);

        // key 4 创建应用程序上下文,
        context = createApplicationContext();
        exceptionReporters = getSpringFactoriesInstances(
                SpringBootExceptionReporter.class,
                new Class[]{ConfigurableApplicationContext.class}, context);
        // key 5 准备应用上下文
        prepareContext(context, environment, listeners, applicationArguments,
                printedBanner);
        // key 6 刷新上下文      
        refreshContext(context);
        // key 7 处理刷新上下文之后的事情
        afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            new StartupInfoLogger(this.mainApplicationClass)
                    .logStarted(getApplicationLog(), stopWatch);
        }
        // key 8 上下文启动完成发布事件
        listeners.started(context);
        // key 9
        callRunners(context, applicationArguments);
    } catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, listeners);
        throw new IllegalStateException(ex);
    }

    try {
        // key 10
        listeners.running(context);
    } catch (Throwable ex) {
        handleRunFailure(context, ex, exceptionReporters, null);
        throw new IllegalStateException(ex);
    }
    return context;
}

key7 刷新之后 afterRefresh(context, applicationArguments)

这里其实方法是空的,没有作任何的事

protected void afterRefresh(ConfigurableApplicationContext context,
        ApplicationArguments args) {
}

key 8 上下文刷新完成,应用程序已经启动,事件发布

但此时 CommandLineRunners和ApplicationRunners还没有被回调

public void started(ConfigurableApplicationContext context) {
    context.publishEvent(
            new ApplicationStartedEvent(this.application, this.args, context));
}

跟踪代码看到最后发布事件之前只有两个Listener感兴趣ApplicationStartedEvent事件

感兴趣ApplicationStartedEvent事件的监听器

BackgroundPreinitializer

在耗时任务的后台线程中触发早期初始化

public void onApplicationEvent(SpringApplicationEvent event) {
    if (event instanceof ApplicationStartingEvent
            && preinitializationStarted.compareAndSet(false, true)) {
        performPreinitialization();
    }
    if ((event instanceof ApplicationReadyEvent
            || event instanceof ApplicationFailedEvent)
            && preinitializationStarted.get()) {
        try {
            preinitializationComplete.await();
        }
        catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
        }
    }
}

可以看到这里两个if都没有进入

DelegatingApplicationListener

委托给其他监听器处理事件

public void onApplicationEvent(ApplicationEvent event) {
    if (event instanceof ApplicationEnvironmentPreparedEvent) {
        List<ApplicationListener<ApplicationEvent>> delegates = getListeners(
                ((ApplicationEnvironmentPreparedEvent) event).getEnvironment());
        if (delegates.isEmpty()) {
            return;
        }
        this.multicaster = new SimpleApplicationEventMulticaster();
        for (ApplicationListener<ApplicationEvent> listener : delegates) {
            this.multicaster.addApplicationListener(listener);
        }
    }
    if (this.multicaster != null) {
        this.multicaster.multicastEvent(event);
    }
}

这里也没有作什么事情,继续往下看

key 9 callRunners

private void callRunners(ApplicationContext context, ApplicationArguments args) {
    List<Object> runners = new ArrayList<>();
    runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
    runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
    AnnotationAwareOrderComparator.sort(runners);
    for (Object runner : new LinkedHashSet<>(runners)) {
        if (runner instanceof ApplicationRunner) {
            callRunner((ApplicationRunner) runner, args);
        }
        if (runner instanceof CommandLineRunner) {
            callRunner((CommandLineRunner) runner, args);
        }
    }
}
  1. 从上下文中获取ApplicationRunner类型的bean,以及CommandLineRunner类型的bean

  2. 排序

  3. 依次调用其run方法,并传入相应的参数

     private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
     try {
         (runner).run(args);
     }
     catch (Exception ex) {
         throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
     }
     }
    
     private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
     try {
         (runner).run(args.getSourceArgs());
     }
     catch (Exception ex) {
         throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
     }
     }
    

至此,整个callRunners方法就分析完毕

key 10 listeners.running(context)

发布上下文ApplicationReadyEvent事件

public void running(ConfigurableApplicationContext context) {
    context.publishEvent(
            new ApplicationReadyEvent(this.application, this.args, context));
}

这里可以看到有三个监听器感兴趣该事件

ApplicationReadyEvent

前两个事件分析过了,重点看一下第三个事件

ApplicationListenerMethodAdapter

public void onApplicationEvent(ApplicationEvent event) {
    this.processEvent(event);
}

public void processEvent(ApplicationEvent event) {
    Object[] args = this.resolveArguments(event);
    if (this.shouldHandle(event, args)) {
        Object result = this.doInvoke(args);
        if (result != null) {
            this.handleResult(result);
        } else {
            this.logger.trace("No result object given - no result to handle");
        }
    }

}

总结

通过前面几篇的springboot 启动分析,至此已经完成了整个启动过程

上一篇下一篇

猜你喜欢

热点阅读