在看一些开源代码的时候,经常出现Spring 发布事件的身影。
JDK其实就有监听模式
/**
* @Author lixw
* @Date 5/22/20 8:59 AM
*/
public class Producer extends Observable {
List<Observer> listener = new ArrayList<>();
public Producer() {
//注册监听者
listener.add(new Consumer());
}
//发布更新 --- 广播消费给注册到Producer的消费者
public void publishEvent(){
System.out.println("生产者有更新,通知消费者");
Producer producer = this;
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
for (Observer observer : listener) {
observer.update(producer, LocalDateTime.now().format(formatter) + "发送新的消息");
}
}
public static void main(String[] args) {
new Producer().publishEvent();
}
//定义消费者 也就是监听者
class Consumer implements Observer {
//定义接收到消息的逻辑
@Override
public void update(Observable o, Object arg) {
System.out.println("消费者接受到" + o + "的消息:" + arg);
}
}
}
- 事件的发布者继承Observable
- 事件的监听者实现Observer,
- 定义监听列表,讲监听者注册到发布者列表中
- 发布事件的时候,通过监听者列表进行广播
- 监听者在update中实现监听逻辑
可以看到第三步是建立事件发布者和监听者联系的核心
那么Spring的具体实现呢?结合Spring Boot的自动配置文件加载机制来看看
image.png事件发布者: ApplicationEnvironmentPreparedEvent
类似 JDK的Observable
监听者: ConfigFileApplicationListener
类似 JDK的Observer
查看ApplicationEnvironmentPreparedEvent的源码并没有发现的实现有地方可以注册监听者或者存储监听者
那么两者是如何建立联系的?通过Debug的栈帧,可以看到
image.png
line134: 求出了event(ApplicationEnvironmentPreparedEvent)的所有的监听者,line139通过Debug信息可以看到listener就是ConfigFileApplicationListener
继续看AbstractApplicationEventMulticaster.getApplicationListeners源码
/**
* Return a Collection of ApplicationListeners matching the given
* event type. Non-matching listeners get excluded early.
* @param event the event to be propagated. Allows for excluding
* non-matching listeners early, based on cached matching information.
* @param eventType the event type
* @return a Collection of ApplicationListeners
* @see org.springframework.context.ApplicationListener
*/
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
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);
// 求监听者列表
Collection<ApplicationListener<?>> listeners =
retrieveApplicationListeners(eventType, sourceType, retriever);
//缓存
this.retrieverCache.put(cacheKey, retriever);
return listeners;
}
}
else {
// No ListenerRetriever caching -> no synchronization necessary
return retrieveApplicationListeners(eventType, sourceType, null);
}
}
/**
* Actually retrieve the application listeners for the given event and source type.
* @param eventType the event type
* @param sourceType the event source type
* @param retriever the ListenerRetriever, if supposed to populate one (for caching purposes)
* @return the pre-filtered list of application listeners for the given event and source type
*/
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);
}
// Add programmatically registered listeners, including ones coming
// from ApplicationListenerDetector (singleton beans and inner beans).
for (ApplicationListener<?> listener : listeners) {
//事件和监听者建立联系
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
...
return allListeners;
}
supportsEvent的实现
image.png
继续看ConfigFileApplicationListener实现了SmartApplicationListener
public interface SmartApplicationListener extends ApplicationListener<ApplicationEvent>, Ordered {}
public class ConfigFileApplicationListener implements EnvironmentPostProcessor, SmartApplicationListener, Ordered {
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
|| ApplicationPreparedEvent.class.isAssignableFrom(eventType);
}
}
从
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
可以知道的defaultRetriever中存储了监听者列表是怎么加载的呢?
- 现在SpringApplication的源码(new SpringApplication()的时候执行)
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
//加载了监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
Spring Boot 初始化的时候EventPublishingRunListener的时候会执行
public EventPublishingRunListener(SpringApplication application, String[] args) {
this.application = application;
this.args = args;
this.initialMulticaster = new SimpleApplicationEventMulticaster();
//从SpringApplication拿到监听者列表
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
SimpleApplicationEventMulticaster(AbstractApplicationEventMulticaster)的代码
@Override
public void addApplicationListener(ApplicationListener<?> listener) {
synchronized (this.retrievalMutex) {
// Explicitly remove target for a proxy, if registered already,
// in order to avoid double invocations of the same listener.
Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
if (singletonTarget instanceof ApplicationListener) {
this.defaultRetriever.applicationListeners.remove(singletonTarget);
}
//讲监听器添加到defaultRetriever中
this.defaultRetriever.applicationListeners.add(listener);
this.retrieverCache.clear();
}
}
到这,ApplicationListener是什么时候在那生成,存储在那,如何和event关联就只全部知道了。总结
- SpringApplication有一个ApplicationListener监听者列表,实例化的时候,Spring会ApplicationListener类型通过JDK发射机制生成,保存到SpringApplication的 listeners 列表中
- Spring容器初始化到EventPublishingRunListener的时候,会SpringApplication保存的ApplicationListener实例保存到SimpleApplicationEventMulticaster对象的defaultRetriever对象中
- SpringApplication执行run方法的时候,会生成一个SpringApplicationRunListeners对象
,并且在run方法中,会出发配置环境初始化的工作,并生成ApplicationEnvironmentPreparedEvent事件对象
SpringApplicationRunListeners listeners = getRunListeners(args);
ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
--> listeners.environmentPrepared(environment);
--> listener.environmentPrepared(environment);
--> this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
4.SpringBoot 通过广播机制,发布事件。在SimpleApplicationEventMulticaster并通过ApplicationEvent event和ResolvableType eventType过滤筛选出监听event事件的监听者,触发监听者方法
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
SimpleApplicationEventMulticaster 是个广播者,其拥有全部的SpringListener实例,然后发布事件的时候调用multicastEvent方法,通过方法列表参数过滤出符合条件的了监听者,监听者触发监听逻辑。
网友评论