码迷,mamicode.com
首页 > 其他好文 > 详细

简易版的生产者消费者实现业务异步事务分离

时间:2019-08-14 13:02:44      阅读:96      评论:0      收藏:0      [点我收藏+]

标签:throw   atd   final   hand   ceo   log   发送   string   import   

定义一个model类

/**
 * 版权所有:
 * 项目名称: 
 * 创建者: 
 * 创建日期: 2018年5月10日
 * 文件说明: 见类描述
 */
package com.huaxin.acws.component.message.model;

import java.util.Date;
import java.util.Map;

/**
 * @author
 *
 */
public class MessageModel {
    /**
     * 事件ID
     */
    private String eventId;
    /**
     * 事件类型
     */
    private String eventType;
    /**
     * 事件内容,保存数据库json格式,
     */
    private Map<String, Object> payload;
    /**
     * 预留,同步发送的失败消息,定时发送重试次数
     */
    private int retryCount = 0;
    /**
     * 预留,定时最后发送事件
     */
    private Date lastRetryTime = null;
    /**
     * 事件开始的事件
     */
    private Date startTime = null;
    
    /**
     * 有效性校验
     * @return
     */
    public boolean isValid() {
        if (this.getEventType() == null || this.payload == null) {
            return false;
        }
        
        return true;
    }
    /**
     * @return the eventId
     */
    public String getEventId() {
        return eventId;
    }
    /**
     * @param eventId the eventId to set
     */
    public void setEventId(String eventId) {
        this.eventId = eventId;
    }
    /**
     * @return the eventType
     */
    public String getEventType() {
        return eventType;
    }
    /**
     * @param eventType the eventType to set
     */
    public void setEventType(String eventType) {
        this.eventType = eventType;
    }
    /**
     * @return the payload
     */
    public Map<String, Object> getPayload() {
        return payload;
    }
    /**
     * @param payload the payload to set
     */
    public void setPayload(Map<String, Object> payload) {
        this.payload = payload;
    }
    /**
     * @return the retryCount
     */
    public int getRetryCount() {
        return retryCount;
    }
    /**
     * @param retryCount the retryCount to set
     */
    public void setRetryCount(int retryCount) {
        this.retryCount = retryCount;
    }
    /**
     * @return the lastRetryTime
     */
    public Date getLastRetryTime() {
        return lastRetryTime;
    }
    /**
     * @param lastRetryTime the lastRetryTime to set
     */
    public void setLastRetryTime(Date lastRetryTime) {
        this.lastRetryTime = lastRetryTime;
    }
    /**
     * @return the startTime
     */
    public Date getStartTime() {
        return startTime;
    }
    /**
     * @param startTime the startTime to set
     */
    public void setStartTime(Date startTime) {
        this.startTime = startTime;
    }
}

 

定义一个接口

/**
 * 版权所有:
 * 项目名称:
 * 创建者: 
 * 创建日期: 2018年5月10日
 * 文件说明: 见类描述
 */
package com.huaxin.acws.component.message.service;

import com.huaxin.acws.component.message.model.MessageModel;

/**
 * 事件消息实际发送类
 * 
 * @author dengxf
 */
public interface MessageHandler {
    /**
     * 是否支持消息类型处理
     * 
     * @param eventType
     * @return
     */
    boolean isSupportEventType(String eventType);
    /**
     * 消息处理
     * @param message
     */
    void hander(MessageModel message);
    
}

定义一个抽象基类---通过2张表来做消息处理,实现补发等操作

/**
 * 版权所有:
 * 项目名称: 
 * 创建者: 
 * 创建日期: 2018年5月10日
 * 文件说明: 见类描述
 */
package com.huaxin.acws.component.message.service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import com.alibaba.fastjson.JSONObject;
import com.huaxin.acws.common.exception.AcwsGenerelException;
import com.huaxin.acws.common.util.DateUtils;
import com.huaxin.acws.component.message.dao.WfoHiEventDao;
import com.huaxin.acws.component.message.dao.WfoRuEventDao;
import com.huaxin.acws.component.message.model.MessageModel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 消息生产者基类
 * @author 
 */
