listeners.starting()

简介: listeners.starting()

SpringBoot启动流程之(listener.starting())

  • starting()流程图:

根据前面讲的SpringApplicationRunListeners listeners = getRunListeners(args);我们已经把所有事件都交给了广播

继续往后看,在系统获取完SpringApplicationRunListeners之后,紧接着便执行了starting方法,代码如下

     

SpringApplicationRunListeners listeners=getRunListeners(args);
        //SpringApplicationRunListeners执行了start方法
        listeners.starting();

遍历SpringApplicationRunListeners的listener集合

class SpringApplicationRunListeners {
    private final Log log;
    //这里接受了一个以SpringApplicationRunListener为类型的List集合
    private final List<SpringApplicationRunListener> listeners;
    //SpringApplicationRunListeners的默认构造,接受了一个子类型继承SpringApplicationRunListener的List
    SpringApplicationRunListeners(Log log, Collection<? extends SpringApplicationRunListener> listeners) {
        this.log = log;
        this.listeners = new ArrayList<>(listeners);
    }
    //遍历listener集合
    void starting() {
        for (SpringApplicationRunListener listener : this.listeners) {
            //启动listener,分派给SpringApplicationRunListener的具体实现EventPublishingRunListener
            listener.starting();
        }
    }
//下面还有很多方法,省略了。。。。。。逻辑基本上跟starting一样
  • SpringApplicationRunListeners参数细节:
  • 在start阶段,this.listeners只有一个为EventPublishingRunListener参数
  • EventPublishingRunListener内部建立了广播SimpleApplicationEventMulticaster
  • 广播内部拥有SpringApplication在构造的所有listener事件

来看看SpringApplicationRunListener的内部结构

public interface SpringApplicationRunListener {
    //run方法第一次启动时调用它
    default void starting() {
    }
    //在环境建立好的时候调用它(建立environment对象)
    default void environmentPrepared(ConfigurableEnvironment environment) {
    }
    //建立ApplicationContext但是不引入配置信息
    default void contextPrepared(ConfigurableApplicationContext context) {
    }
    //载入配置信息
    default void contextLoaded(ConfigurableApplicationContext context) {
    }
    default void started(ConfigurableApplicationContext context) {
    }
    default void running(ConfigurableApplicationContext context) {
    }
    default void failed(ConfigurableApplicationContext context, Throwable exception) {
    }
}
  • 来看看EventPublishingRunListener类吧
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
    private final SpringApplication application;
    private final String[] args;
    private final SimpleApplicationEventMulticaster initialMulticaster;
    /**
     * application是new SpringApplication()时的构造方法的application,这里遍历的application.getListeners()就是构造
     * 时读取以ApplicationListener.class为条件的META-INF/spring.factories的全限定类名集合
     * @param application
     * @param args
     */
    public EventPublishingRunListener(SpringApplication application, String[] args) {
        this.application = application;
        this.args = args;
        this.initialMulticaster = new SimpleApplicationEventMulticaster();
        for (ApplicationListener<?> listener : application.getListeners()) {
            //将listener添加到this.defaultRetriever.applicationListeners里面,每一个listener内部进行了去重,防止相同事件的调用
            this.initialMulticaster.addApplicationListener(listener);
        }
    }
    // 这个地方后面会说,其实从这里开始才是真正的开始启动listener
    public void starting() {
        this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
    }
    //下面还有很多方法,基本上跟starting差不多
}
  • 同样查看starting()方法,发现EventPublishingRunListener将所有事件委托给了SimpleApplicationEventMulticaster(事件多播实现类)
  • 到此为止,事件的start的调用链路是理清了,看看它们之间的关系
  • 总结
  1. 由SpringApplication创建SpringApplicationRunListeners,并且把经过构造的SpringApplication作为参数传递给了EventPublishingRunListener
  2. SpringApplicationRunListeners包含了SpringApplicationRunListener的list集合
  3. SpringApplicationRunListener的具体实现由EventPublishingRunListener实现
  4. EventPublishingRunListener最终把所有listener委托给了SimpleApplicationEventMulticaster实现
  5. 其实SpringApplicationRunListeners listeners = getRunListeners(args) ;阶段就是把SpringApplication构造阶段的listener交给了广播,为随后的start打下基础
  • 事件由SimpleApplicationEventMulticaster多播器实现
public void multicastEvent(final ApplicationEvent event,@Nullable ResolvableType eventType){
        //获取event的具体分派类型
        ResolvableType type=(eventType!=null?eventType:resolveDefaultEventType(event));
        Executor executor=getTaskExecutor();
        //getApplicationListeners(event,type)会根据ResolvableType过滤我们需要的listener。接下来会讲
        //遍历所有listener,并且把listener全部start
        for(ApplicationListener<?> listener:getApplicationListeners(event,type)){
        //是否存在线程池支持异步执行
        if(executor!=null){
        executor.execute(()->invokeListener(listener,event));
        }
        else{
        //同步执行listener事件()
        invokeListener(listener,event);
        }
        }
        }
//不重要
protected void invokeListener(ApplicationListener<?> listener,ApplicationEvent event){
        ......省略
        doInvokeListener(listener,event);
        ......省略
        }
