我们来以应用启动事件:applicationstartingevent为例来进行说明:
以启动类的springapplication.run方法为入口,跟进springapplication的两个同名方法后,我们会看到主要的run方法,方法比较长,在这里只贴出与监听器密切相关的关键的部分:
springapplicationrunlisteners listeners = getrunlisteners(args);listeners.starting();
我们跟进这个starting方法,方法的内容如下:
void starting() { for (springapplicationrunlistener listener : this.listeners) { listener.starting(); }}
这里的listeners已经在getrunlisteners方法中完成了加载,加载原理类似于系统初始化器,关于系统初始化器的加载可以参考springboot深入浅出分析初始化器
starting方法逻辑很简单,就是调用springapplicationrunlistener的starting方法。下面继续分析这个starting方法:
我们进入了eventpublishingrunlistener类(springapplicationrunlistener 的实现类)的starting方法:
@override public void starting() { this.initialmulticaster.multicastevent(new applicationstartingevent(this.application, this.args)); }
这里就使用了广播器,来广播新的applicationstartingevent事件。
我们跟进这个multicastevent方法:
@override public void multicastevent(applicationevent event) { multicastevent(event, resolvedefaulteventtype(event)); }
继续看同名的方法multicastevent:
@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); } } }
这里的resolvabletype 是对event做了包装,我们不去关注;由于我们没有创建线程池,所以executor是空的。我们重点关注两个部分:
获取所有监听此事件的应用程序监听器
2、invokelistener --> 激活监听器;
getapplicationlisteners (abstractapplicationeventmulticaster类中)方法,代码如下:
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); } }
入参中的event就是applicationstartingevent,sourcetype是org.springframework.boot.springapplication类。我把listenerretriever类型看作一个存储监听器的容器。
可以看出,程序首先在缓存里面寻找listenerretriever类型的retriever,如果没有找到,加锁再从缓存里面找一次。这里我们缓存里是没有内容的,所以都不会返回。
然后使用retrieveapplicationlisteners方法,对监听器进行遍历。retrieveapplicationlisteners方法比较长,我们重点关注下supportsevent(listener, eventtype, sourcetype)方法,该方法用来判断是否此监听器关注该事件,过程主要包括,判断此类型是否是genericapplicationlistener类型,如果不是,则构造一个代理,代理的目的是,通过泛型解析,最终获得监听器所感兴趣的事件。
如果经过判断,监听器对该事件是感兴趣的,则此监听器会被加入监听器列表中。
protected boolean supportsevent( applicationlistener<?> listener, resolvabletype eventtype, @nullable class<?> sourcetype) { genericapplicationlistener smartlistener = (listener instanceof genericapplicationlistener ? (genericapplicationlistener) listener : new genericapplicationlisteneradapter(listener)); return (smartlistener.supportseventtype(eventtype) && smartlistener.supportssourcetype(sourcetype)); }
当某个事件所有的监听器被收集完毕后,multicastevent(simpleapplicationeventmulticaster类)方法会对事件进行传播。即调用监听器的通用触发接口方法:listener.onapplicationevent(event);这样,就完成了这个事件的传播。
以上就是springboot监听器模式怎么实现的详细内容。