这里写自定义目录标题
- [1. 概述(重点)](#1. 概述(重点))
- [2. ApplicationEventMulticaster](#2. ApplicationEventMulticaster)
-
- [2.1 SimpleApplicationEventMulticaster](#2.1 SimpleApplicationEventMulticaster)
- [2.2 AbstractApplicationEventMulticaster](#2.2 AbstractApplicationEventMulticaster)
- [3. ApplicationListener](#3. ApplicationListener)
-
- [3.1 注册监听器](#3.1 注册监听器)
- [3.2 自定义](#3.2 自定义)
- [4. SpringApplicationRunListeners](#4. SpringApplicationRunListeners)
1. 概述(重点)
事件监听机制是观察者模式的一种,Spring的事件监听机制有几个重要的顶层接口,分别是:
- ApplicationEventMulticaster 主要看 AbstractApplicationEventMulticaster
- ApplicationListener
- ApplicationEvent
它们三哥们的关系可以用下面的图来概括
AbstractApplicationEventMulticaster维护了 源类型和事件类型 作为KEY 跟 监听器的关系,在下面 [2.1 SimpleApplicationEventMulticaster](#2.1 SimpleApplicationEventMulticaster)有代码的实现解读。
2. ApplicationEventMulticaster
AbstractApplicationEventMulticaster <<Interface>> ApplicationEventMulticaster <<Interface>> Aware <<Interface>> BeanClassLoaderAware <<Interface>> BeanFactoryAware SimpleApplicationEventMulticaster
目前就只有一个实现类SimpleApplicationEventMulticaster
和一个抽象类AbstractApplicationEventMulticaster
。
2.1 SimpleApplicationEventMulticaster
发布和广播事件,主要注意一下getApplicationListeners方法就行了,会根据事件类型
和源类型
找监听器。
java
@Override
public void multicastEvent(ApplicationEvent event) {
multicastEvent(event, resolveDefaultEventType(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);
}
}
}
2.2 AbstractApplicationEventMulticaster
getApplicationListeners
方法就是根据Class<?>、ResolvableType两个对象作为一个缓存key,这个key与一堆监听器`ApplicationListener`做映射,也就是说通过Class<?>、ResolvableType两个对象可以找到监听器,在用法上可以从SimpleApplicationEventMuticaster
的 multicastEvent
方法去看。
看看getApplicationListeners方法的代码实现
java
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);
CachedListenerRetriever newRetriever = null;
// 这个cacheKey就是ApplicationEvent,ResolvableType两个对象。
// 根据cacheKey找监听器,找不到就把cacheKey作为key,创建一个什么都么有的CachedListenerRetriever对象作为值缓存到retrieverCache中。
// 这里有一些细节我没搞明白,putIfAbsent总是返回null。
CachedListenerRetriever existingRetriever = this.retrieverCache.get(cacheKey);
if (existingRetriever == null) {
if (this.beanClassLoader == null ||
(ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) &&
(sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
newRetriever = new CachedListenerRetriever();
existingRetriever = this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
if (existingRetriever != null) {
newRetriever = null; // no need to populate it in retrieveApplicationListeners
}
}
}
if (existingRetriever != null) {
Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners();
if (result != null) {
return result;
}
}
// 假设上面cacheKey对应的值没有监听器,那这个方面就找 给定事件类型和源类型 的监听器。
return retrieveApplicationListeners(eventType, sourceType, newRetriever);
}
// 从默认的 defaultRetriever 和 我们注入的bean 中找监听器。
private Collection<ApplicationListener<?>> retrieveApplicationListeners(
ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable CachedListenerRetriever retriever) {
List<ApplicationListener<?>> allListeners = new ArrayList<>();
Set<ApplicationListener<?>> filteredListeners = (retriever != null ? new LinkedHashSet<>() : null);
Set<String> filteredListenerBeans = (retriever != null ? new LinkedHashSet<>() : null);
Set<ApplicationListener<?>> listeners;
Set<String> listenerBeans;
synchronized (this.defaultRetriever) {
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
// 从defaultRetriever中找监听器
// 这里的supportsEvent有点看不懂,不过只要理解通过事件类型和源类型判断监听器是否符合 事件要求就得了。
for (ApplicationListener<?> listener : listeners) {
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
filteredListeners.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)) {
filteredListeners.add(listener);
}
else {
filteredListenerBeans.add(listenerBeanName);
}
}
allListeners.add(listener);
}
}
else {
Object listener = beanFactory.getSingleton(listenerBeanName);
if (retriever != null) {
filteredListeners.remove(listener);
}
allListeners.remove(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
}
}
}
// 把找到的监听器都放到CachedListenerRetriever中。
AnnotationAwareOrderComparator.sort(allListeners);
if (retriever != null) {
if (filteredListenerBeans.isEmpty()) {
retriever.applicationListeners = new LinkedHashSet<>(allListeners);
retriever.applicationListenerBeans = filteredListenerBeans;
}
else {
retriever.applicationListeners = filteredListeners;
retriever.applicationListenerBeans = filteredListenerBeans;
}
}
return allListeners;
}
3. ApplicationListener
主要是了解如何注册和自定义监听器就行了
3.1 注册监听器
通过META-INF/spring.factories
注册监听器。
java
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();
this.bootstrapRegistryInitializers = new ArrayList<>(
getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 这里就是注册ApplicationListener的代码了,通过META-INF/spring.factories注册。
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
3.2 自定义
java
public class MyApplicationPreparedListener implements ApplicationListener<ApplicationPreparedEvent> {
@Override
public void onApplicationEvent(ApplicationPreparedEvent event) {
System.out.println("开始填充上下文。。。。");
}
}
MATE-INF/spring.factories
txt
org.springframework.context.ApplicationListener=sample.config.MyApplicationPreparedListener
4. SpringApplicationRunListeners
SpringApplicationRunListeners
管理了多个EventPublishingRunListener
,EventPublishingRunListener里面包含了事件监听器模型#1.概述(重点)中描述的部分。
java
class SpringApplicationRunListeners {
private final Log log;
private final List<SpringApplicationRunListener> listeners;
private final ApplicationStartup applicationStartup;
...
}
public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
private final SpringApplication application;
private final String[] args;
private final SimpleApplicationEventMulticaster initialMulticaster;
...
}
EventPublishingRunListener
中定义了Spring整个启动过程中会触发的事件,下面对触发位置进行大概的描述,更具体的内容还有待研究。
- starting
在SpringApplication#run,事件ApplicationStartingEvent
- environmentPrepared
在SpringApplication#prepareEnvironment,事件ApplicationEnvironmentPreparedEvent
- contextPrepared
在SpringApplication#prepareContext,事件ApplicationContextInitializedEvent
- contextLoaded
在SpringApplication#prepareContext,事件ApplicationPreparedEvent
- started
在SpringApplication#run,事件ApplicationStartedEvent
- ready
在SpringApplication#run,事件ApplicationReadyEvent
- failed
在SpringApplication#handleRunFailure,事件ApplicationFailedEvent
我们也可以利用上面的事件,自己创建一个监听器,然后放到spring.factories,比如现在注册一个ApplicationPreparedEvent
的监听器。
java
public class MyApplicationPreparedListener implements ApplicationListener<ApplicationPreparedEvent> {
@Override
public void onApplicationEvent(ApplicationPreparedEvent event) {
System.out.println("开始填充上下文。。。。");
}
}
MATE-INF/spring.factories
txt
org.springframework.context.ApplicationListener=sample.config.MyApplicationPreparedListener