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