//最终执行的是这个
private void doInvokeListener(ApplicationListener listener,ApplicationEvent event){
        //所有的listener最终都是基于这个调用的,接下来看看onApplicationEvent(event);的庐山真面目
        listener.onApplicationEvent(event);
//省略......
  • 根据ResolvableType过滤listeners
  • 未过滤时的listeners
protected boolean supportsEvent(
        //根据当前listener类型加载不同的GenericApplicationListener实现
        ApplicationListener<?> listener,ResolvableType eventType,@Nullable Class<?> sourceType){
        //为listener配置GenericApplicationListener接口的具体实现
        //如果当前listener与GenericApplicationListener存在关联,则类型转化为GenericApplicationListener
        //否则定义适配器GenericApplicationListenerAdapter为两者不兼容接口提供兼容
        GenericApplicationListener smartListener=(listener instanceof GenericApplicationListener?
        (GenericApplicationListener)listener:new GenericApplicationListenerAdapter(listener));
        //这两个方法则是进行具体的listener检测
        return(smartListener.supportsEventType(eventType)&&smartListener.supportsSourceType(sourceType));
        }
  • 这是过滤后的listener
  • (事件的真正执行)ApplicationListener#onApplicationEvent()
  • 过滤的规则
//通过非适配器的过滤规则,这是Class自带的isAssignableFrom方法,用于确定type是否可以转换为supportedType
private boolean isAssignableFrom(Class<?> type,Class<?>...supportedTypes){
        if(type!=null){
        for(Class<?> supportedType:supportedTypes){
        if(supportedType.isAssignableFrom(type)){
        return true;
        }
        }
        }
        return false;
        }
//通过适配器的过滤规则则是通过ResolvableType.isAssignableFrom()方法或者通过
//ResolvableType.forClass(listenerType).as(ApplicationListener.class).getGeneric();来实现
//ResolvableType的过滤规则则是确定该类型能否在对象树上找到对应的指定对象
  • 无论是通过Class、ResolvableType来实现过滤,其本质上都是在确定一个类型是否与指定类型存在关联(比如说继承、实现......)
  • listeners的具体执行listener.onApplicationEvent(event);
/**
 * 由应用程序事件监听器实现的接口。基于 Observer 设计模式的标准 java.util.EventListener 接口。
 * 从 Spring 3.0 开始,ApplicationListener 可以一般性地声明它感兴趣的事件类型。
 * 当向 Spring ApplicationContext 注册时,事件将被相应地过滤,只有匹配事件对象才会调用侦听器。
 * @param <E>
 */
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
    //现在就是正真的开始start了,对于所有该接口的实现类,
    // 都可以在运行时根据具体创建类型执行onApplicationEvent,拓展性十分棒哦
    void onApplicationEvent(E event);
}
-PS:过滤后执行的四个listener
        -LoggingApplicationListener(引导系统日志)
        -BackgroundPreinitializer(ApplicationListener 在耗时任务的后台线程中触发早期初始化)
        -LiquibaseServiceLocatorApplicationListener(说啥换版本?但是不晓得啥意思)
        -DelegatingApplicationListener(context.listener.classes下的listeners,不理解)
目录
相关文章
|
6月前
|
消息中间件 Shell
mq报错abbit@syld36: * connected to epmd (port 4369) on syld36 * epmd reports node ‘rabbit‘ uses po
mq报错abbit@syld36: * connected to epmd (port 4369) on syld36 * epmd reports node ‘rabbit‘ uses po
106 0
|
8月前
|
消息中间件 Linux
mq报错abbit@syld36: * connected to epmd (port 4369) on syld36 * epmd reports node ‘rabbit‘ uses po
mq报错abbit@syld36: * connected to epmd (port 4369) on syld36 * epmd reports node ‘rabbit‘ uses po
140 0
|
安全 Ubuntu 测试技术
l4re Getting started
l4re Getting started
396 0
|
8月前
|
负载均衡 Java 应用服务中间件
Client not connected, current status:STARTING
Client not connected, current status:STARTING
588 1
|
应用服务中间件
The Tomcat connector configured to listen on port 10000 failed to start. The port may already be in
The Tomcat connector configured to listen on port 10000 failed to start. The port may already be in
|
应用服务中间件 Windows
The Tomcat connector configured to listen on port 18081 failed to start. The port may already be in
The Tomcat connector configured to listen on port 18081 failed to start. The port may already be in
221 0
|
Oracle 关系型数据库 Linux
[20170705]lsnrctl status LISTENER_SCAN1
[20170705]lsnrctl status LISTENER_SCAN1.txt --//前几天在解决问题时遇到的问题,现在分析看看.当时没注意操作用户名,选择错误的用户执行(oracle用户执行).
1532 0
|
Java Apache Spring
Exception sending context initialized event to listener instance of class
详细错误信息如下: 严重: Exception sending context initialized event to listener instance of class com.auth.spring.
1235 0
Veloce 之 Getting Started
Veloce 之所以能够加速仿真,原因是Veloce把DUT(Design Under Test) 和 TB(TestBench) 一起综合成实际的电路,然后下载到Veloce硬件中,在硬件上跑,所以是比软件仿真快得多。 那么怎样才能把Veloce用起来,让它来加速我们的仿真呢?
Veloce 之 Getting Started
|
Ruby Web App开发