spring boot 2源码系列(二)- 监听器ApplicationListener

强烈建议阅读本文之前,先看 spring boot 2源码系列(一)- 系统初始化器ApplicationContextInitializer。监听器的源码跟初始化器的源码有很多相似之处,例如:加载、初始化监听器,监听器委派,监听器排序。

spring boot监听器的使用

spring boot的监听器有多种配置方式。

第一种:使用spring.factories配置

1、新建Alistener实现ApplicationListener接口

// 监听ApplicationStartedEvent事件
@Order(1)
public class Alistener implements ApplicationListener<ApplicationStartedEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        System.out.println("####Alistener监听到ApplicationStartedEvent");
    }
}

2、在spring.factories中添加

org.springframework.context.ApplicationListener=com.example.springbootdemo.listener.Alistener

第二种:硬编码方式

1、新建Blistener实现ApplicationListener接口

// 监听ApplicationStartedEvent事件
@Order(2)
public class Blistener implements ApplicationListener<ApplicationStartedEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        System.out.println("####Blistener监听到ApplicationStartedEvent");
    }
}

2、修改启动类,通过代码添加Blistener

@SpringBootApplication
public class SpringBootDemoApplication {
    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(SpringBootDemoApplication.class);
        // 添加监听器
        springApplication.addListeners(new Blistener());
        springApplication.run(args);
    }
}

第三种:在application.properties配置context.listener.classes

1、新建Clistener实现ApplicationListener接口

// 监听ApplicationStartedEvent事件
@Order(3)
public class Clistener implements ApplicationListener<ApplicationStartedEvent> {
    @Override
    public void onApplicationEvent(ApplicationStartedEvent event) {
        System.out.println("####Clistener监听到ApplicationStartedEvent");
    }
}

2、在application.properties中配置

context.listener.classes=com.example.springbootdemo.listener.Clistener

第四种:实现GenericApplicationListener接口

1、新建Dlistener实现GenericApplicationListener接口

/**
 * GenericApplicationListener是标准ApplicationListener接口的扩展变体,
 * 公开了其他元数据,例如受支持的事件和源类型。
 * 从Spring Framework 4.2开始,此接口取代了基于类的SmartApplicationListener,并全面处理了通用事件类型。
 */
@Order(4)
public class Dlistener implements GenericApplicationListener {

    // 此监听器支持的事件类型
    @Override
    public boolean supportsEventType(ResolvableType eventType) {
        // 监听ApplicationStartingEvent、ApplicationStartedEvent事件
        return eventType.isAssignableFrom(ApplicationStartingEvent.class)
                || eventType.isAssignableFrom(ApplicationStartedEvent.class);
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        System.out.println("####Dlistener监听到"+event.getClass().getSimpleName());
    }

}

2、在spring.factories中添加配置(注意:实现类前后以及,\之间不要有空格)。

org.springframework.context.ApplicationListener=com.example.springbootdemo.listener.Alistener,\
com.example.springbootdemo.listener.Dlistener

启动工程,控制台打印

####Dlistener监听到ApplicationStartingEvent
####Clistener监听到ApplicationStartedEvent
####Alistener监听到ApplicationStartedEvent
####Blistener监听到ApplicationStartedEvent
####Dlistener监听到ApplicationStartedEvent

源码讲解—初始化阶段

spring boot监听器初始化阶段跟系统初始化器很相似,都是在创建SpringApplication实例的时候将在spring.factories配置的监听器设置给this.listeners属性。

主要源码如下:

// 源码位置 org.springframework.boot.SpringApplication#SpringApplication(org.springframework.core.io.ResourceLoader, java.lang.Class<?>...)
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	// 将spring.factories配置的监听器赋值给this.listeners
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
}

源码讲解—运行阶段

1、进入SpringApplication#run(java.lang.String...)源码,探究监听器的运行过程

//  仅列出主要代码
org.springframework.boot.SpringApplication#run(java.lang.String...)
    // 此处打断点。获取SpringApplicationRunListeners
    SpringApplicationRunListeners listeners = getRunListeners(args);
    // spring application 开始启动阶段
    listeners.starting();
    // spring application 启动完成阶段。在这里打个断点,通过启动完成阶段的代码分析spring boot监听器源码
    listeners.started(context);
    // spring application 运行阶段
    listeners.running(context);

// SpringApplicationRunListeners讲解
class SpringApplicationRunListeners {

