一、監聽器模式介紹
將一個監聽器(listener)與特定的控件(如按鈕等)綁定起來,當發生用戶點擊等事件(Event)時,調用監聽器的處理方法,從而響應用戶的動作,就叫做事件/監聽器模式。
從上面的語句中,我們可以看出監聽器模式有三個要素:
-
事件源
-
事件對象
-
監聽器
二、自定義監聽器事件
創建天氣事件接口和下雨、下雪實現類
public interface WeatherEvent {
String getWeather();
}
public class RainWeatherEvent implements WeatherEvent {
@Override
public String getWeather() {
return "下雨";
}
}
public class SnowWeatherEvent implements WeatherEvent {
@Override
public String getWeather() {
return "下雪";
}
}
創建天氣監聽實現接口和下雨、下雪監聽實現類
public interface WeatherListener {
void onWeatherEvent(WeatherEvent event);
}
public class RainListener implements WeatherListener {
@Override
public void onWeatherEvent(WeatherEvent event) {
if (event instanceof RainWeatherEvent) {
System.out.println(event.getWeather());
}
}
}
public class SnowListener implements WeatherListener {
@Override
public void onWeatherEvent(WeatherEvent event) {
if (event instanceof SnowWeatherEvent) {
System.out.println(event.getWeather());
}
}
}
創建事件廣播器接口和天氣事件廣播實現類
public interface EventMulticaster {
void multicastEvent(WeatherEvent event);
void addListener(WeatherListener listener);
void removeListener(WeatherListener listener);
}
public class WeatherEventMulticaster implements EventMulticaster {
private List<WeatherListener> listenerList = new ArrayList<>();
@Override
public void multicastEvent(WeatherEvent event) {
System.out.println("==========開始事件廣播==========");
listenerList.forEach(i -> i.onWeatherEvent(event));
System.out.println("==========結束事件廣播==========");
}
@Override
public void addListener(WeatherListener listener) {
listenerList.add(listener);
}
@Override
public void removeListener(WeatherListener listener) {
listenerList.remove(listener);
}
}
創建啟動測試類
public class Start {
public static void main(String[] args) {
// 創建廣播對象
EventMulticaster eventMulticaster = new WeatherEventMulticaster();
// 創建下雨事件監聽對象
RainListener rainListener = new RainListener();
// 創建下雪事件監聽對象
SnowListener snowListener = new SnowListener();
// 添加下雨、下雪監聽事件對象
eventMulticaster.addListener(rainListener);
eventMulticaster.addListener(snowListener);
// 廣播下雨事件
eventMulticaster.multicastEvent(new RainWeatherEvent());
// 廣播下雪事件
eventMulticaster.multicastEvent(new SnowWeatherEvent());
// 移除下雨監聽事件對象
eventMulticaster.removeListener(rainListener);
// 廣播下雨事件
// 廣播下雪事件
eventMulticaster.multicastEvent(new RainWeatherEvent());
eventMulticaster.multicastEvent(new SnowWeatherEvent());
}
}
啟動項目,查看控制台輸出:
==========開始事件廣播==========
下雨
==========結束事件廣播==========
==========開始事件廣播==========
下雪
==========結束事件廣播==========
==========開始事件廣播==========
==========結束事件廣播==========
==========開始事件廣播==========
下雪
==========結束事件廣播==========
可以看到當下雨監聽器被移除之后,下雨事件就不能被監聽處理了。
三、SpringBoot 監聽器實現
3.1 監聽器
@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {
void onApplicationEvent(E event);
}
FunctionalInterface是jdk8新增的,表示ApplicationListener接口只有一個方法,如果大於一個方法,將報錯。- 接口中有個泛型
<E extends ApplicationEvent>,繼承自ApplicationEvent。代表實現接口時,可以聲明對哪些事件(如ApplicationEvent)感興趣,在觸發監聽器的時候,對其他事件進行過濾。
3.2 系統廣播器
public interface ApplicationEventMulticaster {
// 添加事件監聽器
void addApplicationListener(ApplicationListener<?> listener);
// 添加事件監聽器
void addApplicationListenerBean(String listenerBeanName);
// 移除指定事件監聽器
void removeApplicationListener(ApplicationListener<?> listener);
// 移除指定事件監聽器
void removeApplicationListenerBean(String listenerBeanName);
// 移除所有事件監聽器
void removeAllListeners();
// 事件廣播
void multicastEvent(ApplicationEvent event);
// 事件廣播
void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType);
}
3.3 系統事件

