阿里云RocketMQ

阿里云RocketMQ

1、maven依赖

首先去阿里云控制台创建所需消息队列资源,包括消息队列 RocketMQ 的实例、Topic、Group ID (GID),以及鉴权需要的 AccessKey(AK)。

<dependency>
      <groupId>com.aliyun.openservices</groupId>
      <artifactId>ons-client</artifactId>
      <version>1.8.4.Final</version>
    </dependency>

2、配置文件

##-------鉴权需要的 AccessKey(AK)(实际项目,这里填写阿里云自己的账号信息)---
rocketmq.accessKey=xxAxxxxxxxxxx
rocketmq.secretKey=xxxxxxxxxiHxxxxxxxxxxxxxx## 实例TCP 协议公网接入地址(实际项目,填写自己阿里云MQ的公网地址)
rocketmq.nameSrvAddr=http://MQ_INST_***********85_BbM********************yuncs.com:80
#普通消息topic (实际项目,填写自己阿里云MQ中的topic名称和groupid)
rocketmq.topic=common
rocketmq.groupId=GID-message`在这里插入代码片`
rocketmq.tag=*
#定时/延时消息
rocketmq.timeTopic=time-lapse
rocketmq.timeGroupId=GID-message
rocketmq.timeTag=*

3、配置类

/**
 * MQ配置加载
 * @author xf
 */
@Slf4j
@Component
@Data
@Configuration
@EnableApolloConfig(value = {"sysConfig.yml"})
public class MqConfig {

    private String accessKey;
    private String secretKey;
    private String nameSrvAddr;
    private String topic;
    private String groupId;
    private String tag;
    private String timeTopic;
    private String timeGroupId;
    private String timeTag;

    public Properties getMqProperties() {
        Properties properties = new Properties();
        properties.setProperty(PropertyKeyConst.AccessKey, this.accessKey);
        properties.setProperty(PropertyKeyConst.SecretKey, this.secretKey);
        properties.setProperty(PropertyKeyConst.NAMESRV_ADDR, this.nameSrvAddr);
        //设置发送超时时间,单位毫秒
        properties.setProperty(PropertyKeyConst.SendMsgTimeoutMillis, "4000");
        return properties;
    }
}

4、给消息生产者注入配置信息,ProducerBean用于将Producer集成至Spring Bean中

/**
 * MQ配置注入生成消息实例
 */
@Configuration
public class ProducerClient {

    @Autowired
    private MqConfig mqConfig;
    
    @Bean(initMethod = "start", destroyMethod = "shutdown")
    public ProducerBean buildProducer() {
        //ProducerBean用于将Producer集成至Spring Bean中
        ProducerBean producer = new ProducerBean();
        producer.setProperties(mqConfig.getMqPropertie());
        return producer;
    }
}

5、生产者发送消息

/**
 * MQ发送消息.
 * 
 * @author xf
 */
@Component
public class ProducerUtil {
    
    
    private Logger logger = LoggerFactory.getLogger(ProducerUtil.class);
    
    @Autowired
    private MqConfig config;
    
    @Autowired
    private ProducerBean producer;
    
    
    /**
     * 同步发送消息
     * @param msgTag 标签,可用于消息小分类标注
     * @param messageBody 消息body内容,生产者自定义内容
     * @param msgKey 消息key值,建议设置全局唯一,可不传,不影响消息投递
     * @return success:SendResult or error:null
     */
    public SendResult sendMsg(String msgTag,byte[] messageBody,String msgKey) {
        Message msg = new Message(config.getTopic(),msgTag,msgKey,messageBody);
        return this.send(msg,Boolean.FALSE);
    }
    /**
     * 同步发送定时/延时消息
     * @param msgTag 标签,可用于消息小分类标注,对消息进行再归类
     * @param messageBody 消息body内容,生产者自定义内容,二进制形式的数据
     * @param msgKey 消息key值,建议设置全局唯一值,可不设置,不影响消息收发
     * @param delayTime 服务端发送消息时间,立即发送输入0或比更早的时间
     * @return success:SendResult or error:null
     */
    public SendResult sendTimeMsg(String msgTag,byte[] messageBody,String msgKey,long delayTime) {
        Message msg = new Message(config.getTimeTopic(),msgTag,msgKey,messageBody);
        msg.setStartDeliverTime(delayTime);
        return this.send(msg,Boolean.FALSE);
    }
    /**
     * 发送单向消息
     */
    public void sendOneWayMsg(String msgTag,byte[] messageBody,String msgKey) {
        Message msg = new Message(config.getTopic(),msgTag,msgKey,messageBody);
        this.send(msg,Boolean.TRUE);
    }
    
