实现消息总线
- 发布者: publisher
- 订阅者: subscriber
- 事件: event
publisher
EventPublisher:
public interface EventPublisher extends AutoCloseable {
/**
* 广播发布事件
* @param event
*/
void publish(BootEvent event);
/**
* 单个发布
* @param subscriber
* @param event
*/
void notifySubscriber(Subscriber subscriber, BootEvent event);
/**
* 添加订阅者
* @param subscriber
*/
void addSubscriber(Subscriber subscriber);
/**
* 删除订阅者
* @param subscriber
*/
void removeSubscriber(Subscriber subscriber);
}
@Slf4j
public class DefaultEventPublisher extends Thread implements EventPublisher {
private final BlockingQueue<BootEvent> queue;
private List<Subscriber> list = new ArrayList<>();
private Map<Class<? extends BootEvent>, List<Subscriber>> map = new ConcurrentHashMap<>();
private volatile boolean running;
public DefaultEventPublisher(int queueSize) {
queue = new ArrayBlockingQueue<>(queueSize);
setDaemon(true);
setName("DEFAULT-Publisher-");
running = true;
log.info(Thread.currentThread().getName() + " is run..");
start();
}
@Override
public void publish(BootEvent event) {
if (!queue.offer(event)) {
//如果队列已满,则使用调用者线程通知
log.info("publish event failed, queue size is {}, caller thread runs", queue.size());
notifyAllSubscribers(event);
}
}
@Override
public void notifySubscriber(Subscriber subscriber, BootEvent event) {
if (subscriber.executor() != null) {
subscriber.executor().submit(() -> subscriber.onEvent(event));
} else {
subscriber.onEvent(event);
}
}
@Override
public void addSubscriber(Subscriber subscriber) {
list.add(subscriber);
map.computeIfAbsent(subscriber.supportedType(), clz -> new ArrayList<>());
map.get(subscriber.supportedType()).add(subscriber);
}
@Override
public void removeSubscriber(Subscriber subscriber) {
list.remove(subscriber);
if (map.containsKey(subscriber.supportedType())) {
map.remove(subscriber.supportedType());
}
}
@Override
public void run() {
while (running) {
try {
BootEvent event = queue.take();
notifyAllSubscribers(event);
} catch (InterruptedException e) {
log.error("poll event error: ", e);
Thread.currentThread().interrupt();
}
}
}
private void notifyAllSubscribers(BootEvent event) {
for (Subscriber subscriber : list) {
notifySubscriber(subscriber, event);
}
}
@Override
public void close() throws Exception {
running = false;
queue.clear();
log.info("publisher close..");
}
}
PublisherFactory 工厂类:
public interface PublisherFactory {
EventPublisher create(Class<? extends BootEvent> event, int queueSize);
}
//默认实现
public class DefaultPublisherFactory implements PublisherFactory {
private Map<Class<? extends BootEvent>, DefaultEventPublisher> map;
public static DefaultPublisherFactory INSTANCE = new DefaultPublisherFactory();
private DefaultPublisherFactory() {
map = new ConcurrentHashMap<>();
}
@Override
public EventPublisher create(Class<? extends BootEvent> event, int queueSize) {
map.computeIfAbsent(event, e -> {
DefaultEventPublisher eventPublisher = new DefaultEventPublisher(queueSize);
return eventPublisher;
});
return map.get(event);
}
public EventPublisher getPublisher(Class<? extends BootEvent> event) {
return map.get(event);
}
public List<EventPublisher> getEventPublishers() {
return new ArrayList<>(map.values());
}
}
订阅者 subscriber
public abstract class Subscriber<E extends BootEvent> {
public abstract void onEvent(E event);
public abstract Class<? extends BootEvent> supportedType();
/**
* 如果指定了纯种池,则会异步执行
*/
public ThreadPoolExecutor executor(){
return null;
}
}
事件
@Data
public abstract class BootEvent implements Serializable {
private static AtomicLong SEQ = new AtomicLong(0);
private Object source;
private Long timeStamp;
private Long id;
public BootEvent(Object source) {
this.source = source;
this.timeStamp = System.currentTimeMillis();
this.id = getSequence();
}
private Long getSequence() {
return SEQ.getAndIncrement();
}
}
public class LogEvent extends BootEvent {
@Getter
private String msg;
public LogEvent(Object source, String msg) {
super(source);
this.msg = msg;
}
}
通知中心
@Slf4j
public class NotifyBus {
public static NotifyBus INSTANCE = new NotifyBus();
private static Integer QUEUE_SIZE = 100;
private AtomicBoolean CLOSED = new AtomicBoolean(false);
private DefaultPublisherFactory factory = DefaultPublisherFactory.INSTANCE;
private NotifyBus() {
Runtime.getRuntime().addShutdownHook(new Thread(() -> NotifyBus.INSTANCE.shutDown()));
}
public void setFactory(DefaultPublisherFactory factory) {
this.factory = factory;
}
public void publish(BootEvent event) {
factory.getPublisher(event.getClass()).publish(event);
}
public void addSubscriber(Subscriber subscriber) {
addSubscriber(subscriber, factory);
}
private void addSubscriber(Subscriber subscriber, PublisherFactory factory) {
EventPublisher eventPublisher = factory.create(subscriber.supportedType(), QUEUE_SIZE);
eventPublisher.addSubscriber(subscriber);
}
public void shutDown() {
if (!CLOSED.compareAndSet(false, true)) {
log.error(">>>>> notifyBus already close..");
return;
}
log.info(">>>>> notifyBus close...");
for (EventPublisher eventPublisher : DefaultPublisherFactory.INSTANCE.getEventPublishers()) {
try {
eventPublisher.close();
} catch (Exception e) {
log.error("####### notifyBus close error", e);
}
}
}
}
访问
@RestController
public class NotifyBusController {
@GetMapping("/notify")
public String notify(@RequestParam String msg) {
NotifyBus.INSTANCE.publish(new LogEvent(this, msg));
return "success";
}
}
结果:
{"source":{},"timeStamp":1684890639183,"id":0,"msg":"hello"}
{"source":{},"timeStamp":1684890642822,"id":1,"msg":"hello"}
notifyBus close...
publisher close..