All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alibaba.nacos.common.notify.DefaultPublisher Maven / Gradle / Ivy

There is a newer version: 2.4.2
Show newest version
/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.alibaba.nacos.common.notify;

import com.alibaba.nacos.common.notify.listener.Subscriber;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.ConcurrentHashSet;
import com.alibaba.nacos.common.utils.ThreadUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

import static com.alibaba.nacos.common.notify.NotifyCenter.ringBufferSize;

/**
 * The default event publisher implementation.
 *
 * 

Internally, use {@link ArrayBlockingQueue } as a message staging queue. * * @author liaochuntao * @author zongtanghu */ public class DefaultPublisher extends Thread implements EventPublisher { protected static final Logger LOGGER = LoggerFactory.getLogger(NotifyCenter.class); private volatile boolean initialized = false; private volatile boolean shutdown = false; private Class eventType; protected final ConcurrentHashSet subscribers = new ConcurrentHashSet<>(); private int queueMaxSize = -1; private BlockingQueue queue; protected volatile Long lastEventSequence = -1L; private static final AtomicReferenceFieldUpdater UPDATER = AtomicReferenceFieldUpdater .newUpdater(DefaultPublisher.class, Long.class, "lastEventSequence"); @Override public void init(Class type, int bufferSize) { setDaemon(true); setName("nacos.publisher-" + type.getName()); this.eventType = type; this.queueMaxSize = bufferSize; if (this.queueMaxSize == -1) { this.queueMaxSize = ringBufferSize; } this.queue = new ArrayBlockingQueue<>(this.queueMaxSize); start(); } public ConcurrentHashSet getSubscribers() { return subscribers; } @Override public synchronized void start() { if (!initialized) { // start just called once super.start(); initialized = true; } } @Override public long currentEventSize() { return queue.size(); } @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; // To ensure that messages are not lost, enable EventHandler when // waiting for the first Subscriber to register while (!shutdown && !hasSubscriber() && waitTimes > 0) { ThreadUtils.sleep(1000L); waitTimes--; } while (!shutdown) { 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); } } private boolean hasSubscriber() { return CollectionUtils.isNotEmpty(subscribers); } @Override public void addSubscriber(Subscriber subscriber) { subscribers.add(subscriber); } @Override public void removeSubscriber(Subscriber subscriber) { subscribers.remove(subscriber); } @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); receiveEvent(event); return true; } return true; } void checkIsStart() { if (!initialized) { throw new IllegalStateException("Publisher does not start"); } } @Override public void shutdown() { this.shutdown = true; this.queue.clear(); } public boolean isInitialized() { return initialized; } /** * Receive and notifySubscriber to process the event. * * @param event {@link Event}. */ void receiveEvent(Event event) { final long currentEventSequence = event.sequence(); if (!hasSubscriber()) { LOGGER.warn("[NotifyCenter] the {} is lost, because there is no subscriber.", event); return; } // Notification single event listener for (Subscriber subscriber : subscribers) { if (!subscriber.scopeMatches(event)) { continue; } // Whether to ignore expiration events 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); final Runnable job = () -> subscriber.onEvent(event); final Executor executor = subscriber.executor(); if (executor != null) { executor.execute(job); } else { try { job.run(); } catch (Throwable e) { LOGGER.error("Event callback exception: ", e); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy