SpringBoot深度探究(八)源码探究启动流程之二

56 篇文章 3 订阅
12 篇文章 2 订阅

前言

上一篇【SpringBoot深度探究(七)源码探究启动流程之一】主要介绍了SpringApplication在构造方法里做了一些必要的初始化,其中最重要的点就是把初始化器类和监听器类全部都加载进去了。本篇将会接着这一进程继续探索run()方法在后面做的事情。但是要说明的是启动流程将主要针对于如何走的Spring主流程,因为SpringBoot每次发布事件都会把所有的Listener循环一遍,以找到对应此事件感兴趣的Listener,全写出来会使得博客太跳,不利于把控整个主流程。各个Listener起了什么作用的部分有时间会单独开博客讲解,请多多包涵。更多Spring内容进入【Spring解读系列目录】

SpringApplication.run

public ConfigurableApplicationContext run(String... args) {
   StopWatch stopWatch = new StopWatch();
   stopWatch.start(); //记录日志时间的,没啥大作用
   ConfigurableApplicationContext context = null;//现在没啥大用
   Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); //错误报告列表,没啥大用
   //配置系统属性headless,没啥大用
   configureHeadlessProperty();
   //这方法做的事情也是从spring.factories里面拿到一个类的实例,并且赋值给this.listeners备用
   SpringApplicationRunListeners listeners = getRunListeners(args);
   //调用starting()方法
   listeners.starting();
   try {
      /*暂时略,后面具体分析*/
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, exceptionReporters, listeners);
      throw new IllegalStateException(ex);
   }

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

进入run()方法以后先跳过没啥大用的代码,就遇到第一个很重要的方法了getRunListeners(args),这个方法本身没啥特别可说的。但是它生成类以及返回的对象SpringApplicationRunListeners listeners非常的有用,那么先进入方法再说。

private SpringApplicationRunListeners getRunListeners(String[] args) {
   Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
   // getSpringFactoriesInstances() 和上篇讲的完全一样的方法
   return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}

注意这里和上篇SpringApplication初始化的时候是一样的getSpringFactoriesInstances()方法,这里去文件spring.factories里面寻找并且实例化的类型是SpringApplicationRunListener。通过调试和查找最终这里只有一个类被实例化出来。然后通过构造方法SpringApplicationRunListeners(),赋值给this.listeners备用。

所有spring.factories文件里只有一个 SpringApplicationRunListeners类型:
// org.springframework.boot.SpringApplicationRunListener=\
// org.springframework.boot.context.event.EventPublishingRunListener

注意,这里的this.listeners是SpringApplicationRunListeners类的,而上一篇的this.listeners则是SpringApplication类的。这里必要分清楚,因为后续会使用RunListeners类直接调用SpringApplication里面的各种实例化出来的Listener类,跳出这个方法继续就到了listeners.starting();方法,这里的listeners是返回的SpringApplicationRunListeners类对象。

SpringApplicationRunListeners.starting

void starting() {
   //由于listeners只有一个对象,这里循环了一个寂寞,估计Spring会在以后进行扩展
   for (SpringApplicationRunListener listener : this.listeners) {
      listener.starting();
   }
}

进入starting()以后,发现这里对所有的SpringApplicationRunListener进行了一个循环,但是通过刚刚分析的代码知道这里其实就只有一个类对象EventPublishingRunListener的类对象。因此可以知道这里执行的就是EventPublishingRunListener.starting(),跳转过去。

EventPublishingRunListener.starting

public void starting() {
   // this.application就是上面的SpringApplication.class
   this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}

进来以后发现里面的内容很少,但是却很重要,在拆解之前,要说明白这里传的是一个new ApplicationStartingEvent(),也就是说给multicastEvent()方法里面传递了一个ApplicationStarting事件。注意:这里就开始应用观察者模式了。拆解解释一下:

SimpleApplicationEventMulticaster

首先先说this.initialMulticaster,它是SimpleApplicationEventMulticaster类对象,这个类从名字看大概知道是一个广播器,那么其实说明了EventPublishingRunListener并不是一个标准的Listener。其里面还有个广播器,会在这个类初始化的时候被new出来。这个过程十分的重要,因为在new出来广播器对象以后,Spring通过一个循环,把之前初始化好的所有监听器Listener都传递到了广播器中,这样广播器就可以对每个监听器进行响应。

