前面一章主要学习了系统监听器在springboot中是在怎样运行的,这章主要围绕starting事件来学习springboot事件的触发机制。
public void starting() {
Iterator var1 = this.listeners.iterator();
while(var1.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var1.next();
listener.starting();
}
}
public void starting() {
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
从代码可以看出,它是通过SpringApplicationRunListener接口去调用它内部的starting方法。starting方法的具体实现是使用广播器去发送一个ApplicationStartingEvent事件。springboot通过这种机制使得监听器的内部实现和外部调用隔离开了。springboot在运行阶段只需要调用SpringApplicationRunListener的各个方法就可以了。不需要springboot自己去构造相应的事件来发送。
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
//获取事件类型
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
//获取线程池
Executor executor = getTaskExecutor();
//getApplicationListeners获取感兴趣的监听器
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
//执行监听器
invokeListener(listener, event);
}
}
}
上面代码是springboot广播器源码,先获取事件类型,在获取线程池,最后获取对该事件感兴趣的监听器,并执行这些监听器。整个流程非常的简单,这里需要重点关注的方法getApplicationListeners(),下面重点学习下这个方法,看看springboot是如何获取到对当前事件感兴趣的监听器的。
protected Collection<ApplicationListener<?>> getApplicationListeners(
ApplicationEvent event, ResolvableType eventType) {
//获取source
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)))) {
//进入同步方法
synchronized (this.retrievalMutex) {
//再次从缓存中获取对该事件感兴趣的监听器,防止其他线程已经对监听器进行了过滤
retriever = this.retrieverCache.get(cacheKey);
if (retriever != null) {
return retriever.getApplicationListeners();
}
retriever = new ListenerRetriever(true);
//通过retrieveApplicationListeners方法去判断监听器是否对当前事件感兴趣
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);
}
}
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) {
//获取applicationListeners(从spring.factories中获取)
listeners = new LinkedHashSet<>(this.defaultRetriever.applicationListeners);
//获取applicationListenerBeans
listenerBeans = new LinkedHashSet<>(this.defaultRetriever.applicationListenerBeans);
}
//遍历listeners
for (ApplicationListener<?> listener : listeners) {
//通过supportsEvent方法来判断监听器是否对该事件感兴趣
if (supportsEvent(listener, eventType, sourceType)) {
if (retriever != null) {
//添加监听器
retriever.applicationListeners.add(listener);
}
allListeners.add(listener);
}
}
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 {
// Remove non-matching listeners that originally came from
// ApplicationListenerDetector, possibly ruled out by additional
// BeanDefinition metadata (e.g. factory method generics) above.
Object listener = beanFactory.getSingleton(listenerBeanName);
if (retriever != null) {
retriever.applicationListeners.remove(listener);
}
allListeners.remove(listener);
}
}
catch (NoSuchBeanDefinitionException ex) {
// Singleton listener instance (without backing bean definition) disappeared -
// probably in the middle of the destruction phase
}
}
}
//对监听器进行排序
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类型的,就返回该监听器
//如果不是则用GenericApplicationListenerAdapter封装该监听器
GenericApplicationListener smartListener = (listener instanceof GenericApplicationListener ?
(GenericApplicationListener) listener : new GenericApplicationListenerAdapter(listener));
return (smartListener.supportsEventType(eventType) && smartListener.supportsSourceType(sourceType));
}
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));
}
}
以上代码就是springboot获取到对当前事件感兴趣的监听器主要步骤,代码只截取了关键部分,感兴趣的可以自己去源码当中debug走一遍。下面总结下流程:
getApplicationListeners类中:
- 首先从缓存中获取对当前事件感兴趣的监听器,主要是为了节省资源。
- 如果缓存中没有,则用同步方法锁锁住该方法,再次去缓存中获取,目的是防止已经有其它线程完成了监听器比对。
- 完后调用retrieveApplicationListeners方法去检索对当前事件感兴趣的监听器。
retrieveApplicationListeners类中:
- 先获取同步锁,然后从spring.factories中获取所有监听器
- 完后根据supportsEvent来判断该监听器是否对该事件感兴趣,如果感兴趣返回true并加入到监听器集合中
supportsEvent类中:
- 首先判断listener是否属于GenericApplicationListener,如果属于就返回listener,否则使GenericApplicationListenerAdapter对监听器进行封装。
- 然后使用supportsEventType和supportsSourceType进行判断(该方法永远返回true)
supportsEventType类中:
- 先判断是不是SmartApplicationListener子类,如果是则获取事件类型的Class对象,完后进行判断
- 如果不是则判断当前监听器的事件类型是否为空或者是否为当前事件的父类。
这是springboot在获取对当前事件感兴趣的监听器各个类中的方法以及步骤。
在了解了springboot监听机制后,在了解一下我们该如何实现自己的监听器并将监听器加入到我们springboot容器当中。
在之前章节中学习了如何向springboot添加系统初始化器,这里监听器的添加与添加系统初始化器的方式基本一样,一共分为三种:1.在spring.factories中通过key-value方式加入。2.在application中用硬编码的方式进行添加。3.在application.yml中添加。原理注意点基本与系统初始化器一致,这里就不在进行描述了。
下面主要看一下监听器在springboot中如何实现:
@Order(1)
public class FirstListener implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent applicationStartedEvent) {
System.out.println("第一个触发器");
}
}
这种方式通过继承ApplicationListener<ApplicationStartedEvent>接口并给定事件类型进行实现
@Order(4)
public class FourthListener implements SmartApplicationListener {
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> aClass) {
return ApplicationStartedEvent.class.isAssignableFrom(aClass) || ApplicationPreparedEvent.class
.isAssignableFrom(aClass);
}
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent) {
if (ApplicationStartedEvent.class.isAssignableFrom(applicationEvent.getClass())){
System.out.println("ApplicationStartedEvent");
}else if (ApplicationPreparedEvent.class.isAssignableFrom(applicationEvent.getClass())){
System.out.println("ApplicationPreparedEvent");
}else {
System.out.println(1111);
}
}
}
这种方式则是通过实现SmartApplicationListener接口进行实现,较第一种实现方法来说,该方法可以指定多个事件类型。