异步事件框架

简介

  • 基于生产者与消费者模型实现
  • 生产者在为框架的外部接口,发送待处理事件至同步优先队列中。
  • 消费者从事件队列中读取事件
  • 根据读取到的事件,根据事件的类型分发至具体的处理器

流程图如下:
异步事件处理流程图

  • 同步优先队列使用Redis存储,方便分布式环境使用
  • 在消费者中使用线程池并发从同步队列中获取待处理事件
  • 每个事件处理器均接口同一接口,在Spring中可以直接获取所有的处理器实现类,再根据期望处理的事件类型初始化 事件映射表
  • 事件处理期望处理的类型应为事件类型集合,因为一个事件处理器可能期望处理多种事件类型

代码实现

事件模型

public class EventModel {

    /** 事件类型 */
    private EventType eventType;

    /** 触发者ID */
    private int actorId;

    /** 数据实体ID */
    private int entityId;

    /** 数据实体类型 */
    private int entityType;

    /** 事件所属者 */
    private int entityOwnerId;

    /** 扩展数据字段 */
    private Map<String, String> exts = new HashMap<String, String>();

    public EventModel() {}

    public EventModel(EventType eventType) {
        this.eventType = eventType;
    }

    public EventModel setExts(String key, String value) {
        this.exts.put(key, value);

        return this;
    }

    public EventModel setExts(Map<String, String> map) {
        this.exts.putAll(map);

        return this;
    }

    public EventType getEventType() {
        return eventType;
    }

    public EventModel setEventType(EventType eventType) {
        this.eventType = eventType;

        return this;
    }

    public int getActorId() {
        return actorId;
    }

    public EventModel setActorId(int actorId) {
        this.actorId = actorId;

        return this;
    }

    public int getEntityId() {
        return entityId;
    }

    public EventModel setEntityId(int entityId) {
        this.entityId = entityId;

        return this;
    }

    public int getEntityType() {
        return entityType;
    }

    public EventModel setEntityType(int entityType) {
        this.entityType = entityType;

        return this;
    }

    public int getEntityOwnerId() {
        return entityOwnerId;
    }

    public EventModel setEntityOwnerId(int entityOwnerId) {
        this.entityOwnerId = entityOwnerId;

        return this;
    }

    public Map<String, String> getExts() {
        return exts;
    }

    public String getExts(String key) {
        return this.exts.get(key);
    }
}

事件类型(枚举类)

public enum EventType {

    LIKE(0),
    COMMENT(1),
    LOGIN(2),
    MAIL(3),
    FOLLOW(4),
    UNFOLLOW(5);

    private int value;

    EventType(int value) {
        this.value = value;
    }

    public int getValue() {
        return this.value;
    }
}

生产者

@Service
public class EventProducer {

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

    @Autowired
    private JedisAdapter jedisAdapter;

    /**
     * 向事件队列发送事件
     * @param eventModel
     * @return
     */
    public boolean emitEvent(EventModel eventModel) {
        try {
            String json = JSONObject.toJSONString(eventModel);
            String key = RedisUtil.getEventQueueKey();

            jedisAdapter.lpush(key, json);
            return true;
        } catch(Exception e) {
            logger.error("出现异常"+e.getMessage());
        }

        return false;
    }
}

消费者

@Service
public class EventConsumer implements InitializingBean, ApplicationContextAware {

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

    /** 映射表 */
    private Map<EventType, List<EventHandler>> config = new HashMap<EventType, List<EventHandler>>();

    private ApplicationContext applicationContext;

    @Autowired
    private JedisAdapter jedisAdapter;

    @Override
    public void afterPropertiesSet() throws Exception {
        Map<String, EventHandler> beans = applicationContext.getBeansOfType(EventHandler.class);

        if(beans != null) {
            for(Map.Entry<String, EventHandler> entry : beans.entrySet()) {
                List<EventType> eventTypes = entry.getValue().getSupportEventTypes();

                for(EventType type : eventTypes) {
                    if(!config.containsKey(type))
                        config.put(type, new ArrayList<EventHandler>());

                    config.get(type).add(entry.getValue());
                }
            }
        }

        Thread thread = new Thread() {
            @Override
            public void run() {
                // 使用线程池分发事件
                ExecutorService exec = Executors.newCachedThreadPool();
                while(true) {
                    String key = RedisUtil.getEventQueueKey();
                    List<String> events = jedisAdapter.brpop(0, key);

                    for(String event : events) {
                        if(event.equals(key))
                            continue;

                        EventModel model = JSONObject.parseObject(event, EventModel.class);

                        exec.execute(new Consumer(model));
                    }
                }
            }
        };
        thread.start();
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {

        this.applicationContext = applicationContext;
    }

    class Consumer implements Runnable {

        private EventModel eventModel;

        public Consumer(EventModel eventModel) {
            this.eventModel = eventModel;
        }

        @Override
        public void run() {
            if(!config.containsKey(eventModel.getEventType())) {
                logger.error("不能识别的事件类型"+eventModel.getEventType());
                return;
            }

            for(EventHandler handler : config.get(eventModel.getEventType())) {
                handler.doHandle(eventModel);
            }
        }
    }
}

事件处理接口

public interface EventHandler {

    // 具体的处理操作
    void doHandle(EventModel eventModel);

    // 支持处理的事件类型
    List<EventType> getSupportEventTypes();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值