    /**
     * SpringApplicationRunListeners 是对 SpringApplicationRunListener 的封装。
     * 包含多个SpringApplicationRunListener,以便能批量执行SpringApplicationRunListener的同名方法。
     * 利用List<SpringApplicationRunListener> listeners 可以方便我们拓展,自定义运行监听器。
     */
    private final List<SpringApplicationRunListener> listeners;

    // 省略部分代码

    /**
     * 循环listeners并调用SpringApplicationRunListener的started同名方法。
     * this.listeners默认只包含一个SpringApplicationRunListener实现类EventPublishingRunListener
     */
    void started(ConfigurableApplicationContext context) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.started(context);
        }
    }

    void environmentPrepared(ConfigurableEnvironment environment) {
        for (SpringApplicationRunListener listener : this.listeners) {
            listener.environmentPrepared(environment);
        }
    }

    // 省略部分代码

}

SpringApplicationRunListener接口定义如下:

/**
 * SpringApplicationRunListener是SpringApplication运行阶段的侦听器。
 */
public interface SpringApplicationRunListener {

	/**
	 * 在首次启动run方法时立即调用。 可用于非常早的初始化。
	 */
	default void starting() {
	}

	/**
	 * 在环境准备好、ApplicationContext创建之前调用。
	 */
	default void environmentPrepared(ConfigurableEnvironment environment) {
	}

	/**
	 * ApplicationContext已创建并准备好,但是在加载源之前。
	 */
	default void contextPrepared(ConfigurableApplicationContext context) {
	}

	/**
	 * 应用程序上下文已加载,但尚未刷新。
	 */
	default void contextLoaded(ConfigurableApplicationContext context) {
	}

	/**
	 * 上下文已刷新,应用程序已启动,CommandLineRunners和ApplicationRunner尚未被调用。
	 */
	default void started(ConfigurableApplicationContext context) {
	}

	/**
	 * 在run方法完成之前,当刷新应用程序上下文并且已调用所有CommandLineRunners和ApplicationRunners
	 */
	default void running(ConfigurableApplicationContext context) {
	}

	/**
	 * 运行应用程序时发生故障时调用
	 */
	default void failed(ConfigurableApplicationContext context, Throwable exception) {
	}

}

2、进入 listeners.started();源码中

2.1 首先进入到SpringApplicationRunListeners#started 方法

// 源码位置 org.springframework.boot.SpringApplicationRunListeners#started
void started(ConfigurableApplicationContext context) {
    for (SpringApplicationRunListener listener : this.listeners) {
        // 调用SpringApplicationRunListener实现类的同名方法
        listener.started(context);
    }
}

2.2 listener.started(context); 分析

listener是EventPublishingRunListener。

/**
 * EventPublishingRunListener是SpringApplicationRunListener接口的默认实现,用于发布事件。
 * 仅展示部分代码
 */
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {

    // 默认事件广播器,用于广播事件
    private final SimpleApplicationEventMulticaster initialMulticaster;

    @Override
    public int getOrder() {
        return 0;
    }

    // 省略部分代码

    // 使用SimpleApplicationEventMulticaster#multicastEvent()广播ApplicationStartedEvent事件
    @Override
    public void started(ConfigurableApplicationContext context) {
        context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
    }
    
    @Override
    public void environmentPrepared(ConfigurableEnvironment environment) {
        this.initialMulticaster
                .multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
    }

}

3、context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));   源码

// 源码位置 org.springframework.context.support.AbstractApplicationContext.publishEvent(java.lang.Object, org.springframework.core.ResolvableType)
protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
    /**
     * 主要代码:
     * getApplicationEventMulticaster()返回的依旧是SimpleApplicationEventMulticaster实例
     * multicastEvent(applicationEvent, eventType);广播事件
     */
    getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
}

4、SimpleApplicationEventMulticaster#multicastEvent()的作用是广播事件。

// 源码位置 org.springframework.context.event.SimpleApplicationEventMulticaster#multicastEvent(org.springframework.context.ApplicationEvent, org.springframework.core.ResolvableType)
// 将的应用程序事件广播给对此事件感兴趣的侦听器
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
    // 重点代码1:根据event创建ResolvableType
    ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
    Executor executor = getTaskExecutor();
    /**
     * 重点代码2:getApplicationListeners(event, type)
     * 返回监听了当前event事件的监听器,不监听当前事件的监听器被排除,不会返回
     * event:要广播的事件
     * eventType:事件类型
     */
    for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
        // 若设置了线程池,使用线程调用监听器
        if (executor != null) {
            executor.execute(() -> invokeListener(listener, event));
        }
        else {
            // 重点代码3:没设置线程池,使用当前线程调用监听器。默认没设置线程池
            invokeListener(listener, event);
        }
    }
}