public abstract class AbstractMessageProducerService {
    private ExecutorService threadPool = Executors.newFixedThreadPool(5);
    
    /**
     * 日志记录对象
     */
    private static final Logger logger = LoggerFactory.getLogger(AbstractMessageProducerService.class);
            
    /**
     * 未发送事件消息
     */
    @Resource
    private WfoRuEventDao wfoRuEventDao;
    /**
     * 已发送事件消息
     */
    @Resource
    private WfoHiEventDao wfoHiEventDao;
    
    /**
     * 发送消息
     * 
     * @param message 消息对象
     * @param handler 消息实际发送对象
     */
    protected void sendMessage(final MessageModel message, final MessageHandler handler) {
        if (!message.isValid()) {
            throw new AcwsGenerelException("消息类型或内容为空,发送失败");
        }
        
        message.setStartTime(new Date());
        
        //1、MessageModel 保存
        final Map<String, Object> record = new HashMap<String, Object>();
        record.put("EVENT_TYPE", message.getEventType());
        record.put("EVENT_PAYLOAD", JSONObject.toJSONString(message.getPayload(), true));
        record.put("RETRY_COUNT", 0);
        record.put("START_TIME", message.getStartTime());
        
        String messageId = wfoRuEventDao.save(record);
        message.setEventId(messageId);
        record.put("WFO_RU_EVENT_ID", messageId);
                
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                //https://segmentfault.com/a/1190000004235193
                threadPool.execute(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            //1、发送事件
                            handler.hander(message);
                            logger.info("messageId={},发送成功", message.getEventId());
                            
                            //2、处理成功事件迁移历史表
                            record.put("END_TIME", new Date());
                            wfoHiEventDao.save(record);
                            wfoRuEventDao.deleteByPrimaryKey(message.getEventId());
                        } catch (RuntimeException e) {
                            logger.error("发送消息错误,EventId=" + message.getEventId(), e);
                        }                        
                    }
                });
//                try {
//                    //1、发送事件
//                    handler.hander(message);
//                    logger.info("messageId={},发送成功", message.getEventId());
//                    
//                    //2、处理成功事件迁移历史表
//                    record.put("END_TIME", new Date());
//                    wfoHiEventDao.save(record);
//                    wfoRuEventDao.deleteByPrimaryKey(message.getEventId());
//                } catch (RuntimeException e) {
//                    logger.error("发送消息错误,EventId=" + message.getEventId(), e);
//                }
            }
        });
    }
    
    /**
     * 发送成功归档
     * 
     * @param messageId
     */
    protected void archiveForSuccess(String messageId) {
        Map<String, String> ruRecord = wfoRuEventDao.getByPrimaryKey(messageId);
        ruRecord.put("END_TIME", DateUtils.formatDate(new Date(), DateUtils.DATE_FORMAT_YMDHMS));
        
        wfoHiEventDao.save(ruRecord);
        wfoRuEventDao.deleteByPrimaryKey(messageId);
    }
    
    /**
     * 发送失败更新重发计数
     * 
     * @param messageId
     */
    protected void updateCountForFailed(String messageId) {
        Map<String, String> messageMap = wfoRuEventDao.getByPrimaryKey(messageId);
        String retryCount = messageMap.get("RETRY_COUNT");

        Map<String, Object> record = new HashMap<String, Object>();
        record.put("WFO_RU_EVENT_ID", messageId);
        record.put("RETRY_COUNT", Integer.valueOf(retryCount) + 1);
        record.put("LAST_RETRY_TIME", new Date());
        
        wfoRuEventDao.save(record);
    }
}

 

业务实现类

/**
 * 版权所有:
 * 项目名称:
 * 创建者: 
 * 创建日期: 2019年2月12日
 * 文件说明: demo
 */