    /**
     * 普通消息发送发放
     * @param msg 消息
     * @param isOneWay 是否单向发送
     */
    private SendResult send(Message msg,Boolean isOneWay) {
        try {
            if(isOneWay) {
                //由于在 oneway 方式发送消息时没有请求应答处理,一旦出现消息发送失败,则会因为没有重试而导致数据丢失。
                //若数据不可丢,建议选用同步或异步发送方式。
                producer.sendOneway(msg);
                success(msg, "单向消息MsgId不返回");
                return null;
            }else {
                //可靠同步发送
                SendResult sendResult = producer.send(msg);
                   //获取发送结果,不抛异常即发送成功
                if (sendResult != null) {
                   success(msg, sendResult.getMessageId());
                   return sendResult;
                }else {
                   error(msg,null);
                   return null;
                }
            }
        } catch (Exception e) {
            error(msg,e);
            return null;
        }
    }
    
    //对于使用异步接口,可设置单独的回调处理线程池,拥有更灵活的配置和监控能力。
    //根据项目需要,服务器配置合理设置线程数,线程太多有OOM 风险,
    private ExecutorService threads = Executors.newFixedThreadPool(3);
    //仅建议执行轻量级的Callback任务,避免阻塞公共线程池 引起其它链路超时。
    
    /**
     * 异步发送普通消息
     * @param msgTag
     * @param messageBody
     * @param msgKey
     */
    public void sendAsyncMsg(String msgTag,byte[] messageBody,String msgKey) {
        producer.setCallbackExecutor(threads);
        
        Message msg = new Message(config.getTopic(),msgTag,msgKey,messageBody);
         try {
             producer.sendAsync(msg, new SendCallback() {
                 @Override
                 public void onSuccess(final SendResult sendResult) {
                     assert sendResult != null;
                     success(msg, sendResult.getMessageId());
                 }
                 @Override
                 public void onException(final OnExceptionContext context) {
                     //出现异常意味着发送失败,为了避免消息丢失,建议缓存该消息然后进行重试。
                     error(msg,context.getException());
                 }
             });
         } catch (ONSClientException e) {
             error(msg,e);
         }
    }
    
    
    //--------------日志打印----------
    private void error(Message msg,Exception e) {
        logger.error("发送MQ消息失败-- Topic:{}, Key:{}, tag:{}, body:{}"
                 ,msg.getTopic(),msg.getKey(),msg.getTag(),new String(msg.getBody()));
        logger.error("errorMsg --- {}",e.getMessage());
    }
    private void success(Message msg,String messageId) {
        logger.info("发送MQ消息成功 -- Topic:{} ,msgId:{} , Key:{}, tag:{}, body:{}"
                ,msg.getTopic(),messageId,msg.getKey(),msg.getTag(),new String(msg.getBody()));
    }
    
}

6、消息消费者的配置

@Configuration
public class ConsumerClient {

    @Autowired
    private MqConfig mqConfig;

    //普通消息监听器,Consumer注册消息监听器来订阅消息. 
    @Autowired
    private MqMessageListener messageListener;
    
    //定时消息监听器,Consumer注册消息监听器来订阅消息. 
    @Autowired
    private MqTimeMessageListener timeMessageListener;

    @Bean(initMethod = "start", destroyMethod = "shutdown")
    public ConsumerBean buildConsumer() {
        ConsumerBean consumerBean = new ConsumerBean();
        //配置文件
        Properties properties = mqConfig.getMqPropertie();
        properties.setProperty(PropertyKeyConst.GROUP_ID, mqConfig.getGroupId());
        //将消费者线程数固定为20个 20为默认值
        properties.setProperty(PropertyKeyConst.ConsumeThreadNums, "20");
        consumerBean.setProperties(properties);
        //订阅消息
        Map<Subscription, MessageListener> subscriptionTable = new HashMap<Subscription, MessageListener>();
        //订阅普通消息
        Subscription subscription = new Subscription();
        subscription.setTopic(mqConfig.getTopic());
        subscription.setExpression(mqConfig.getTag());
        subscriptionTable.put(subscription, messageListener);
        //订阅定时/延时消息
        Subscription subscriptionTime = new Subscription();
        subscriptionTime.setTopic(mqConfig.getTimeTopic());
        subscriptionTime.setExpression(mqConfig.getTimeTag());
        subscriptionTable.put(subscriptionTime, timeMessageListener);

        consumerBean.setSubscriptionTable(subscriptionTable);
        return consumerBean;
    }

}

7、消费者消费消息

/**
 * 普通(默认同步)MQ消息监听消费
 * @author xf
 */
@Component
public class MqMessageListener implements MessageListener {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public Action consume(Message message, ConsumeContext context) {
        logger.info("接收到MQ消息. Topic :" + message.getTopic() + ", tag :" + message.getTag()+ " msgId : " + message.getMsgID()+", Key :" + message.getKey()+", body:" + new String(message.getBody()));
        try {
            String msgTag = message.getTag();//消息类型
            String msgKey = message.getKey();//唯一key
            switch (msgTag) {
            //--------普通通知
            case "userMessage":

                break;
            }
            return Action.CommitMessage;
        } catch (Exception e) {
            logger.error("消费MQ消息失败! msgId:" + message.getMsgID()+"----ExceptionMsg:"+e.getMessage());
            return Action.ReconsumeLater;
        }
    }
    
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值