nacos的发布者订阅者的实现
nacos2.0采用了订阅者/发布者模式对各类事件的处理进行解耦,本小节将对该实现进行解析。
上图为Nacos事件机制的实现相关类,如果是订阅者/发布者模式的同学一定注意到了Publisher和Subscriber,分别对应了发布者和订阅者。
Publisher & Subscriber
- Publisher 发布者
顶级接口为EventPublisher
public interface EventPublisher extends Closeable {
// 初始化方法,用于初始化发布者关心事件类型和缓存队列大小
void init(Class<? extends Event> type, int bufferSize);
// 当前事件队列大小
long currentEventSize();
// 添加订阅者
void addSubscriber(Subscriber subscriber);
// 移除订阅者
void removeSubscriber(Subscriber subscriber);
// 发布事件
boolean publish(Event event);
// 通知订阅者
void notifySubscriber(Subscriber subscriber, Event event);
}
DefaultPublisher为默认实现,也是我们在使用NotifyCenter时候采用的默认发布者
public class DefaultPublisher extends Thread implements EventPublisher
DefaultPublisher继承了Thread,表明DefaultPublisher为一个线程,其run方法如下
@Override
public void run() {
openEventHandler();
}
void openEventHandler() {
try {
// This variable is defined to resolve the problem which message overstock in the queue.
int waitTimes = 60;
// 当没有停机时,并且没有订阅者时候进行等待,最多等待60秒
while (!shutdown && !hasSubscriber() && waitTimes > 0) {
ThreadUtils.sleep(1000L);
waitTimes--;
}
while (!shutdown) {
// 其中queue为阻塞队列,默认采用ArrayBlockingQueue
final Event event = queue.take();
receiveEvent(event);
// 更新最后一次处理时间
UPDATER.compareAndSet(this, lastEventSequence, Math.max(lastEventSequence, event.sequence()));
}
} catch (Throwable ex) {
LOGGER.error("Event listener exception : ", ex);
}
}
- Subscriber 订阅者
顶级接口为Subscriber
public abstract class Subscriber<T extends Event> {
// 事件回调
public abstract void onEvent(T event);
// 订阅的事件类型
public abstract Class<? extends Event> subscribeType();
// 通过该方法决定订阅者在消费事件时是否在线程池中执行
public Executor executor() {
return null;
}
// 是否无视超时的事件
public boolean ignoreExpireEvent() {
return false;
}
// 判断当前订阅者的作用域是否符合当前事件
public boolean scopeMatches(T event) {
return true;
}
}
除了以上的发布者和订阅者外,我们还需要关注两个类EventPublisherFactory和NotifyCenter。
EventPublishFactory
首先,介绍一下EventPublisherFactory,该类采用了抽象工厂模式用于生产发布者,继承了BiFunction接口,后续的工厂通过实现apply方法完成发布者的建造。
public interface EventPublisherFactory extends BiFunction<Class<? extends Event>, Integer, EventPublisher> {
@Override
EventPublisher apply(Class<? extends Event> eventType, Integer maxQueueSize);
}
NotifyCenter
然后便是关键的NotiyCenter,顾名思义便是事件通知中心,其起到的作用是纳管所有的发布者和进行事件发布。
核心的成员变量如下
public class NotifyCenter {
// 对于非共享的订阅者的事件缓存队列大小
public static int ringBufferSize;
// 对于共享的订阅者的事件缓存队列大小
public static int shareBufferSize;
// notifyCenter是否关闭的标识
private static final AtomicBoolean CLOSED = new AtomicBoolean(false);
// 事件发布者工厂
private static final EventPublisherFactory DEFAULT_PUBLISHER_FACTORY;
// 单例模式
private static final NotifyCenter INSTANCE = new NotifyCenter();
// 共享事件发布者
private DefaultSharePublisher sharePublisher;
// 事件发布者工厂的默认事件发布者类型
private static Class<? extends EventPublisher> clazz;
// key为Event类的小写名称,key为对应事件发布者
private final Map<String, EventPublisher> publisherMap = new ConcurrentHashMap<>(16);
}
其核心方法为
addSubscriber:添加消费者
private static void addSubscriber(final Subscriber consumer, Class<? extends Event> subscribeType,
EventPublisherFactory factory) {
final String topic = ClassUtils.getCanonicalName(subscribeType);
synchronized (NotifyCenter.class) {
// MapUtils.computeIfAbsent is a unsafe method.
MapUtil.computeIfAbsent(INSTANCE.publisherMap, topic, factory, subscribeType, ringBufferSize);
}
EventPublisher publisher = INSTANCE.publisherMap.get(topic);
if (publisher instanceof ShardedEventPublisher) {
((ShardedEventPublisher) publisher).addSubscriber(consumer, subscribeType);
} else {
publisher.addSubscriber(consumer);
}
}
registerToPublisher:该方法注册Event对应的发布者并返回
public static EventPublisher registerToPublisher(final Class<? extends Event> eventType,
final EventPublisherFactory factory, final int queueMaxSize) {
if (ClassUtils.isAssignableFrom(SlowEvent.class, eventType)) {
return INSTANCE.sharePublisher;
}
final String topic = ClassUtils.getCanonicalName(eventType);
synchronized (NotifyCenter.class) {
// MapUtils.computeIfAbsent is a unsafe method.
MapUtil.computeIfAbsent(INSTANCE.publisherMap, topic, factory, eventType, queueMaxSize);
}
return INSTANCE.publisherMap.get(topic);
}
publishEvent:根据事件类型,在publisherMap中找到对应的发布者执行发布。
private static boolean publishEvent(final Class<? extends Event> eventType, final Event event) {
if (ClassUtils.isAssignableFrom(SlowEvent.class, eventType)) {
return INSTANCE.sharePublisher.publish(event);
}
final String topic = ClassUtils.getCanonicalName(eventType);
EventPublisher publisher = INSTANCE.publisherMap.get(topic);
if (publisher != null) {
return publisher.publish(event);
}
if (event.isPluginEvent()) {
return true;
}
LOGGER.warn("There are no [{}] publishers for this event, please register", topic);
return false;
}
此外在NotifyCenter初始化时候还采用了Spi机制对默认的EventPublisher进行自定义
static {
// 省略部分代码
// spi加载
final Collection<EventPublisher> publishers = NacosServiceLoader.load(EventPublisher.class);
Iterator<EventPublisher> iterator = publishers.iterator();
if (iterator.hasNext()) {
clazz = iterator.next().getClass();
} else {
clazz = DefaultPublisher.class;
}
DEFAULT_PUBLISHER_FACTORY = (cls, buffer) -> {
try {
EventPublisher publisher = clazz.newInstance();
publisher.init(cls, buffer);
return publisher;
} catch (Throwable ex) {
LOGGER.error("Service class newInstance has error : ", ex);
throw new NacosRuntimeException(SERVER_ERROR, ex);
}
};
// 省略部分代码
}
总结
nacos通过NotifyCenter对Publisher进行纳管,每一个Event都会被放入对应Publisher的阻塞队列中等待执行。
调用方通过NotifyCenter注册订阅者时,实际上是根据订阅者的事件类型查找或创建对应的发布者,将订阅者注册进入发布者。
调用方通过NotiryCenter对事件进行注册时,实际上是根据订阅者类型查找或者创建对应的发布者。