4.1 ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));   通过event创建ResolvableType。

4.2 getApplicationListeners(event, type) 返回监听了当前event事件的监听器,不监听当前事件的监听器被排除,不会返回。这是个重点的方法。

进入getApplicationListeners(event, type)中debug,会进入到 AbstractApplicationEventMulticaster#supportsEvent() 中

// 源码位置 org.springframework.context.event.AbstractApplicationEventMulticaster#supportsEvent(org.springframework.context.ApplicationListener<?>, org.springframework.core.ResolvableType, java.lang.Class<?>)
protected boolean supportsEvent(ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
    // 如果监听器是GenericApplicationListener的实现类则返回监听器本身,否则创建GenericApplicationListenerAdapter
    GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
            (GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
    /**
     * 通过supportsEventType和supportsSourceType判断监听器是否监听了当前事件
     * supportsSourceType默认返回true
     */
    return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}

我们自己创建的Dlistener实现GenericApplicationListener接口,并重写了supportsEventType()方法,监听ApplicationStartingEvent、ApplicationStartedEvent事件。

Alistener、Blistener没实现GenericApplicationListener。与系统初始化器一样,Clistener由DelegatingApplicationListener调用,DelegatingApplicationListener也没实现GenericApplicationListener。因此会创建GenericApplicationListenerAdapter实例,再执行  (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType)); 判断

4.2.1 new GenericApplicationListenerAdapter(listener)); 源码分析

// 源码位置 org.springframework.context.event.GenericApplicationListenerAdapter#GenericApplicationListenerAdapter
public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {
    // 将监听器赋值给delegate属性
    this.delegate = (ApplicationListener<ApplicationEvent>) delegate;
    /**
     * 获取监听器监听的事件类型。
     * 例如:this.delegate = Alistener
     *      this.declaredEventType就等于ApplicationStartedEvent
     */
    this.declaredEventType = resolveDeclaredEventType(this.delegate);
}

4.2.2 GenericApplicationListenerAdapter#supportsEventType()源码分析

    // 源码位置 org.springframework.context.event.GenericApplicationListenerAdapter.supportsEventType(org.springframework.core.ResolvableType)
    @Override
    @SuppressWarnings("unchecked")
    public boolean supportsEventType(ResolvableType eventType) {
        if (this.delegate instanceof SmartApplicationListener) {
            Class<? extends ApplicationEvent> eventClass = (Class<? extends ApplicationEvent>) eventType.resolve();
            return (eventClass != null && ((SmartApplicationListener) this.delegate).supportsEventType(eventClass));
        }
        else {
            /**
             * 主要代码是 this.declaredEventType.isAssignableFrom(eventType))
             * 当监听器是Alistener、Blistener时:
             *    this.declaredEventType是ApplicationStartedEvent,eventType也是ApplicationStartedEvent,返回true
             * 当监听器是DelegatingApplicationListener时:
             *    this.declaredEventType是ApplicationEvent,eventType是ApplicationStartedEvent,
             *    ApplicationEvent是ApplicationStartedEvent的父类,this.declaredEventType.isAssignableFrom(eventType)也返回true
             */
            return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
        }
    }

在本项目中 getApplicationListeners(event, type) 返回的监听器会包含Alistener、Blistener、Dlistener、DelegatingApplicationListener。DelegatingApplicationListener会调用Clistener。

4.3 监听了event事件的监听器通过 getApplicationListeners(event, type) 返回了,接下来就是调用监听器的onApplicationEvent(event)方法。

 invokeListener(listener, event); 源码

// 源码位置 org.springframework.context.event.SimpleApplicationEventMulticaster#invokeListener
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
    // 主要代码,调用监听器
    doInvokeListener(listener, event);
}

4.3.1 doInvokeListener(listener, event); 源码

// 源码位置 org.springframework.context.event.SimpleApplicationEventMulticaster#doInvokeListener
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
    // 主要代码,执行监听器的onApplicationEvent(E event);方法
    listener.onApplicationEvent(event);
}
发布了51 篇原创文章 · 获赞 14 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/u010606397/article/details/105325189
今日推荐