事件架构图
事件类图
EventInit:事件的初始化
EventRegister:负责将EventHandler注册到EventHub进行存储
EventHub:负责EventHandler的存储
EventBusI:发布事件可以操作的方法,通知所有,通知一个,是否执行异步事件等功能
EvenI:事件
EventHandelerI:事件的处理方法
具体实现
EventI
public abstract class EventI {
Boolean retry = false;
String handlerName;
/**
* 事件唯一标识
*
* @return
*/
public String eventIdentify() {
return bizIdentify() + "_" + eventType() + "_" + action() + "_" + getRetry() + "_" + getHandlerName();
}
/**
* 事件名称
*
* @return
*/
public String eventName() {
return eventType() + "_" + action() + "_" + getRetry() + "_" + getHandlerName();
}
/**
* 业务id。例如订单id / 工单id 等
*
* @return
*/
public abstract String bizIdentify();
/**
* 事件类型。例如 trade / workcard 等
*
* @return
*/
public abstract String eventType();
/**
* 动作。例如 paid / completed 等
*
* @return
*/
public abstract String action();
public Boolean getRetry() {
return retry;
}
public void setRetry(Boolean retry) {
this.retry = retry;
}
public String getHandlerName() {
if (StringUtils.isNotBlank(handlerName)) {
return handlerName;
} else {
return "";
}
}
public void setHandlerName(String handlerName) {
this.handlerName = handlerName;
}
}
EventHandelerI
import java.util.concurrent.ExecutorService;
/**
* event handler
*/
public interface EventHandlerI<E extends EventI> {
default ExecutorService getExecutor() {
return null;
}
/**
* 当前handler处理失败是否重试
* <p>
* 使用调度事件进行重试,总计6次,间隔10分钟
*
* @return {@link Boolean }
*/
default Boolean retry() {
return false;
}
/**
* 重试侦听器
*/
default void retryListener(E e) {
}
default void beforeExecute(E e) {
}
void execute(E e);
default void exceptionListener(E e, Exception exception) {
}
default void afterExecute(E e) {
}
}
EventBusI
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
public class EventBus implements EventBusI {
@Resource
private EventPublisher eventPublisher;
/**
* 默认线程池
* 如果处理器无定制线程池,则使用此默认
*/
ExecutorService defaultExecutor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() + 1,
Runtime.getRuntime().availableProcessors() + 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1000));
@Autowired
private EventHub eventHub;
@Override
public void fireAll(EventI event) {
eventHub.getEventHandler(event.getClass()).forEach(handlerI -> {
try {
MDC.put("biz_log", handlerI.getClass().getSimpleName());
log.info("EventBus fire event:{},eventHandler:{}", JSON.toJSONString(event), handlerI.getClass().getName());
handlerI.beforeExecute(event);
handlerI.execute(event);
} catch (Exception exception) {
handlerI.exceptionListener(event, exception);
if (handlerI.retry()) {
event.setRetry(true);
event.setHandlerName(handlerI.getClass().getName());
handlerI.retryListener(event);
eventPublisher.publishEvent(event);
} else {
log.error("EventBus fire event:{},eventHandler:{},errorMsg:{}", JSON.toJSONString(event), handlerI.getClass().getName(), exception.getMessage(), exception);
}
} finally {
handlerI.afterExecute(event);
MDC.remove("biz_log");
}
});
}
@Override
public void retryFireAll(EventI event) {
EventHandlerI eventHandler = eventHub.getEventHandler(event.getHandlerName());
if (eventHandler != null) {
try {
MDC.put("biz_log", eventHandler.getClass().getSimpleName());
log.info("EventBus retryFireAll event:{},eventHandler:{}", JSON.toJSONString(event), eventHandler.getClass().getName());
eventHandler.beforeExecute(event);
eventHandler.execute(event);
} catch (Exception exception) {
eventHandler.exceptionListener(event, exception);
log.error("EventBus retryFireAll event:{},eventHandler:{},errorMsg:{}", JSON.toJSONString(event), eventHandler.getClass().getName(), exception.getMessage(), exception);
throw exception;
} finally {
eventHandler.afterExecute(event);
MDC.remove("biz_log");
}
}
}
@Override
public void asyncFireAll(EventI event) {
eventHub.getEventHandler(event.getClass()).forEach(handlerI -> {
try {
log.info("EventBus fire event:{},eventHandler:{}", JSON.toJSONString(event), handlerI.getClass().getName());
handlerI.beforeExecute(event);
if (null != handlerI.getExecutor()) {
handlerI.getExecutor().submit(() -> handlerI.execute(event)).get();
} else {
defaultExecutor.submit(() -> handlerI.execute(event));
}
} catch (Exception exception) {
handlerI.exceptionListener(event, exception);
if (handlerI.retry()) {
event.setRetry(true);
event.setHandlerName(handlerI.getClass().getName());
handlerI.retryListener(event);
eventPublisher.publishEvent(event);
}
log.error("EventBus fire event:{},eventHandler:{},errorMsg:{}", JSON.toJSONString(event), handlerI.getClass().getName(), exception.getMessage(), exception);
} finally {
handlerI.afterExecute(event);
}
});
}
}
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
public class EventBus implements EventBusI {
@Resource
private EventPublisher eventPublisher;
/**
* 默认线程池
* 如果处理器无定制线程池,则使用此默认
*/
ExecutorService defaultExecutor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors() + 1,
Runtime.getRuntime().availableProcessors() + 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1000));
@Autowired
private EventHub eventHub;
@Override
public void fireAll(EventI event) {
eventHub.getEventHandler(event.getClass()).forEach(handlerI -> {
try {
MDC.put("biz_log", handlerI.getClass().getSimpleName());
log.info("EventBus fire event:{},eventHandler:{}", JSON.toJSONString(event), handlerI.getClass().getName());
handlerI.beforeExecute(event);
handlerI.execute(event);
} catch (Exception exception) {
handlerI.exceptionListener(event, exception);
if (handlerI.retry()) {
event.setRetry(true);
event.setHandlerName(handlerI.getClass().getName());
handlerI.retryListener(event);
eventPublisher.publishEvent(event);
} else {
log.error("EventBus fire event:{},eventHandler:{},errorMsg:{}", JSON.toJSONString(event), handlerI.getClass().getName(), exception.getMessage(), exception);
}
} finally {
handlerI.afterExecute(event);
MDC.remove("biz_log");
}
});
}
@Override
public void retryFireAll(EventI event) {
EventHandlerI eventHandler = eventHub.getEventHandler(event.getHandlerName());
if (eventHandler != null) {
try {
MDC.put("biz_log", eventHandler.getClass().getSimpleName());
log.info("EventBus retryFireAll event:{},eventHandler:{}", JSON.toJSONString(event), eventHandler.getClass().getName());
eventHandler.beforeExecute(event);
eventHandler.execute(event);
} catch (Exception exception) {
eventHandler.exceptionListener(event, exception);
log.error("EventBus retryFireAll event:{},eventHandler:{},errorMsg:{}", JSON.toJSONString(event), eventHandler.getClass().getName(), exception.getMessage(), exception);
throw exception;
} finally {
eventHandler.afterExecute(event);
MDC.remove("biz_log");
}
}
}
@Override
public void asyncFireAll(EventI event) {
eventHub.getEventHandler(event.getClass()).forEach(handlerI -> {
try {
log.info("EventBus fire event:{},eventHandler:{}", JSON.toJSONString(event), handlerI.getClass().getName());
handlerI.beforeExecute(event);
if (null != handlerI.getExecutor()) {
handlerI.getExecutor().submit(() -> handlerI.execute(event)).get();
} else {
defaultExecutor.submit(() -> handlerI.execute(event));
}
} catch (Exception exception) {
handlerI.exceptionListener(event, exception);
if (handlerI.retry()) {
event.setRetry(true);
event.setHandlerName(handlerI.getClass().getName());
handlerI.retryListener(event);
eventPublisher.publishEvent(event);
}
log.error("EventBus fire event:{},eventHandler:{},errorMsg:{}", JSON.toJSONString(event), handlerI.getClass().getName(), exception.getMessage(), exception);
} finally {
handlerI.afterExecute(event);
}
});
}
}
EventHub
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* 事件控制中枢
*/
@Component
public class EventHub {
private HashMap<Class, List<EventHandlerI>> eventRepository = new HashMap<>();
@Resource
private List<EventHandlerI> eventHandlerIList;
public List<EventHandlerI> getEventHandler(Class eventClass) {
List<EventHandlerI> eventHandlerIList = eventRepository.get(eventClass);
if (eventHandlerIList == null || eventHandlerIList.isEmpty()) {
throw new RuntimeException(eventClass + "is not registered in eventHub, please register first");
}
return eventHandlerIList;
}
public EventHandlerI getEventHandler(String handlerName) {
return eventHandlerIList.stream().filter(handler -> handlerName.equals(handler.getClass().getName())).findFirst().orElse(null);
}
/**
* 注册事件
*
* @param eventClz
* @param executor
*/
public void register(Class<? extends EventI> eventClz, EventHandlerI executor) {
List<EventHandlerI> eventHandlers = eventRepository.get(eventClz);
if (eventHandlers == null) {
eventHandlers = new ArrayList<>();
eventRepository.put(eventClz, eventHandlers);
}
eventHandlers.add(executor);
}
}
EventRegister
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Method;
@Component
public class EventRegister {
@Resource
private EventHub eventHub;
private Class<? extends EventI> getEventFromExecutor(Class<?> eventExecutorClz) {
Method[] methods = eventExecutorClz.getDeclaredMethods();
for (Method method : methods) {
if (isExecuteMethod(method)) {
return checkAndGetEventParamType(method);
}
}
throw new RuntimeException("Event param in " + eventExecutorClz + "execute () is not detected");
}
public void doRegistration(EventHandlerI eventHandler) {
Class<? extends EventI> eventClz = getEventFromExecutor(eventHandler.getClass());
eventHub.register(eventClz, eventHandler);
}
private boolean isExecuteMethod(Method method) {
return "execute".equals(method.getName()) && !method.isBridge();
}
private Class checkAndGetEventParamType(Method method) {
Class<?>[] exeParams = method.getParameterTypes();
if (exeParams.length == 0) {
throw new RuntimeException("Execute method in " + method.getDeclaringClass() + " should at least have one parameter");
}
if (!EventI.class.isAssignableFrom(exeParams[0])) {
throw new RuntimeException("Execute method in " + method.getDeclaringClass() + " should be the subClass of Event");
}
return exeParams[0];
}
}
EventInit
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Map;
@Component
public class EventInit implements ApplicationContextAware, InitializingBean{
@Resource
private EventRegister eventRegister;
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void afterPropertiesSet() throws Exception {
Map<String, Object> eventHandlerBeans = applicationContext.getBeansWithAnnotation(EventHandler.class);
eventHandlerBeans.values().forEach(
eventHandler -> eventRegister.doRegistration((EventHandlerI) eventHandler)
);
}
}