| 事件名 | 作用 |
|---|---|
| ApplicationStartingEvent | 框架啟動事件 |
| ApplicationEnvironmentPreparedEvent | 環境准備完畢事件 |
| ApplicationContextInitializedEvent | 上下文初始化 |
| ApplicationPreparedEvent | 上下文創建完畢,但是Bean還沒有加載完畢 |
| ApplicationStartedEvent | bean 實例化完成,但是未調用 Runners接口 |
| ApplicationReadyEvent | 調用 Runners 接口完畢 |
| ApplicationFailedEvent | 啟動失敗事件 |
系統事件發生順序:

3.4 監聽器注冊
在 SpringApplication 初始化的時候就進行了監聽器注冊
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
......
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
......
}
3.5 監聽器事件觸發機制
以 starting 事件為例
public ConfigurableApplicationContext run(String... args) {
......
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
......
}
進入 starting 方法,里面是遍歷所有的 SpringApplicationRunListeners:
void starting() {
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
SpringApplicationRunListeners 接口定義如下,可以看到申明了多個事件:
public interface SpringApplicationRunListener {
default void starting() {}
default void environmentPrepared(ConfigurableEnvironment environment) {}
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{
......
private final SimpleApplicationEventMulticaster initialMulticaster;
@Override
public void starting() {
// 調用廣播器來發送事件
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
......
}
進入 multicastEvent 方法
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(event));
}
resolveDefaultEventType 是對 event 的包裝,不需要理會。
private ResolvableType resolveDefaultEventType(ApplicationEvent event) {
return ResolvableType.forInstance(event);
}
回到 multicastEvent 方法
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
// 獲得線程池
Executor executor = getTaskExecutor();
// getApplicationListeners --> 獲得對當前event感興趣的監聽器列表
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
獲得對當前 event 感興趣的監聽器列表:
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
// 獲取事件來源,這里的 source 就是 SpringApplication
Object source = event.getSource();
Class<?> sourceType = (source != null ? source.getClass() : null);
ListenerCacheKey cacheKey = new ListenerCacheKey(eventType, sourceType);
// 從緩存中獲取結果
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)))) {
// 完全同步構建和緩存ListenerRetriever
synchronized (this.retrievalMutex) {
retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
// 檢索感興趣的監聽器
Collection<ApplicationListener<?>> listeners =
retrieveApplicationListeners(eventType, sourceType, retriever);
// 存放到緩存中
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
else {
// 無需 ListenerRetriever 緩存->無需同步
return retrieveApplicationListeners(eventType, sourceType, null);
}
}
檢索感興趣的監聽器實現:
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) {
// 這些監聽器定義在 spring.factories 文件中
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
for (ApplicationListener<?> listener : listeners) {
// 只有對當前 eventType 感興趣的 listerer 才會添加到監聽器列表中
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
// 通過 bean 名稱獲取監聽器列表
if (!listenerBeans.isEmpty()) {
ConfigurableBeanFactory beanFactory = getBeanFactory();
for (String listenerBeanName : listenerBeans) {
try {
if (supportsEvent(beanFactory, listenerBeanName, eventType)) {
ApplicationListener<?> listener =
beanFactory.getBean(listenerBeanName, ApplicationListener.class);
if (!allListeners.contains(listener) && supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
if (beanFactory.isSingleton(listenerBeanName)) {
retriever.applicationListeners.add(listener);
}
else {
retriever.applicationListenerBeans.add(listenerBeanName);
}
}
allListeners.add(listener);
}
}
else {
Object listener = beanFactory.getSingleton(listenerBeanName);
if (retriever != null) {
retriever.applicationListeners.remove(listener);
}
allListeners.remove(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
}
}
}
// 對監聽器列表進行排序
AnnotationAwareOrderComparator.sort(allListeners);
if (retriever != null && retriever.applicationListenerBeans.isEmpty()) {
retriever.applicationListeners.clear();
retriever.applicationListeners.addAll(allListeners);
}
return allListeners;
}
獲取感興趣的事件判斷邏輯
protected boolean supportsEvent(
ApplicationListener<?> listener, ResolvableType eventType, @Nullable Class<?> sourceType) {
// 必須是 GenericApplicationListener 監聽器類型,如果不是需要進行轉換
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
構建為 GenericApplicationListenerAdapter
public GenericApplicationListenerAdapter(ApplicationListener<?> delegate) {
Assert.notNull(delegate, "Delegate listener must not be null");
this.delegate = (ApplicationListener<ApplicationEvent>) delegate;
this.declaredEventType = resolveDeclaredEventType(this.delegate);
}
@Nullable
private static ResolvableType resolveDeclaredEventType(ApplicationListener<ApplicationEvent> listener) {
ResolvableType declaredEventType = resolveDeclaredEventType(listener.getClass());
if (declaredEventType == null || declaredEventType.isAssignableFrom(ApplicationEvent.class)) {
Class<?> targetClass = AopUtils.getTargetClass(listener);
if (targetClass != listener.getClass()) {
declaredEventType = resolveDeclaredEventType(targetClass);
}
}
return declaredEventType;
}
@Nullable
static ResolvableType resolveDeclaredEventType(Class<?> listenerType) {
ResolvableType eventType = eventTypeCache.get(listenerType);
if (eventType == null) {
eventType = ResolvableType.forClass(listenerType).as(ApplicationListener.class).getGeneric();
eventTypeCache.put(listenerType, eventType);
}
return (eventType != ResolvableType.NONE ? eventType : null);
}
進入 GenericApplicationListenerAdapter 類 supportsEventType 和 supportsSourceType 方法
@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 {
return (this.declaredEventType == null || this.declaredEventType.isAssignableFrom(eventType));
}
}
@Override
public boolean supportsSourceType(@Nullable Class<?> sourceType) {
return !(this.delegate instanceof SmartApplicationListener) ||
((SmartApplicationListener) this.delegate).supportsSourceType(sourceType);
}
我們回到 invokeListener 方法的實現上來:
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 發送事件
listener.onApplicationEvent(event);
} catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass())) {
Log logger = LogFactory.getLog(getClass());
if (logger.isTraceEnabled()) {
logger.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
四、自定義監聽器
自定義監聽器事件也有三種方式,我們依次來實現下。首先我們先創建三個監聽器:
@Order(1)
public class FirstListner implements ApplicationListener<ApplicationStartingEvent> {
@Override
public void onApplicationEvent(ApplicationStartingEvent event) {
System.out.println("run firstListner");
}
}
public class SecondListner implements ApplicationListener<ApplicationStartingEvent> {
@Override
public void onApplicationEvent(ApplicationStartingEvent event) {
System.out.println("run SecondListner");
}
}
public class ThirdListner implements ApplicationListener<ApplicationStartingEvent> {
@Override
public void onApplicationEvent(ApplicationStartingEvent event) {
System.out.println("run ThirdListner");
}
}
4.1 在 application.properties 配置文件中配置
context.listner.classes=com.learn.springboot.listener.FirstListner
4.2 在 META-INF/spring.factories 文件中配置
org.springframework.context.ApplicationListener=com.learn.springboot.listener.SecondListner
4.3 在代碼中配置
public static void main(String[] args) {
// SpringApplication.run(SpringbootApplication.class, args);
SpringApplication springApplication = new SpringApplication(SpringbootApplication.class);
springApplication.addListeners(new ThirdListner());
springApplication.run();
}
啟動項目,觀察控制台輸出:
run firstListner
run SecondListner
run ThirdListner
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.5.RELEASE)