public EventPublishingRunListener(SpringApplication application, String[] args) {
   this.application = application;
   this.args = args;
   //实例化广播器
   this.initialMulticaster = new SimpleApplicationEventMulticaster();
   //并且把之前拿到的ApplicationListener类全部循环加载到initialMulticaster对象里
   //  这个广播器将会在后面根据event的不同进行不同的处理。换句话说根据event的类型循环使用不同的Listener进行处理
   for (ApplicationListener<?> listener : application.getListeners()) {
      this.initialMulticaster.addApplicationListener(listener);
   }
}
注解:
   for循环以后initialMulticaster对象里面就有了下面的Listener类对象,一共11个
    org.springframework.boot.ClearCachesApplicationListener,\							1
    org.springframework.boot.builder.ParentContextCloserApplicationListener,\			2
    org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\			3
    org.springframework.boot.context.FileEncodingApplicationListener,\					4
    org.springframework.boot.context.config.AnsiOutputApplicationListener,\				5
    org.springframework.boot.context.config.ConfigFileApplicationListener,\				6
    org.springframework.boot.context.config.DelegatingApplicationListener,\				7
    org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\		8
    org.springframework.boot.context.logging.LoggingApplicationListener,\				9
    org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener		10
    ----分割,下面的在另一个文件里----
   org.springframework.boot.autoconfigure.BackgroundPreinitializer						11

那么在执行starting()的时候,就可以说this.initialMulticaster已经把所有需要的监听器做了初始化,并存到了自己里面,所以this.initialMulticaster.multicastEvent(...)所做的事情,就是把对应的事件发布出去。要注意的是这个方法已经脱离了SpringBoot的原始jar包,此时已经到了SpringFramework里的jar包中。

SimpleApplicationEventMulticaster. multicastEvent

注意这个方法的包名,是org.springframework.context,已经不是org.springframework.boot了。
org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(ApplicationEvent, ResolvableType)

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
   //使用多线程去执行监听器
   Executor executor = getTaskExecutor();
   //这里getApplicationListeners(event, type)是寻找对应的event和type是否对某个listener感兴趣
   for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      if (executor != null) {
         executor.execute(() -> invokeListener(listener, event));
      }
      else {
         invokeListener(listener, event);
      }
   }
}

进入这个方法其实最重要的就是for循环内容。最先说明一点,for循环里面invokeListener(listener, event))就是具体的Listener执行的内容,这点暂且不做分析,原因在前言部分已经说过了。这里重点分析的将会是Spring如何对某个事件感兴趣的,那么就直接进入getApplicationListeners(event, type)

protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
   //这里将会调用方法去找到是否有listener对传进来的东西感兴趣
   Object source = event.getSource();
   Class<?> sourceType = (source != null ? source.getClass() : null);
   ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
   // Quick check for existing entry on ConcurrentHashMap...
   ListenerRetriever retriever = this.retrieverCache.get(cacheKey);
   if (retriever != null) {
      return retriever.getApplicationListeners();
   }
   if (this.beanClassLoader == null ||
         (ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
               (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
      // Fully synchronized building and caching of a ListenerRetriever
      synchronized (this.retrievalMutex) {
         retriever = this.retrieverCache.get(cacheKey);
         if (retriever != null) {
            return retriever.getApplicationListeners();
         }
         retriever = new ListenerRetriever(true);
         //最终将会使用这个方法去返回是否有对传递进来的事件event或者source感兴趣
         Collection<ApplicationListener<?>> listeners =
               retrieveApplicationListeners(eventType, sourceType, retriever);
         this.retrieverCache.put(cacheKey, retriever);
         return listeners;
      }
   }
   else {
      // No ListenerRetriever caching -> no synchronization necessary
      //最终将会使用这个方法去返回是否有对传递进来的事件event或者source感兴趣
      return retrieveApplicationListeners(eventType, sourceType, null);
   }
}

进入以后略过各种初始化获取eventcache的部分,最终返回的是使用retrieveApplicationListeners()方法拿到的结果,直接点进去。

private Collection<ApplicationListener<?>> retrieveApplicationListeners(
      ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable ListenerRetriever retriever) {

   List<ApplicationListener<?>> allListeners = new ArrayList<>();
   Set<ApplicationListener<?>> listeners;
   Set<String> listenerBeans;
   synchronized (this.retrievalMutex) {
      listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
      listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
   }//以上是做了一些初始化内容
   //循环遍历listeners查看是否有感兴趣的监听器,如何判断呢,就是用GenericApplicationListener里面的两个方法去判断
   for (ApplicationListener<?> listener : listeners) {
     // 每个监听器都对同一个事件的进行过滤,直到发现一个合适的。
      if (supportsEvent(listener, eventType, sourceType)) {
         if (retriever != null) {
            retriever.applicationListeners.add(listener);
         }
         allListeners.add(listener);
      }
   }
   if (!listenerBeans.isEmpty()) {
      /* 无关主线领略过
      Add listeners by bean name, potentially overlapping with programmatically
         registered listeners above - but here potentially with additional metadata.
       */
   }
   //排序
   AnnotationAwareOrderComparator.sort(allListeners);
   if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
      retriever.applicationListeners.clear();
      retriever.applicationListeners.addAll(allListeners);
   }//返回所有感兴趣的Listeners
   return allListeners;
}