package com.huaxin.gxgc.gxprocess.service;

import com.alibaba.fastjson.JSONObject;
import com.huaxin.acws.bpm.event.ProcessCompletedEvent;
import com.huaxin.acws.common.exception.AcwsGenerelException;
import com.huaxin.acws.component.message.model.MessageModel;
import com.huaxin.acws.component.message.service.AbstractMessageProducerService;
import com.huaxin.acws.component.message.service.MessageHandler;
import com.huaxin.gxgc.mq.constant.MqEventTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

/**
 * 
 * @author diaoby
 *
 */
@Service
public class GxMqProducerService extends AbstractMessageProducerService implements MessageHandler{
    
    /** 日志实例 */
    private static final Logger logger = LoggerFactory.getLogger(GxMqProducerService.class);

    /* (non-Javadoc)
     * @see com.huaxin.acws.component.message.service.MessageHandler#isSupportEventType(java.lang.String)
     * @author diaoby
     */
    @Override
    public boolean isSupportEventType(String eventType) {
        return MqEventTypeEnum.MqEventType.PROCESS_COMPLETED_EVENT_GXPROCESSDEMO_MQ.getValue().equals(eventType);
    }

    /* (non-Javadoc)
     * @see com.huaxin.acws.component.message.service.MessageHandler#hander(com.huaxin.acws.component.message.model.MessageModel)
     * @author diaoby
     */
    @Override
    public void hander(MessageModel message) {
        Map<String, Object> payload = message.getPayload();
        ProcessCompletedEvent processCompletedEvent = null;
        Object object = payload.get("PROCESS_COMPLETED_EVENT");
        if( object instanceof JSONObject) {
            //ProcessCompletedEvent中 source 不能为空,随便设置一个值
            ((JSONObject) object).put("source", "1");
            JSONObject jsonobject = (JSONObject) object;
            processCompletedEvent = JSONObject.toJavaObject(jsonobject,ProcessCompletedEvent.class);
        } else {
            processCompletedEvent = (ProcessCompletedEvent) object;
        }
        //假设前10次都不成功
        if(message.getRetryCount() >= 10) {
            //业务操作
            logger.info("appId={}", processCompletedEvent.getAppId());
            logger.info("instanceId={}" +processCompletedEvent.getInstanceId());
        }else {
            logger.error("发送消息错误,EventId=" + message.getEventId());
            throw new AcwsGenerelException("GxMqProducerService流程结束事件失败");
        }
    }
    /**
     * 流程结束后触发完成后触发mq
     * @param processCompletedEvent
     * @author diaoby
     */
    public void completedProcess(ProcessCompletedEvent processCompletedEvent){
        Map<String, Object> payload = new HashMap<String, Object>();
        payload.put("PROCESS_COMPLETED_EVENT", processCompletedEvent);
        MessageModel message = new MessageModel();
        message.setEventType(MqEventTypeEnum.MqEventType.PROCESS_COMPLETED_EVENT_GXPROCESSDEMO_MQ.getValue());
        message.setPayload(payload);
        super.sendMessage(message, this);
    }
    
}

本例子中 ProcessCompletedEvent 是定义的一个 流程完成事件,流程完成事件后触发后续业务,通过流程也业务分离

业务调用处

    /* (non-Javadoc)
     * @see com.huaxin.gxgc.process.service.IProcessCompleted#completedProcess(com.huaxin.acws.bpm.event.ProcessCompletedEvent)
     * @author diaoby
     */
    @Override
    public void completedProcess(ProcessCompletedEvent processCompletedEvent) {
        gxMqProducerService.completedProcess(processCompletedEvent);
    }

 

简易版的生产者消费者实现业务异步事务分离

标签:throw   atd   final   hand   ceo   log   发送   string   import   

原文地址:https://www.cnblogs.com/diaobiyong/p/11350766.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!