1. 背景
为啥突然想到写这个?起因就是看到了Nacos的#3757 ISSUE
,理解错误, 以为是服务启动,没有注册上服务,实际namespace不同,导致服务无法注册。 但这丝毫不影响再去研究了一波代码,顺便也看到了Nacos是如何利用Spring的事件来进行服务注册的。分享一波,欢迎大家学习指正!
2. 娓娓道来 - Spring事件
2.1 怎么发布事件
我们大家应该都知道,在Spring中,是通过实现org.springframework.context.ApplicationEventPublisher
来发布一个事件。ApplicationEcentPublisher
是一个接口,我们来看一下接口中逻辑。
public interface ApplicationEventPublisher {
/**
* Notify all <strong>matching</strong> listeners registered with this
* application of an application event. Events may be framework events
* (such as RequestHandledEvent) or application-specific events.
* @param event the event to publish
* @see org.springframework.web.context.support.RequestHandledEvent
*/
default void publishEvent(ApplicationEvent event) {
publishEvent((Object) event);
}
/**
* Notify all <strong>matching</strong> listeners registered with this
* application of an event.
* <p>If the specified {@code event} is not an {@link ApplicationEvent},
* it is wrapped in a {@link PayloadApplicationEvent}.
* @param event the event to publish
* @since 4.2
* @see PayloadApplicationEvent
*/
void publishEvent(Object event);
}
接口很简单,里面有两个方法,都是发布事件,而接口默认实现,是调用publishEvent(Object event)
的实现,唯一的区别就是default方法的参数是具体的事件类。
既然这是个接口,那一定有实现类,那么我们肯定是要进入实现类,快捷键,查看一下具体实现类。
我们通过实现类,可以看到,应该是从AbstractApplicationContext
进去(其他Context都是实现类,凭感觉和代码提示,从第一个类进如代码)。
进去org.springframework.context.support.AbstractApplicationContext
,我们直奔主题,查看是如何实现PublishEvent。具体代码如下:
/**
* Publish the given event to all listeners.
* @param event the event to publish (may be an {@link ApplicationEvent}
* or a payload object to be turned into a {@link PayloadApplicationEvent})
* @param eventType the resolved event type, if known
* @since 4.2
*/
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 = (ApplicationEvent) event;
}
else {
// 将事件装饰成PayloadApplicationEvent,
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) {
// 广播还未初始化完成,放入earlyApplicationEvents.
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);
}
}
}
在这段代码中,我们得到了两点有用的信息,分别是:
- 发布事件的整体流程。(封装事件,广播事件)
- 发布的时间通过
getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);
广播事件
通过代码可以知道,我们接下来的关