最近在看apollo源码,发现一个自己没怎么玩过的东西,就研究下看看,就是事件的监听。
定义一个事件类MyEvent。
public class MyEvent extends ApplicationEvent { public MyEvent(Object source) { super(source); } public EventDto getEventDto() { return (EventDto) getSource(); } }
定义一个事件传输对象类EventDto,就是相当于一个事件的载体。
@Data public class EventDto { private String name; private String content; }
定义一个监听类MyListener,用于接受处理订阅事件,如果这里有多个需要订阅的相同的事件的类的话,就可以在写一个MyListenerB,然后实现ApplicationListener<MyEvent>即可。
@Component public class MyListener implements ApplicationListener<MyEvent> { @Override public void onApplicationEvent(MyEvent event) { try { EventDto eventDto = event.getEventDto(); Thread.sleep(2000); System.out.println(eventDto); System.out.println(Thread.currentThread().getName() + Thread.currentThread().getId()); } catch (Exception ex) { System.out.println(ex); } } }
然后写示例代码,发布一个事件。
private final ApplicationEventPublisher publisher; @RequestMapping("/index") public String index() { EventDto eventDto = new EventDto(); eventDto.setContent("我是content"); eventDto.setName("我是name"); MyEvent myEvent = new MyEvent(eventDto); publisher.publishEvent(myEvent); return "推送数据成功" + Thread.currentThread().getName() + Thread.currentThread().getId(); }
上述这种事件的订阅会发现每搞一个订阅都要重新建立一个类,并继承Listener,下面介绍一种通过注解@EventListener的方式直接来实现监听,把MyListener类进行调整成下述的代码所示即可。如果同一事件订阅多个监听,复制一份,参数不变即可。
@Component public class MyListener { @EventListener public void onApplicationEvent(MyEvent event) { try { EventDto eventDto = event.getEventDto(); Thread.sleep(2000); System.out.println(eventDto); System.out.println(Thread.currentThread().getName() + Thread.currentThread().getId()); } catch (Exception ex) { System.out.println(ex); } } }
事件的应用就到这里结束,下面简单刨析下源码看看。
1、我们通过ApplicationEventPublisher类的publishEvent方法进去看看,他的实现类是AbstractApplicationContext,因此可以直接到这个类中查看。
protected void publishEvent(Object event, @Nullable ResolvableType eventType) { Assert.notNull(event, "Event must not be null"); // Decorate event as an ApplicationEvent if necessary ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent) event; } else { applicationEvent = new PayloadApplicationEvent<>(this, event); if (eventType == null) { eventType = ((PayloadApplicationEvent<?>) applicationEvent).getResolvableType(); } } // Multicast right now if possible - or lazily once the multicaster is initialized //这个东西暂时我也不知道是干啥子 if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else { //代码会进到这里,将消息进行广播,继续进去 getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); } // Publish event via parent context as well... if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext) { ((AbstractApplicationContext) this.parent).publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } }
SimpleApplicationEventMulticaster实现类
@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); } } }
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); } }
拿到指定的监听器类型就可以进行调用相应的监听方法了。
使用事件而不直接调用方法,重点是解耦,比如,村里喇叭响,村民A听到喇叭响就去地里干活,如果只有一个村民,那调就调了,但是如果有N多村民呢?因此每个村民订阅这个喇叭事件,听到就去地里干活,如果新增加一个村民就订阅这个事件即可。
来源:oschina
链接:https://my.oschina.net/uwith/blog/4269352