03.Nacos事件驱动架构源码

146 阅读5分钟

Nacos事件驱动架构源码

1.体验Nacos源码提供的事件驱动架构功能

角色

  1. 事件
  2. 事件订阅者
  3. 事件发送者

源码

事件
/**
 * @author IT贱男,继承Event是Nacos源码里面的
 * @version v1.0.0
 * @date 2023/3/13 11:01
 */
public class TestEvent extends Event {
}
事件订阅者

/**
 * 订阅者
 *
 * @author IT贱男
 * @version v1.0.0
 * @date 2023/3/13 10:57
 */
@Component
public class TestSubscriber extends SmartSubscriber {

    public TestSubscriber() {
        NotifyCenter.registerSubscriber(this);
    }

    @Override
    public List<Class<? extends Event>> subscribeTypes() {
        List<Class<? extends Event>> result = new LinkedList<>();
        result.add(TestEvent.class);
        return result;
    }

    @Override
    public void onEvent(Event event) {
        System.out.println("TestSubscriber onEvent");
    }
}
事件发送者
@RestController
@RequestMapping("/sub")
public class SubscriberController {
    @GetMapping("/test")
    public void test(){
        NotifyCenter.publishEvent(new TestEvent());
    }
}

2.图示

EventPublisher图示

添加事件订阅者流程

发布事件流程

3.源码

DefaultPublisher类

介绍

负责存储事件和推送事件给绑定事件的所有消费者

继承结构

核心属性
    /**启动标识*/
    private volatile boolean initialized = false;
    /**终止标识*/
    private volatile boolean shutdown = false;
    /**该事件发布者对应的类型*/
    private Class<? extends Event> eventType;
    /**该事件发布者绑定的所有监听者*/
    protected final ConcurrentHashSet<Subscriber> subscribers = new ConcurrentHashSet<>();
    /**队列的最大大小*/
    private int queueMaxSize = -1;
    /**存储事件的队列*/
    private BlockingQueue<Event> queue;
    
    protected volatile Long lastEventSequence = -1L;
核心方法init

设置各种属性和启动Thread

    @Override
    public void init(Class<? extends Event> type, int bufferSize) {
        // 设置守护线程
        setDaemon(true);
        // 设置名称
        setName("nacos.publisher-" + type.getName());
        // 设置事件类型
        this.eventType = type;
        // 设置队列大小
        this.queueMaxSize = bufferSize;
        // 设置队列
        this.queue = new ArrayBlockingQueue<>(bufferSize);
        // 启动线程消费队列
        start();
    }
    @Override
    public synchronized void start() {
        if (!initialized) {
            // start just called once
            super.start();
            if (queueMaxSize == -1) {
                queueMaxSize = ringBufferSize;
            }
            initialized = true;
        }
    }
核心方法addSubscriber

添加对应的事件订阅者

    @Override
    public void addSubscriber(Subscriber subscriber) {
        // 添加订阅者
        subscribers.add(subscriber);
    }
核心方法publish

发布事件

    @Override
    public boolean publish(Event event) {
        checkIsStart();
        // 放到阻塞队列中
        boolean success = this.queue.offer(event);
        // 已经满了放入失败
        if (!success) {
            LOGGER.warn("Unable to plug in due to interruption, synchronize sending time, event : {}", event);
            // 直接消费事件然后返回true
            receiveEvent(event);
            return true;
        }
        return true;
    }
核心方法run

线程拉取事件并消费的方法,由当前线程执行

    @Override
    public void run() {
        openEventHandler();
    }
    void openEventHandler() {
        try {
            
            // 定义此变量是为了解决队列中信息过量的问题
            int waitTimes = 60;
            // 为确保信息不会丢失,请在以下情况下启用 EventHandler
            // 等待第一个订阅者注册
            for (; ; ) {
                if (shutdown || hasSubscriber() || waitTimes <= 0) {
                    break;
                }
                ThreadUtils.sleep(1000L);
                waitTimes--;
            }
            // 自选
            for (; ; ) {
                // 如果shutdown了就停止
                if (shutdown) {
                    break;
                }
                // 从队列中获取一个Event
                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);
        }
    }
    void receiveEvent(Event event) {
        final long currentEventSequence = event.sequence();
        
        if (!hasSubscriber()) {
            LOGGER.warn("[NotifyCenter] the {} is lost, because there is no subscriber.", event);
            return;
        }

        // 循环遍历通知发布事件对应的订阅者
        for (Subscriber subscriber : subscribers) {
            // 是否忽略过期事件
            if (subscriber.ignoreExpireEvent() && lastEventSequence > currentEventSequence) {
                LOGGER.debug("[NotifyCenter] the {} is unacceptable to this subscriber, because had expire",
                        event.getClass());
                continue;
            }
            
            // Because unifying smartSubscriber and subscriber, so here need to think of compatibility.
            // Remove original judge part of codes.
            //通知
            notifySubscriber(subscriber, event);
        }
    }
    @Override
    public void notifySubscriber(final Subscriber subscriber, final Event event) {
        
        LOGGER.debug("[NotifyCenter] the {} will received by {}", event, subscriber);
        // 把subscriber的执行封装到Runnable中
        final Runnable job = () -> subscriber.onEvent(event);
        // 获取执行器,默认是NULL
        final Executor executor = subscriber.executor();
        // 如果有则用这个监听器返回的线程池来异步执行任务
        if (executor != null) {
            executor.execute(job);
        } else {
            try {
                // 否则用这个线程来执行任务
                job.run();
            } catch (Throwable e) {
                LOGGER.error("Event callback exception: ", e);
            }
        }
    }

