事件

52 阅读3分钟

事件架构图

image.png

事件类图

image.png


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)
        );
    }
}