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

com.sghd.common.event.EventBusImpl Maven / Gradle / Ivy

The newest version!
package com.sghd.common.event;

import java.lang.management.ManagementFactory;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.management.MBeanServer;
import javax.management.ObjectName;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import com.sghd.common.utils.thread.NamedThreadFactory;

/**
 * 事件总线接口的实现类
 */
@Component
public class EventBusImpl implements EventBus, EventBusImplMBean {

	private static final Logger logger = LoggerFactory.getLogger(EventBusImpl.class);

	/** 注册的事件接收者 */
	private ConcurrentHashMap>> receivers = new ConcurrentHashMap>>();

	@Autowired(required = false)
	@Qualifier("event_queue_size")
	private Integer queueSize = 32768;

	@Autowired(required = false)
	@Qualifier("event_pool_size")
	private Integer poolSize = 5;
	@Autowired(required = false)
	@Qualifier("event_pool_max_size")
	private Integer poolMaxSize = 10;
	@Autowired(required = false)
	@Qualifier("event_pool_alive_time")
	private Integer poolKeepAlive = 60;
	@Autowired(required = false)
	@Qualifier("event_pool_await_time")
	private Integer poolAwaitTime = 60;

	private ExecutorService pool;

	/**
	 * 根据配置初始化
	 */
	@PostConstruct
	protected void initialize() {
		ThreadGroup threadGroup = new ThreadGroup("事件模块");
		NamedThreadFactory threadFactory = new NamedThreadFactory(threadGroup, "事件处理");
		pool = new ThreadPoolExecutor(poolSize, poolMaxSize, poolKeepAlive, TimeUnit.SECONDS,
				new LinkedBlockingQueue(queueSize), threadFactory);

		// 注册MBean
		try {
			MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
			ObjectName name = new ObjectName("com.sghd.common:type=EventBusMBean");
			mbs.registerMBean(this, name);
		} catch (Exception e) {
			logger.error("注册[common-event]的JMX管理接口失败", e);
		}
	}

	/** 销毁方法 */
	@PreDestroy
	public void destory() {
		shutdown();
	}

	/** 停止状态 */
	private volatile boolean stop;

	/**
	 * 关闭事件总线,阻塞方法会等待总线中的全部事件都发送完后再返回
	 */
	public void shutdown() {
		if (isStop())
			return;
		stop = true;
		ThreadPoolExecutor executor = ((ThreadPoolExecutor) pool);
		for (;;) {
			if (executor.getQueue().isEmpty()) {
				break;
			}
			Thread.yield();
		}
		// 等待线程池关闭
		pool.shutdown();
		logger.error("开始关闭事件总线线程池");
		try {
			if (!pool.awaitTermination(poolAwaitTime, TimeUnit.SECONDS)) {
				logger.error("无法在预计时间内完成事件总线线程池关闭,尝试强行关闭");
				pool.shutdownNow();
				if (!pool.awaitTermination(poolAwaitTime, TimeUnit.SECONDS)) {
					logger.error("事件总线线程池无法完成关闭");
				}
			}
		} catch (InterruptedException e) {
			logger.error("事件总线线程池关闭时线程被打断,强制关闭事件总线线程池");
			pool.shutdownNow();
		}
	}

	/**
	 * 检查该事件总线是否已经停止服务
	 * @return
	 */
	public boolean isStop() {
		return stop;
	}

	@Override
	public void post(Event event) {
		if (event == null) {
			throw new IllegalArgumentException("事件对象不能为空");
		}
		if (stop) {
			throw new IllegalStateException("事件总线已经停止,不能再接收事件");
		}
		String name = event.getName();
		if (!receivers.containsKey(name)) {
			logger.warn("事件[{}]没有对应的接收器", name);
			return;
		}
		for (Receiver receiver : receivers.get(name)) {
			Runnable runner = createRunner(receiver, event);
			try {
				pool.submit(runner);
			} catch (RejectedExecutionException e) {
				logger.error("事件线程池已满,请尽快调整配置参数");
				onRejected(receiver, event);
			}
		}
	}

	@Override
	public void register(String name, Receiver receiver) {
		if (name == null || receiver == null) {
			throw new IllegalArgumentException("事件名和接收者均不能为空");
		}

		CopyOnWriteArraySet> set = receivers.get(name);
		if (set == null) {
			set = new CopyOnWriteArraySet<>();
			CopyOnWriteArraySet> prev = receivers.putIfAbsent(name, set);
			set = prev != null ? prev : set;
		}

		set.add(receiver);
	}

	@Override
	public void unregister(String name, Receiver receiver) {
		if (name == null || receiver == null) {
			throw new IllegalArgumentException("事件名和接收者均不能为空");
		}

		CopyOnWriteArraySet> set = receivers.get(name);
		if (set != null) {
			set.remove(receiver);
		}
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public void syncPost(Event event) {
		String name = event.getName();
		if (!receivers.containsKey(name)) {
			logger.warn("事件'{}'没有对应的接收器", name);
			return;
		}
		for (Receiver receiver : receivers.get(name)) {
			try {
				receiver.onEvent(event);
			} catch (Exception e) {
				logger.error("事件[" + event.getName() + "]处理时发生异常", e);
			}
		}
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void onRejected(Receiver receiver, Event event) {
		try {
			receiver.onEvent(event);
		} catch (ClassCastException e) {
			logger.error("事件[" + event.getName() + "]对象类型不符合接收器声明", e);
		} catch (Throwable t) {
			logger.error("事件[" + event.getName() + "]处理时发生异常", t);
		}
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private Runnable createRunner(final Receiver receiver, final Event event) {
		return new Runnable() {
			@Override
			public void run() {
				try {
					receiver.onEvent(event);
				} catch (ClassCastException e) {
					logger.error("事件[" + event.getName() + "]对象类型不符合接收器[" + receiver.getClass() + "]声明", e);
				} catch (Throwable t) {
					logger.error("事件[" + event.getName() + "]处理器[" + receiver.getClass() + "]运行时发生异常", t);
				}
			}
		};
	}

	// JMX管理接口的实现方法

	@Override
	public int getEventQueueSize() {
		return ((ThreadPoolExecutor) pool).getQueue().size();
	}

	@Override
	public int getPoolActiveCount() {
		return ((ThreadPoolExecutor) pool).getActiveCount();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy