Web Project (4) - Implementation of Asynchronous Queue

content:

1 Overview

2.JedisAdapter

3.EventModel

4.EventHandler

5.LikeHandler

6.EventProducer

7.EventConsumer

 

1 Overview

In a website, while a business takes place, there are some follow-up businesses that need to take place.

For example, in addition to completing the like function, there are also a series of likes, such as reminding users who have been liked, etc. In order to realize these operations and not delay the implementation of the simple like function, we will implement these using asynchronous queues.

The processing flow is as follows:

Biz is a business department, which is understood as the implementation of likes, that is, to send an event through EventProducer while implementing likes;

This event enters the queue to wait, and at the other end of the queue, there is an EventConsumer that continuously consumes events;

There are many EventHandlers under the EventConsumer. As long as the EventHandler finds the event type it needs to handle, it will perform corresponding operations.

Advantages: ①The realization of follow-up business will not slow down the main business. ②If the server for subsequent services hangs, just restart and continue to consume events from the priority queue.

2.JedisAdapter

Add the following method to jedisAdapter

public void setObject(String key, Object obj) {//将一个对象转换为一个jsoon串存入set中
        set(key, JSON.toJSONString(obj));
}


public <T> T getObject(String key, Class<T> clazz) {//从set中取出json串,并转换为相应object
        String value = get(key);
        if (value != null) {
            return JSON.parseObject(value, clazz);
        }
        return null;
}

3.EventModel

That is, the event model of the sent queue has only some basic properties and get and set methods.

The return of some of these sets is set to this, because it is convenient to set multiple properties in a row.

package com.nowcoder.async;

import java.awt.*;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by nowcoder on 2016/7/14.
 */
public class EventModel {
    private EventType type;
    private int actorId;
    private int entityId;
    private int entityType;
    private int entityOwnerId;
    private Map<String, String> exts = new HashMap<>();

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

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

    public String getExt(String name) {
        return exts.get(name);
    }

    public EventModel setExt(String name, String value) {
        exts.put(name, value);
        return this;
    }

    public EventType getType() {
        return type;
    }

    public EventModel setType(EventType type) {
        this.type = type;
        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;
    }
}

EventType

package com.nowcoder.async;

/**
 * Created by nowcoder on 2016/7/14.
 */
public enum EventType {//枚举类
    LIKE(0),
    COMMENT(1),
    LOGIN(2),
    MAIL(3);

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

4.EventHandler

It is designed as an interface, and handlers implement this interface.

package com.nowcoder.async;

import java.util.List;

/**
 * Created by nowcoder on 2016/7/14.
 */
public interface EventHandler {
    void doHandle(EventModel model);//处理此事件
    List<EventType> getSupportEventTypes();//添加监视的事件类型
}

5.LikeHandler

Implement the EventHandler interface.

package com.nowcoder.async.handler;

import com.nowcoder.async.EventHandler;
import com.nowcoder.async.EventModel;
import com.nowcoder.async.EventType;
import com.nowcoder.model.Message;
import com.nowcoder.model.User;
import com.nowcoder.service.MessageService;
import com.nowcoder.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * Created by nowcoder on 2016/7/14.
 */
@Component
public class LikeHandler implements EventHandler {
    @Autowired
    MessageService messageService;

    @Autowired
    UserService userService;

    @Override
    public void doHandle(EventModel model) {
        Message message = new Message();
        User user = userService.getUser(model.getActorId());
        message.setToId(model.getEntityOwnerId());
        message.setContent("用户" + user.getName() +
                " 赞了你的资讯,http://127.0.0.1:8080/news/"
                + String.valueOf(model.getEntityId()));
        // SYSTEM ACCOUNT
        message.setFromId(3);
        message.setCreatedDate(new Date());
        messageService.addMessage(message);
    }

    @Override
    public List<EventType> getSupportEventTypes() {//只关注“like”类型的事件
        return Arrays.asList(EventType.LIKE);
    }
}

6.EventProducer

Responsible for adding events to the queue.

package com.nowcoder.async;

import com.alibaba.fastjson.JSONObject;
import com.nowcoder.util.JedisAdapter;
import com.nowcoder.util.RedisKeyUtil;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.ExceptionHandler;

/**
 * Created by nowcoder on 2016/7/14.
 */
@Service
public class EventProducer {

    @Autowired
    JedisAdapter jedisAdapter;

    public boolean fireEvent(EventModel eventModel) {
        try {
            String json = JSONObject.toJSONString(eventModel);//生成value
            String key = RedisKeyUtil.getEventQueueKey();//生成key
            jedisAdapter.lpush(key, json);//将事件添加到队列中
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

7.EventConsumer

Responsible for consuming events from the queue.

package com.nowcoder.async;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.nowcoder.async.handler.LoginExceptionHandler;
import com.nowcoder.util.JedisAdapter;
import com.nowcoder.util.RedisKeyUtil;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by nowcoder on 2016/7/14.
 */
@Service
public class EventConsumer implements InitializingBean, ApplicationContextAware {

//InitializingBean  通过实现此接口的afterPropertiesSet()方法记录哪些Event需要哪些handler来处理
//ApplicationContextAware  通过实现此接口的setApplicationContext方法获取上下文

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

    //用来存储一个事件类型对应的所有的eventhandler,下次有该事件产生时,即可直接调用对应的list
    private Map<EventType, List<EventHandler>> config = new HashMap<>();

    private ApplicationContext applicationContext;

    @Autowired
    private JedisAdapter jedisAdapter;

    @Override
    public void afterPropertiesSet() throws Exception {//记录哪些Event需要哪些handler来处理
        //找出上下文中所有实现了EventHandler接口的类,存入beans
        Map<String, EventHandler> beans = applicationContext.getBeansOfType(EventHandler.class);
        if (beans != null) {
            //遍历所有的handler,将他们存入他们所监听的eventType对应的list中
            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(new Runnable() {
            @Override
            public void run() {
                // 从队列一直消费
                while (true) {
                    String key = RedisKeyUtil.getEventQueueKey();
                    List<String> messages = jedisAdapter.brpop(0, key);//从redis的队列中取出事件,并存入list中
                    // 第一个元素是队列名字,跳过
                    for (String message : messages) {
                        if (message.equals(key)) {
                            continue;
                        }

                        EventModel eventModel = JSON.parseObject(message, EventModel.class);
                        // 找到这个事件的处理handler列表
                        if (!config.containsKey(eventModel.getType())) {
                            logger.error("不能识别的事件");
                            continue;
                        }

                        for (EventHandler handler : config.get(eventModel.getType())) {//处理他的所有的handler
                            handler.doHandle(eventModel);
                        }
                    }
                }
            }
        });
        thread.start();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325466655&siteId=291194637