NotifyCenter类

核心属性
    /**创建事件发布者对象的队列的大小*/
    public static int ringBufferSize;
    
    private static final AtomicBoolean CLOSED = new AtomicBoolean(false);
    /**用于创建事件发布者的工厂*/
    private static final EventPublisherFactory DEFAULT_PUBLISHER_FACTORY;
    /**实例*/
    private static final NotifyCenter INSTANCE = new NotifyCenter();
    /**默认sharePublisher的*/
    private DefaultSharePublisher sharePublisher;
    /**要创建EventPublisher的类型*/
    private static Class<? extends EventPublisher> clazz;
    /**
     * 发布者管理容器
     * key:topic
     * value:对应的EventPublisher
     */
    private final Map<String, EventPublisher> publisherMap = new ConcurrentHashMap<>(16);
核心方法静态代码块

主要就是初始化各种东西

    static {
        // Internal ArrayBlockingQueue buffer size. For applications with high write throughput,
        // this value needs to be increased appropriately. default value is 16384
        String ringBufferSizeProperty = "nacos.core.notify.ring-buffer-size";
        ringBufferSize = Integer.getInteger(ringBufferSizeProperty, 16384);
        
        // The size of the public publisher's message staging queue buffer
        String shareBufferSizeProperty = "nacos.core.notify.share-buffer-size";
        shareBufferSize = Integer.getInteger(shareBufferSizeProperty, 1024);
        
        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 {
                // 创建一个DefaultPublisher
                EventPublisher publisher = clazz.newInstance();
                // 调用init方法
                publisher.init(cls, buffer);
                // 返回
                return publisher;
            } catch (Throwable ex) {
                LOGGER.error("Service class newInstance has error : ", ex);
                throw new NacosRuntimeException(SERVER_ERROR, ex);
            }
        };
        
        try {
            
            // Create and init DefaultSharePublisher instance.
            INSTANCE.sharePublisher = new DefaultSharePublisher();
            INSTANCE.sharePublisher.init(SlowEvent.class, shareBufferSize);
            
        } catch (Throwable ex) {
            LOGGER.error("Service class newInstance has error : ", ex);
        }
        
        ThreadUtils.addShutdownHook(NotifyCenter::shutdown);
    }
核心方法publishEvent

发布事件

    public static boolean publishEvent(final Event event) {
        try {
            return publishEvent(event.getClass(), event);
        } catch (Throwable ex) {
            LOGGER.error("There was an exception to the message publishing : ", ex);
            return false;
        }
    }
    private static boolean publishEvent(final Class<? extends Event> eventType, final Event event) {
        if (ClassUtils.isAssignableFrom(SlowEvent.class, eventType)) {
            return INSTANCE.sharePublisher.publish(event);
        }
        // 获取所传类从java语言规范定义的格式输出
        final String topic = ClassUtils.getCanonicalName(eventType);
        // 根据topic获取EventPublisher
        EventPublisher publisher = INSTANCE.publisherMap.get(topic);
        // 如果存在则调用publish方法
        if (publisher != null) {
            return publisher.publish(event);
        }
        LOGGER.warn("There are no [{}] publishers for this event, please register", topic);
        return false;
    }
核心方法registerSubscriber

注册事件订阅者

    public static void registerSubscriber(final Subscriber consumer) {
        registerSubscriber(consumer, DEFAULT_PUBLISHER_FACTORY);
    }
    public static void registerSubscriber(final Subscriber consumer, final EventPublisherFactory factory) {
        // 如果要监听多个事件,则需要分别进行
        // 根据子类的 subscribeTypes 方法返回列表,它可以向发布者注册
        if (consumer instanceof SmartSubscriber) {
            // 遍历这个监听者支持的所有监听事件类型
            for (Class<? extends Event> subscribeType : ((SmartSubscriber) consumer).subscribeTypes()) {
                // For case, producer: defaultSharePublisher -> consumer: smartSubscriber.
                if (ClassUtils.isAssignableFrom(SlowEvent.class, subscribeType)) {
                    INSTANCE.sharePublisher.addSubscriber(consumer, subscribeType);
                } else {
                    // 添加订阅者
                    addSubscriber(consumer, subscribeType, factory);
                }
            }
            return;
        }
        // 逻辑跟上面一样,省略
        final Class<? extends Event> subscribeType = consumer.subscribeType();
        if (ClassUtils.isAssignableFrom(SlowEvent.class, subscribeType)) {
            INSTANCE.sharePublisher.addSubscriber(consumer, subscribeType);
            return;
        }
        
        addSubscriber(consumer, subscribeType, factory);
    }
    private static void addSubscriber(final Subscriber consumer, Class<? extends Event> subscribeType,
            EventPublisherFactory factory) {
        // 根据事件类型获取topic
        final String topic = ClassUtils.getCanonicalName(subscribeType);
        // 上锁
        synchronized (NotifyCenter.class) {
            // MapUtils.computeIfAbsent 是一个不安全的方法
            // 这里很关键,会创建 EventPublisher 对象,一个事件会对应一个 EventPublisher 一个对象
            MapUtil.computeIfAbsent(INSTANCE.publisherMap, topic, factory, subscribeType, ringBufferSize);
        }
        // 获取EventPublisher
        EventPublisher publisher = INSTANCE.publisherMap.get(topic);
        if (publisher instanceof ShardedEventPublisher) {
            ((ShardedEventPublisher) publisher).addSubscriber(consumer, subscribeType);
        } else {
            // 往 EventPublisher 对象添加订阅者信息
            publisher.addSubscriber(consumer);
        }
    }