消息驅動封裝

1、消息驅動可以幹什麼
答:可用於異步事務,分佈式服務調用等
2、消息驅動需要注意的是什麼
答:兼容生成者本地事務,事務檢查,消息發送失敗自動補償,消費者業務方免冪等操作,免事務操作
3、本消息驅動缺點是什麼
答:違反設計模式中最少知道原則,並且有表侵入問題,消息表必須跟業務表在一起,正在努力改進中

設計概要:

基於AP原則,只保證最終一致性,整體思想基於經典MQ事務處理,其中發送、接收消息表會侵入業務,MQ基於RabbitMQ,

接收方使用僞觀察者模式

模型圖如下:

1、主業務方處理完,寫數據庫

2、主業務方調用消息驅動

3、消息驅動先檢查事務,無事務則拋異常,然後向DB寫發送數據

4、異步發送,發送成功失敗不影響業務操作

5、消息確認

6、修改發送記錄確認成功或失敗(定時任務重試發送失敗消息)

7、接收消息

8、寫接收消息

9、開啓事務調用業務方

10、業務方寫DB

11、消息驅動修改消息處理成功(定時任務處理初始狀態消息)

12、消息回執ACK

 

相關實現

結構

sql

CREATE TABLE `cs_receive_message`  (
  `message_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '消息類型',
  `business_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '業務類型',
  `business_id` bigint(19) NULL DEFAULT NULL COMMENT '業務訂單號',
  `data` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '數據',
  `gmt_receive` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '接收時間',
  `handle_state` tinyint(4) NULL DEFAULT NULL COMMENT '狀態',
  `gmt_create` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '創建時間',
  `gmt_modify` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '修改時間',
  PRIMARY KEY (`message_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

CREATE TABLE `cs_send_message`  (
  `message_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '消息類型',
  `business_type` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '業務類型',
  `business_id` bigint(19) NULL DEFAULT NULL COMMENT '業務訂單號',
  `exchange` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '路由',
  `routing_key` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '路由策略',
  `data` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '數據',
  `gmt_send` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '發送時間',
  `gmt_confirm` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '確認時間',
  `message_state` tinyint(4) NULL DEFAULT NULL COMMENT '狀態',
  `gmt_create` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '創建時間',
  `gmt_modify` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '修改時間',
  PRIMARY KEY (`message_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

實體類

@Data
public class ReceiveMessage implements Serializable {

    /**
     * 消息類型
     */
    private String messageId;

    /**
     * 業務類型
     */
    private String businessType;

    /**
     * 業務訂單號
     */
    private Long businessId;

    /**
     * 數據
     */
    private String data;

    /**
     * 接收時間
     */
    private Date gmtReceive;

    /**
     * 狀態
     */
    private Integer handleState;

    /**
     * 創建時間
     */
    private Date gmtCreate;

    /**
     * 修改時間
     */
    private Date gmtModify;

    private static final long serialVersionUID = 1L;
}

 

@Data
public class SendMessage implements Serializable {
    /**
     * 消息類型
     */
    private String messageId;

    /**
     * 業務類型
     */
    private String businessType;

    /**
     * 業務訂單號
     */
    private Long businessId;

    /**
     * 路由
     */
    private String exchange;

    /**
     * 路由策略
     */
    private String routingKey;

    /**
     * 數據
     */
    private String data;

    /**
     * 發送時間
     */
    private Date gmtSend;

    /**
     * 確認時間
     */
    private Date gmtConfirm;

    /**
     * 狀態
     */
    private Integer messageState;

    /**
     * 創建時間
     */
    private Date gmtCreate;

    /**
     * 修改時間
     */
    private Date gmtModify;

    private static final long serialVersionUID = 1L;
}

 枚舉類

public enum ReceiveHandleStateEnum {

    /**
     * 初始
     */
    INIT(0, "初始"),

    /**
     * 處理中
     */
    PROCESSING(5, "處理中"),

    /**
     * 處理成功
     */
    PROCESS_SUCCESS(10, "處理成功"),

    ;

    /**
     * 編碼
     */
    private Integer code;

    /**
     * 說明
     */
    private String describe;

    ReceiveHandleStateEnum(Integer code, String describe) {
        this.code = code;
        this.describe = describe;
    }

    public Integer getCode() {
        return code;
    }

    public String getDescribe() {
        return describe;
    }
    
}
public enum SendHandleStateEnum {

    /**
     * 初始
     */
    INIT(0, "初始"),

    /**
     * 待確認
     */
    WAITING_CONFIRM(5, "待確認"),

    /**
     * 發送成功
     */
    SEND_SUCCESS(10, "發送成功"),

    /**
     * 發送失敗
     */
    SEND_FAIL(15, "發送失敗"),

    ;

    /**
     * 編碼
     */
    private Integer code;

    /**
     * 說明
     */
    private String describe;

    SendHandleStateEnum(Integer code, String describe) {
        this.code = code;
        this.describe = describe;
    }

    public Integer getCode() {
        return code;
    }

    public String getDescribe() {
        return describe;
    }

}

Mapper,忽略公共部分,公共部分請用mybatis工具生成

<!-- 根據業務訂單和查詢接收消息列表 -->
  <select id="findByBusinessId" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from cs_receive_message
    where business_id = #{businessId,jdbcType=BIGINT}
    </select>

  <select id="findOverdueOrder" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from cs_receive_message
    WHERE
    <![CDATA[
        gmt_create <= #{endGmtCreate,jdbcType=VARCHAR}
    ]]>
    AND handle_state in
    <foreach item="item" collection="receiveStateList" separator="," open="(" close=")" index="">
      #{item,jdbcType=INTEGER}
    </foreach>
  </select>
<!-- 根據業務訂單號查詢列表-->
  <select id="findByBusinessId" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from cs_send_message
    where business_id = #{businessId,jdbcType=BIGINT}
    </select>
  <select id="findOverdueOrder" resultMap="BaseResultMap">
    select
    <include refid="Base_Column_List" />
    from cs_send_message
    WHERE
    <![CDATA[
        gmt_create <= #{endGmtCreate,jdbcType=VARCHAR}
    ]]>
    AND message_state in
    <foreach item="item" collection="sendStateList" separator="," open="(" close=")" index="">
      #{item,jdbcType=INTEGER}
    </foreach>
  </select>

Dao

public interface ReceiveMessageMapper extends BaseMapper<ReceiveMessage, String> {

    /**
     * 根據業務訂單和查詢接收消息列表
     *
     * @param businessId
     * @return
     */
    List<ReceiveMessage> findByBusinessId(Long businessId);

    /**
     * 根據狀態查詢創建時間小於等於endGmtCreate
     * @param receiveStateList
     * @param endGmtCreate
     * @return
     */
    List<ReceiveMessage> findOverdueOrder(@Param(value = "receiveStateList") List<Integer> receiveStateList, @Param(value = "endGmtCreate") String endGmtCreate);
}
public interface SendMessageMapper extends BaseMapper<SendMessage, String> {

    /**
     * 根據業務訂單號查詢列表
     *
     * @param businessId
     * @return
     */
    List<SendMessage> findByBusinessId(Long businessId);

    /**
     * 根據狀態查詢創建時間小於等於endGmtCreate
     * @param sendStateList
     * @param endGmtCreate
     * @return
     */
    List<SendMessage> findOverdueOrder(@Param(value = "sendStateList") List<Integer> sendStateList, @Param(value = "endGmtCreate") String endGmtCreate);
}

Service類 

@Slf4j
@Service
public class SendMessageService {

    @Resource
    private SendMessageMapper sendMessageMapper;

    public void insert(SendMessage sendMessage) {
        if (sendMessage == null || StringUtils.isEmpty(sendMessage.getMessageId())) {
            throw new RuntimeException("參數錯誤");
        }

        int total = sendMessageMapper.insertSelective(sendMessage);
        if (total <= 0) {
            throw new RuntimeException("系統異常");
        }
    }

    public void update(SendMessage sendMessage) {
        if (sendMessage == null || StringUtils.isEmpty(sendMessage.getMessageId())) {
            throw new RuntimeException("參數錯誤");
        }

        sendMessageMapper.updateByPrimaryKeySelective(sendMessage);
    }

    public SendMessage getByMessageId(String messageId) {
        if (StringUtils.isEmpty(messageId)){
            return null;
        }

        return sendMessageMapper.selectByPrimaryKey(messageId);
    }

    public List<SendMessage> findByBusinessId(Long businessId) {
        if (businessId == null){
            return Collections.emptyList();
        }

        return sendMessageMapper.findByBusinessId(businessId);
    }

    public void updateMessageState(String messageId, Integer messageState) {
        if (StringUtils.isEmpty(messageId) || messageState == null) {
            throw new RuntimeException("參數錯誤");
        }

        SendMessage sendMessageUpdate = new SendMessage();
        sendMessageUpdate.setMessageId(messageId);
        sendMessageUpdate.setMessageState(messageState);
        sendMessageUpdate.setGmtConfirm(new Date());

        update(sendMessageUpdate);
    }

    public List<SendMessage> findOverdueOrder(List<Integer> sendStateList, String endGmtCreate) {
        if (sendStateList.isEmpty() || StringUtils.isEmpty(endGmtCreate)){
            return Collections.emptyList();
        }

        return sendMessageMapper.findOverdueOrder(sendStateList, endGmtCreate);
    }
}
@Slf4j
@Service
public class ReceiveMessageService {

    @Resource
    private ReceiveMessageMapper receiveMessageMapper;

    public void insert(ReceiveMessage receiveMessage) {
        if (receiveMessage == null || StringUtils.isEmpty(receiveMessage.getMessageId())) {
            throw new RuntimeException("參數錯誤");
        }

        int total = receiveMessageMapper.insertSelective(receiveMessage);
        if (total <= 0) {
            throw new RuntimeException("系統異常");
        }
    }

    public void update(ReceiveMessage receiveMessage) {
        if (receiveMessage == null || StringUtils.isEmpty(receiveMessage.getMessageId())) {
            throw new RuntimeException("參數錯誤");
        }

        receiveMessageMapper.updateByPrimaryKeySelective(receiveMessage);
    }

    public ReceiveMessage getByMessageId(String messageId) {
        if (StringUtils.isEmpty(messageId)) {
            return null;
        }

        return receiveMessageMapper.selectByPrimaryKey(messageId);
    }

    public List<ReceiveMessage> findByBusinessId(Long businessId) {
        if (businessId == null) {
            return Collections.emptyList();
        }

        return receiveMessageMapper.findByBusinessId(businessId);
    }

    public void updateHandleState(String messageId, Integer handleState) {
        if (StringUtils.isEmpty(messageId) || handleState == null) {
            throw new RuntimeException("參數錯誤");
        }

        ReceiveMessage receiveMessageUpdate = new ReceiveMessage();
        receiveMessageUpdate.setMessageId(messageId);
        receiveMessageUpdate.setHandleState(handleState);

        update(receiveMessageUpdate);
    }

    public List<ReceiveMessage> findOverdueOrder(List<Integer> receiveStateList, String endGmtCreate) {
        if (receiveStateList.isEmpty() || StringUtils.isEmpty(endGmtCreate)){
            return Collections.emptyList();
        }

        return receiveMessageMapper.findOverdueOrder(receiveStateList, endGmtCreate);
    }

}

發送類

@Slf4j
@Component
public class SendExecute {

    @Autowired
    private SendMessageService sendMessageService;

    @Autowired
    @Qualifier("driveRabbitTemplate")
    private RabbitTemplate driveRabbitTemplate;

    @Transactional(rollbackFor = Exception.class)
    public void execute(Long businessId, String businessType, String routingKey, String date) {
        String messageId = StringUtil.randomGUID();
        SendMessage message = new SendMessage();
        message.setMessageId(messageId);
        message.setBusinessId(businessId);
        message.setBusinessType(businessType);
        message.setData(date);
        message.setExchange(driveRabbitTemplate.getExchange());
        message.setRoutingKey(routingKey);
        message.setGmtSend(new Date());
        message.setMessageState(SendHandleStateEnum.WAITING_CONFIRM.getCode());
        sendMessageService.insert(message);

        log.info("開始異步發送消息{}", message);
        sendMessage(message);
    }

    /**
     * 發送消息(這裏用public只是爲了事務)
     *
     * @param message
     */
    @Async("sendPool")
    public void sendMessage(SendMessage message) {
        CorrelationData correlationData = new CorrelationData();
        correlationData.setId(message.getMessageId());
        driveRabbitTemplate.convertAndSend(message.getRoutingKey(), (Object) JSONObject.toJSONString(message), correlationData);
        log.info("異步消息發送成功{}", message);
    }

}

異步線程池配置

@Configuration
public class DriveAsyncConfig {

    @Bean(name = "sendPool")
    public ThreadPoolExecutor withdrawAuditPool() {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(8, 16, 60, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(128), new ThreadPoolExecutor.DiscardPolicy());
        return threadPoolExecutor;
    }

}

接收業務處理接口

public interface ReceiveHandle {

    /**
     * 獲取處理器名稱
     * @return
     */
    String getName();

    /**
     * 業務處理
     * @param data 業務數據
     */
    void execute(String data);

}
@Slf4j
@Service
public class ReceiveExecute {

    @Autowired
    private RedisLock redisLock;

    @Autowired
    private ReceiveMessageService receiveMessageService;

    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 接收處理類
     */
    private volatile Map<String, ReceiveHandle> handleMap;

    /**
     * 處理鎖名稱
     */
    private static final String RECEIVE_EXECUTE_LOCK = "RECEIVE:EXECUTE:LOCK:";

    /**
     * 通過類型獲取接收處理類
     *
     * @param businessType
     * @return
     */
    private ReceiveHandle getReceiveHandle(String businessType) {
        if (CollectionUtils.isEmpty(handleMap)) {
            synchronized (this) {
                if (CollectionUtils.isEmpty(handleMap)) {
                    // 獲取所有實現類型
                    Map<String, ReceiveHandle> beans = applicationContext.getBeansOfType(ReceiveHandle.class);
                    if (CollectionUtils.isEmpty(beans)) {
                        return null;
                    }

                    // 初始化map
                    handleMap = beans.values().stream().collect(Collectors.toMap(ReceiveHandle::getName, x -> x));
                }
            }
        }
        return handleMap.get(businessType);
    }

    /**
     * 業務處理操作
     *
     * @param messageId
     * @param businessType
     */
    @Transactional(rollbackFor = Exception.class)
    public void execute(String messageId, String businessType) {
        log.info("消息驅動開始業務處理 參數 messageId{} businessType{}", messageId, businessType);
        // 驗證參數
        if (StringUtils.isEmpty(messageId) || StringUtils.isEmpty(businessType)) {
            return;
        }

        // 開始調用處理
        ReceiveHandle receiveHandle = getReceiveHandle(businessType);
        if (receiveHandle == null) {
            return;
        }

        redisLock.tryLock(RECEIVE_EXECUTE_LOCK, messageId, () -> {
            // 必須是待處理狀態
            ReceiveMessage receiveMessageSelect = receiveMessageService.getByMessageId(messageId);
            if (receiveMessageSelect == null) {
                throw new RuntimeException("消息" + messageId + "不存在");
            }
            log.info("消息驅動業務處理 messageId{}當前狀態{}", messageId, receiveMessageSelect.getHandleState());
            // 定時任務會查初始狀態數據並調用此方執行
            if (!ReceiveHandleStateEnum.INIT.getCode().equals(receiveMessageSelect.getHandleState())) {
                return;
            }
            // 修改消息處理中
            receiveMessageService.updateHandleState(receiveMessageSelect.getMessageId(), ReceiveHandleStateEnum.PROCESSING.getCode());
            log.info("驅動開始業務處理 參數{}", receiveMessageSelect);

            // 處理業務
            receiveHandle.execute(receiveMessageSelect.getData());

            log.info("驅動結束業務處理 參數{}", receiveMessageSelect);

            // 修改消息處理成功
            receiveMessageService.updateHandleState(receiveMessageSelect.getMessageId(), ReceiveHandleStateEnum.PROCESS_SUCCESS.getCode());
        });
        log.info("消息驅動結束業務處理");
    }

}
@Slf4j
@Service
public class ReceiveListener implements ChannelAwareMessageListener {

    @Autowired
    private RedisLock redisLock;

    @Autowired
    private ReceiveExecute receiveExecute;

    @Autowired
    private ReceiveMessageService receiveMessageService;

    /**
     * 寫庫鎖名稱
     */
    private static final String RECEIVE_WRITING_DATA_LOCK = "RECEIVE:WRITING:DATA:LOCK:";

    @Override
    public void onMessage(Message message, Channel channel) throws Exception {
        log.info("消息驅動接收消息 - 數據{}", message.getBody());
        if (message == null || StringUtils.isEmpty(message.getBody())) {
            return;
        }

        // 獲取發送數據
        String json = new String(message.getBody(), StandardCharsets.UTF_8);
        log.info("消息驅動接收消息 - 數據{}", json);
        SendMessage sendMessage = JSONObject.parseObject(json, SendMessage.class);
        if (sendMessage == null) {
            // 拒絕並且丟棄
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }

        redisLock.tryLock(RECEIVE_WRITING_DATA_LOCK, sendMessage.getMessageId(), () -> {
            // 是否接收過,已經接收過直接確認
            ReceiveMessage receiveMessageSelect = receiveMessageService.getByMessageId(sendMessage.getMessageId());
            if (receiveMessageSelect != null) {
                log.info("消息驅動接收消息 - 重複消息 ID{}", sendMessage.getMessageId());
                return;
            }

            // 消息入庫
            ReceiveMessage receiveMessage = new ReceiveMessage();
            receiveMessage.setMessageId(sendMessage.getMessageId());
            receiveMessage.setBusinessType(sendMessage.getBusinessType());
            receiveMessage.setBusinessId(sendMessage.getBusinessId());
            receiveMessage.setData(sendMessage.getData());
            receiveMessage.setGmtReceive(new Date());
            receiveMessage.setHandleState(ReceiveHandleStateEnum.INIT.getCode());
            receiveMessageService.insert(receiveMessage);
            log.info("消息驅動接收消息 - 消息寫入DB成功{}", receiveMessage);
        });

        // 調用業務執行
        receiveExecute.execute(sendMessage.getMessageId(), sendMessage.getBusinessType());

        // 消息確認
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

}

驅動類:

public interface DriveManage {

    /**
     * 發送消息
     * @param businessId 業務ID
     * @param businessType 業務類型
     * @param date 業務數據
     */
    void send(Long businessId, String businessType, String date);

    /**
     * 發送消息
     * @param businessId 業務ID
     * @param businessType 業務類型
     * @param routingKey 路由key
     * @param date 業務數據
     */
    void send(Long businessId, String businessType, String routingKey, String date);

}

驅動實現類

@Slf4j
@Component
@EnableScheduling
public class DriveManageImpl implements DriveManage {

    @Autowired
    private SendMessageService sendMessageService;

    @Autowired
    private ReceiveMessageService receiveMessageService;

    @Lazy
    @Autowired
    private SendExecute sendExecute;

    @Lazy
    @Autowired
    private ReceiveExecute receiveExecute;

    /**
     * 驅動 - 消息隊列名稱(必須爲每個業務系統建立一個隊列)
     */
    @Value("${drive.message.queue.name}")
    private String messageQueueName;

    /**
     * 默認exchange
     */
    @Value("${spring.rabbitmq.template.exchange}")
    private String exchange;

    /**
     * 驅動 - 本服務routingKey
     */
    @Value("${drive.message.routingKey}")
    private String routingKey;

    @Bean
    public RabbitTemplate driveRabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate driveRabbitTemplate = new RabbitTemplate(connectionFactory);
        driveRabbitTemplate.setExchange(exchange);
        driveRabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (ack) {
                // 修改消息發送成功
                sendMessageService.updateMessageState(correlationData.getId(), SendHandleStateEnum.SEND_SUCCESS.getCode());
                log.info("drive消息確認 - 發送成功 ID{}", correlationData.getId());
            } else {
                sendMessageService.updateMessageState(correlationData.getId(), SendHandleStateEnum.SEND_FAIL.getCode());
                log.error("drive消消息確認 - 發送失敗 ID{}", correlationData.getId());
            }
        });
        return driveRabbitTemplate;
    }

    @Override
    public void send(Long businessId, String businessType, String date) {
        sendExecute.execute(businessId, businessType, routingKey, date);
    }

    @Override
    public void send(Long businessId, String businessType, String routingKey, String date) {
        sendExecute.execute(businessId, businessType, routingKey, date);
    }

    @Bean
    public MessageListenerContainer openAccountListenerContainer(ConnectionFactory connectionFactory, ReceiveListener receiveListener) {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.setQueueNames(messageQueueName);
        container.setMessageListener(receiveListener);
        container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        return container;
    }

    /**
     * 同步發送記錄
     */
    @Scheduled(cron = "0 0/1 * * * ?")
    public void synSend() {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MINUTE, -1);
        String endGmtCreate = new SimpleDateFormat(DateConstant.DATETIME_FORMAT).format(calendar.getTime());

        // 查詢一分鐘之前發送狀態爲待確認的
        List<Integer> sendStateList = new ArrayList<>();
        sendStateList.add(SendHandleStateEnum.SEND_FAIL.getCode());
        sendStateList.add(SendHandleStateEnum.WAITING_CONFIRM.getCode());
        List<SendMessage> sendMessagesListSelect = sendMessageService.findOverdueOrder(sendStateList, endGmtCreate);
        if (sendMessagesListSelect.isEmpty()) {
            return;
        }

        // 調用發送執行方法
        for (SendMessage sendMessage : sendMessagesListSelect) {
            sendExecute.sendMessage(sendMessage);
        }
    }

    /**
     * 同步接收記錄
     */
    @Scheduled(cron = "0 0/1 * * * ?")
    public void synReceive() {
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MINUTE, -1);
        String endGmtCreate = new SimpleDateFormat(DateConstant.DATETIME_FORMAT).format(calendar.getTime());

        // 查詢一分鐘之前發送狀態爲初始
        List<Integer> receiveStateList = new ArrayList<>();
        receiveStateList.add(ReceiveHandleStateEnum.INIT.getCode());
        List<ReceiveMessage> receiveMessageList = receiveMessageService.findOverdueOrder(receiveStateList, endGmtCreate);
        if (receiveMessageList.isEmpty()) {
            return;
        }

        // 調用接收執行方法
        for (ReceiveMessage receiveMessage : receiveMessageList) {
            receiveExecute.execute(receiveMessage.getMessageId(), receiveMessage.getBusinessType());
        }
    }

}

業務實現例子

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Starter.class)
public class MainTest {

    @Autowired
    private DriveManage driveManage;

    public String testSend() {
        return driveManage.send(0L, "order.pay.result", "支付成功");
        return driveManage.send(1L, "order.create.result", "下單成功");
    }

}

@Slf4j
@Service
public class Receive1 implements ReceiveHandle {

    @Override
    public String getName() {
        return "order.pay.result";
    }

    @Override
    public void execute(String data) {
        log.info("驅動業務實現{},接收參數{}", getName(), data);
        log.info("訂單支付成功");
    }

}

@Slf4j
@Service
public class Receive2 implements ReceiveHandle {

    @Override
    public String getName() {
        return "order.create.result";
    }

    @Override
    public void execute(String data) {
        log.info("驅動業務實現{},接收參數{}", getName(), data);
        log.info("訂單下單成");
    }

}

引用方配置

drive:
  message:
    queue:
      name: topic.transaction.drive.order
    routingKey: order.transaction.order

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章