springtboot启动主流程-run方法

版本说明

Spring Boot:【2.4.6】

Spring: 【5.3.7】

SpringApplication#run方法主流程

项目为一个简单的springboot项目,只导入web模块。

接上文springtboot启动主流程-构造方法,从SpringApplication#run方法开始分析,构造完SpringApplication实例后调用其run方法

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

run方法是springboot启动过程中另一重要方法,它在springboot和spring之间建立联系

// Run the Spring application, creating and refreshing a new ApplicationContext.
public ConfigurableApplicationContext run(String... args) {
   StopWatch stopWatch = new StopWatch();
   stopWatch.start();
   // 创建一个DefaultBootstrapContext,作为参数,调用全部BootstrapRegistryInitializer的initialize方法
   DefaultBootstrapContext bootstrapContext = createBootstrapContext();
   ConfigurableApplicationContext context = null;
   // 配置java.awt.headless,服务端程序无显示器
   configureHeadlessProperty();
   // 获取所有SpringApplicationRunListeners
   SpringApplicationRunListeners listeners = getRunListeners(args);
   // 发布ApplicationStartingEvent事件
   listeners.starting(bootstrapContext, this.mainApplicationClass);
   try {
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      // 创建一个StandardServletEnvironment并配置环境,发布ApplicationEnvironmentPreparedEvent事件
      ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
      configureIgnoreBeanInfo(environment);
      // 打印banner
      Banner printedBanner = printBanner(environment);
      // 1. 创建ApplicationContext,通过从上到下实例化,实例化了一个DefaultListableBeanFactory,作为Spring框架中很重要的一个类
      context = createApplicationContext();
      context.setApplicationStartup(this.applicationStartup);
      // 2. 用已有的数据准备环境
      prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
      // 3. 刷新Context,最终会回到Spring中的核心流程AbstractApplicationContext#refresh
      refreshContext(context);
      // 4. 目前为空
      afterRefresh(context, applicationArguments);
      stopWatch.stop();
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
      }
      // 发布ApplicationStartedEvent
      listeners.started(context);
      // 获取ApplicationRunner和CommandLineRunner,并调用其run方法
      callRunners(context, applicationArguments);
   }
   catch (Throwable ex) {
      // 发布ApplicationFailedEvent
      handleRunFailure(context, ex, listeners);
      throw new IllegalStateException(ex);
   }

   try {
      // 发布ApplicationReadyEvent
      listeners.running(context);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, null);
      throw new IllegalStateException(ex);
   }
   return context;
}

从上面代码可以看出,refreshContext(context)方法回到了Spring框架完成了IOC容器的初始化,bean的实例化,bean初始化等工作。这里先跳过Spring的分析,只分析其余的部分。

发布事件 - 观察者模式的应用

SpringBoot中引入了大量的事件,开发者可以扩展对事件的监听,只关注感兴趣的事件,这样可以降低代码之间的耦合。这里只分析下这两句

SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);

上面代码获取了SpringApplicationRunListener,然后用SpringApplicationRunListeners来包装,SpringApplicationRunListeners封装了事件的发布工作

void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
   doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
         (step) -> {
            if (mainApplicationClass != null) {
               step.tag("mainApplicationClass", mainApplicationClass.getName());
            }
         });
}

上面方法传入了两个lambda表达式,看下doWithListeners的执行逻辑

private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
      Consumer<StartupStep> stepAction) {
   StartupStep step = this.applicationStartup.start(stepName);
   // 遍历所有listener,等同于调用所有listenerAction.accept(listener)
   this.listeners.forEach(listenerAction);
   if (stepAction != null) {
      stepAction.accept(step);
   }
   step.end();
}

默认下SpringApplicationRunListener接口只有一个实现,就是在spring-boot包下的spring.factories中定义,唯一的实现类就是这个EventPublishingRunListener

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener

这个类就是个事件发布器,构造过程中实例化了一个SimpleApplicationEventMulticaster,用来真正去发布事件

public EventPublishingRunListener(SpringApplication application, String[] args) {
   this.application = application;
   this.args = args;
   this.initialMulticaster = new SimpleApplicationEventMulticaster();
   for (ApplicationListener<?> listener : application.getListeners()) {
      // 添加监听器,等待未来事件产生的时候去调用监听器
      this.initialMulticaster.addApplicationListener(listener);
   }
}

SimpleApplicationEventMulticaster的multicastEvent方法负责遍历所有listener并调用listener

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
   // 是否允许在单独executor中执行
   Executor executor = getTaskExecutor();
   // 获取所有已注册的listen
   for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      if (executor != null) {
         executor.execute(() -> invokeListener(listener, event));
      }
      else {
         invokeListener(listener, event);
      }
   }

run方法发布的事件

JDK中的观察者模式

下面是引自《设计模式之禅》中的观察者模式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XmVyyb6i-1644309778318)(C:\Users\sunhongyue_it\AppData\Roaming\Typora\typora-user-images\image-20220208153459029.png)]

JDK从1.0就定义了Observer接口,Observable类,但是到JDK9就给废弃了,文档写的理由是:

This class and the Observer interface have been deprecated. The event model supported by Observer and Observable is quite limited, the order of notifications delivered by Observable is unspecified, and state changes are not in one-for-one correspondence with notifications. For a richer event model, consider using the java.beans package. For reliable and ordered messaging among threads, consider using one of the concurrent data structures in the java.util.concurrent package. For reactive streams style programming, see the Flow API

可以参考sof讨论

End

run方法完成的核心内容:

  • 运行Spring application,创建并刷新一个新的ApplicationContext(eg.AnnotationConfigServletWebServerApplicationContext)
    • context持有一个beanFactory(eg.DefaultListableBeanFactory)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值