<!--加上publisher-confirms=true;channel-cache-size设置为100可以减少由于网络抖动造成的消息的一定丢失--> <rabbit:connection-factory id="connectionFactory" publisher-confirms="true" channel-cache-size="100" host="${rabbitmq.host}" port="${rabbitmq.port}" username="${rabbitmq.username}" password="${rabbitmq.password}"/> <bean id="rabbitTemplate" class="org.springframework.amqp.rabbit.core.RabbitTemplate"> <property name="connectionFactory" ref="connectionFactory"/> <property name="exchange" value="redpacket-user-exchange"/> <property name="mandatory" value="true"/> <!--当手动ack的时候,事务不需要开启--> <property name="channelTransacted" value="false"/> <!--设置ack的具体实现,这里由于我的生产者实现了ConfirmCallback,所以传入自己--> <property name="confirmCallback" ref="redPacketUserProvider"/> </bean>
具体的生产者代码:
package com.xwtec.service; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.xwtec.redis.RedisService; import com.xwtec.util.DateTimeUtil; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.amqp.rabbit.core.RabbitTemplate; import org.springframework.amqp.rabbit.support.CorrelationData; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.UUID; import java.util.concurrent.TimeUnit; /** * 红包中心入mq队列 * Created by by.lv on 2018/3/26 */ @Service public class RedPacketUserProvider implements RabbitTemplate.ConfirmCallback { private static final Logger LOGGER = LoggerFactory.getLogger(RedPacketUserProvider.class); @Autowired private RabbitTemplate rabbitTemplate; @Autowired private RedisService redisRedPacketService; private static final String REDPACKET_USER_KEY = "REDPACKET_USER_KEY"; /** * 送红包数据入mq * 如果入MQ失败,则入redis队列 * * @param pkgId * @param phone */ public void addUser(String phone, String pkgId) { JSONObject jsonObject = new JSONObject(); jsonObject.put("phone", phone); jsonObject.put("pkgId", pkgId); jsonObject.put("time", DateTimeUtil.getTodayChar14()); String msg = JSON.toJSONString(jsonObject); /** * 发送消息 */ CorrelationData correlationId = new CorrelationData(UUID.randomUUID().toString()); rabbitTemplate.convertAndSend("redpacket.user", (Object) msg, correlationId); /** * 将消息存入缓存中1分钟失效时间,在ack失败的时候,放缓存 */ redisRedPacketService.set(correlationId.toString(), msg, 1, TimeUnit.MINUTES); } @Override public void confirm(CorrelationData correlationData, boolean ack, String cause) { if (ack) { LOGGER.info("消息发送ACK成功"); } else { String msg = redisRedPacketService.get(correlationData.toString()); LOGGER.error("消息发送ACK失败,原因{},回掉id:{},从缓存中拿ACK失败的消息,进行入redis队列,消息内容{}", cause, correlationData,msg); if (!StringUtils.isBlank(msg)) { redisRedPacketService.lpush(REDPACKET_USER_KEY, msg); } } } }