可以看到最终判断是否对发的事件感兴趣主要是由条件语句中的supportsEvent()方法的返回结果决定的。这个方法就是用来判断当前监听器对当前的事件是否感兴趣,可以看到这是一个for循环,也就是说所有的监听器都会对同一个事件进行过滤,直到发现一个合适的。点入supportsEvent()方法。

AbstractApplicationEventMulticaster.supportsEvent

protected boolean supportsEvent(
      ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
   // 类型转换
   GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
         (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
   // 判断是否感兴趣
   return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}

首先判断当前listener是不是GenericApplicationListener。如果是直接用,如果不是转换成GenericApplicationListenerAdapter再用。因为GenericApplicationListener 是个接口,不能直接用的,除非外部实现了。然后根据GenericApplicationListener中的supportsEventType()方法和supportsSourceType()方法中的逻辑判断是否感兴趣。如果感兴趣,返回true,如果不感兴趣,返回false

如何判断当前事件是否能引起某个Listener的兴趣

是否感兴趣是怎么判断得呢?其实从smartListener对象调用supportsEventType()supportsSourceType()方法就可以知道,每一个Listener里面都有实现这两个方法,如果Listener中对应得方法返回true那就说明匹配上了,否则就是不感兴趣。这里一共要判断11次,不可能把每一个都拿出来讲一遍。所以返回出去那么getApplicationListeners(event, type)这个方法就是所有对ApplicationStarting的事件感兴趣的监听器都添加到allListeners列表里,并且作为一个for循环的集合,在下面的方法里对所有在list里面的方法执行监听器应该做的事情,即执行对应的invokeListener(listener, event)

public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
   ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
   //使用多线程去执行监听器
   Executor executor = getTaskExecutor();
   //这里getApplicationListeners(event, type)是寻找对应的event和type是否对某个listener感兴趣
   for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      if (executor != null) {
         executor.execute(() -> invokeListener(listener, event));
      }
      else {
         invokeListener(listener, event);
      }
   }
}

最后一层一层点进去执行的就是ApplicationListener#onApplicationEvent()方法,每一个监听器最终都会执行这个方法完成对应的逻辑。对这个方法感兴趣的同学可以去看【SpringBoot深度探究(六)事件编程模型(Listener-Event)的扩展】这篇博客。

总结

总结下本篇博客的内容,本篇说到SpringBoot启动了SpringApplicationRunListeners类,并且由这个类调用广播器对每一个Listener进行广播。如果一个Listener判断自己对某个类型(本篇只说了Strating后面还有会有别的类型)感兴趣,那么就添加到一个list里作为循环的集合。然后由外部for循环,循环调用Listener中的方法,进行具体的逻辑执行。随者SpringBoot的流程往下走,还会看到更多的事件被注册,以及更多的Listener执行,有兴趣的同学可以自己先读下。我们下一篇【SpringBoot深度探究(九)源码探究启动流程之三】将会说到SpringBoot在何处启动的Tomcat,最后在总结一下广播器的作用。

广播器initialMulticaster这个类的作用
  1. 首先会广播一个事件,并且对询问所有的监听器是否感兴趣:
     for (ApplicationListener<?> listener : getApplicationListeners(event, type))getApplicationListeners()传入了两个参数event,type,作为兴趣源或者事件类型。
     这个方法的作用就是告诉所有的监听器,现在有了一个type类型的event,谁感兴趣?
  2. 通知所有监听器
     getApplicationListeners()里面会遍历所有的监听器,每一个监听器都会对这个方法进行判断,
     是否对这个事件感兴趣。
     如何判断呢?
        a).用两个方法确定
           supportsEventType(eventType)supportsSourceType(sourceType),这两个方法
           可以理解为通过传入一个事件类型到监听器里面,进而判断是否对这个事件感兴趣。如果感兴趣
           返回true,如果不感兴趣返回false。如果是true会被添加到一个list中,再由后续的代码进行处理。
        b).在监听器进行回调的时候
           除了a)以外也可以通过onApplicationEvent(E event)进行判断,如果事件类型不感兴趣,那么不作
           任何的处理即可。注:Spring是通过a)+b)进行双重判断的。
  3. 获得所有对这个事件感兴趣的监听器以后,遍历执行onApplicationEvent(E event)方法。
     这里的代码传递一个ApplicationStartingEvent的事件到里面去,最终决定如何执行相关的方法。
  4. initialMulticaster金额图就阿布带事故SimpleApplicationEventMulticaster类型的对象
     主要有两个方法,一个是广播事件,一个是执行listener的onApplicationEvent()方法。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值