springboot集成阿里MNS消息队列发布订阅消息功能

声明:

上一篇文章是springboot集成阿里ons发布订阅消息,此篇文章是mns发布订阅功能先简单记录一下ons与mns有什么区别

这里是在网上找的对比图:


此处为具体区别文章链接:点击打开链接


但是其实我在实际使用的时候发现区别还是有的。

1、ons的sdk 集成需要配置生产者消费者config文件加载produce和consumer

而mns的sdk 集成到项目里只需要一个MnsConfig文件加载MNSClient 

2、ons需要阿里云账户控制台配置获取 ACCESS_KEY 、SECRET_KEY、ONS_ADDR

创建PRODUCER_ID、CONSUMER_ID、TOPIC、TAG(可不建)

mns只需要ACCESS_ID、ACCESS_KEY、ACCOUNT_ENDPOINT 通过控制台生产唯一的。可以在控制台创建队列queue也可以在代码中创建queue和删除队列queue

3.ons的消息发送和接收到topic、mns的消息发送和接收到queue或者topic中 mns有两种发布订阅的方式:

    

    消息服务MNS提供了两种API接口,一种是队列接口,一种是主题接口

    队列接口适用于点对点的消息收发,当接收消息时,需要应用端自行轮询获取消息(拉模式)。

    主题接口适用于一对多的消息收发,应用端只需要在某个地址上启动监听,服务端就会主动将消息推送过去(推模式)。

    1,其实使用两种方式都有自己的利弊,不然提供两种方式也就没有什么区别了。

    2,队列模型保证消息至少会被消费一次, 支持多个生产者和消费者并发操作同一个消息队列。消费消息时尽量做到先进先出,正是因为分布式    消息队列的一些特性并不能保证你能按照消息的发送顺序消费消息,如果你的业务必需先进先出, 建议在消息中加入序号信息以便消费消息后    进行重新排序。

    3,主题模型支持服务端主动将消息推送给用户指定的回调地址(Endpoint),消除用户程序不必要的轮询和资源消耗。
    主题模型保证通知消息按照指定的策略推送给用户,支持多个消息发布者并发操作同一个主题。主题模式支持一对多广播消息,一条通知消息可    以同时被多个订阅者接收和消费。

 

4.ons需要在消费者自定义的实现MessageListener监听器的listener中写自己的业务逻辑

mns的queue不用可以,直接获取到数据,然后随意使用可以封装方法获取到值在自己的实现层调用获取数据编写逻辑

5其他暂时没有遇到,这里暂留

一springboot配置MNS的queue模式发布订阅

查看官网的的操作文档:https://help.aliyun.com/document_detail/32449.html?spm=a2c4g.11174283.6.649.92Il3N

点击打开链接

配置之前的工作,获取到ACCESS_ID、ACCESS_KEY、ACCOUNT_ENDPOINT 通过控制台生产唯一的。可以在控制台创建队列queue也可以在代码中创建queue和删除队列queue

第一步配置pom文件:

<!-- Mq sdk-mns-->
        <dependency>
            <groupId>com.aliyun.mns</groupId>
            <artifactId>aliyun-sdk-mns</artifactId>
            <version>1.1.8</version>
            <classifier>jar-with-dependencies</classifier>
        </dependency>

第二步配置参数类:


第三步配置自动加载创建bean的config类:

@Configuration注解就是启动时自动运行 @Bean创建类到spring上下文中 (注:使用此类时用@Autowired 引入即可,不能用new方法)


import com.aliyun.mns.client.MNSClient;
import com.aliyun.mns.common.utils.ServiceSettings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class MnsConfig {
    private static final Logger LOGGER = LoggerFactory.getLogger(MnsConfig.class);

    @Bean(name = "client") //获取到本地路径下的配置文件属性内容
    public MNSClient getClient() {
        LOGGER.info("start");
        CloudAccount account = new CloudAccount(
        ServiceSettings.getMNSAccessKeyId(),
        ServiceSettings.getMNSAccessKeySecret(),
        ServiceSettings.getMNSAccountEndpoint());
        MNSClient client = account.getMNSClient();// 在程序中,CloudAccount以及MNSClient单例实现即可,多线程安全
        LOGGER.info("信息:{}",client);
        return client;
    }

第四步:封装发送消息方法

import com.aliyun.mns.client.CloudAccount;
import com.aliyun.mns.client.CloudQueue;
import com.aliyun.mns.client.MNSClient;
import com.aliyun.mns.common.ClientException;
import com.aliyun.mns.common.ServiceException;
import com.renrenche.databus.common.MnsParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author Mood
 * @date: 2018/6/28 15:30
 * @version: 1.0
 * @description: 推送消息给队列通用方法
 */
@Service
public class MnsProducer {


    private final static Logger logger = LoggerFactory.getLogger(MnsProducer.class);

    @Autowired
    private MNSClient  client ;//配置文件mnsconfig中配置好,这里使用的时候这样引入就可以了

    public void sendMessageByConfig(String queueName,String msg) {
       
        try {
            CloudQueue queue = client.getQueueRef(queueName);
            com.aliyun.mns.model.Message message = new com.aliyun.mns.model.Message();
            message.setMessageBody(msg);
            com.aliyun.mns.model.Message putMsg = queue.putMessage(message);
            System.out.println("Send message id is: " + putMsg.getMessageId());
        } catch (ClientException ce)
        {
            System.out.println("Something wrong with the network connection between client and MNS service."
                    + "Please check your network and DNS availablity.");
            ce.printStackTrace();
        } catch (ServiceException se)
        {
            se.printStackTrace();
            logger.error("MNS exception requestId:" + se.getRequestId(), se);
            if (se.getErrorCode() != null) {
                if (se.getErrorCode().equals("QueueNotExist"))
                {
                    System.out.println("Queue is not exist.Please create before use");
                } else if (se.getErrorCode().equals("TimeExpired"))
                {
                    System.out.println("The request is time expired. Please check your local machine timeclock");
                }
            /*
                you can get more MNS service error code from following link:
                https://help.aliyun.com/document_detail/mns/api_reference/error_code/error_code.html
            */
            }
        } catch (Exception e)
        {
            System.out.println("Unknown exception happened!");
            e.printStackTrace();
        }
        //client.close();  // 程序退出时,需主动调用client的close方法进行资源释放 配置文件中创建client的话方法应注释掉close 不然调用一次后close了就无法调用第二次了。还要重新new

    }

}

第五步:封装接收消息方法

import com.aliyun.mns.client.CloudAccount;
import com.aliyun.mns.client.CloudQueue;
import com.aliyun.mns.client.MNSClient;
import com.aliyun.mns.common.ClientException;
import com.aliyun.mns.common.ServiceException;
import com.aliyun.mns.model.Message;
import com.renrenche.databus.common.MnsParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Created by qixin on 2018/6/28.
 */
@Service
public class MnsConsumer {
    private final static Logger logger = LoggerFactory.getLogger(MnsConsumer.class);
    @Autowired
    private MNSClient  client ;//配置文件mnsconfig中配置好,这里使用的时候这样引入就可以了
    public void getMessage(String queueName){
      /* CloudAccount account = new CloudAccount(MnsParams.ACCESS_ID, MnsParams.ACCESS_KEY, MnsParams.ACCOUNT_ENDPOINT);
       MNSClient client = account.getMNSClient(); // 在程序中,CloudAccount以及MNSClient单例实现即可,多线程安全*/
       try{
           CloudQueue queue = client.getQueueRef(queueName);
           Message popMsg = queue.popMessage();
           if (popMsg != null){
               System.out.println("message handle: " + popMsg.getReceiptHandle());
               System.out.println("message body: " + popMsg.getMessageBodyAsString());
               System.out.println("message id: " + popMsg.getMessageId());
               System.out.println("message dequeue count:" + popMsg.getDequeueCount());
               //删除已经取出消费的消息
               queue.deleteMessage(popMsg.getReceiptHandle());
               System.out.println("delete message successfully.\n");
           }
           else{
               System.out.println("message not exist in TestQueue.\n");
           }
       } catch (ClientException ce)
       {
           System.out.println("Something wrong with the network connection between client and MNS service."
                   + "Please check your network and DNS availablity.");
           ce.printStackTrace();
       } catch (ServiceException se)
       {
           se.printStackTrace();
           logger.error("MNS exception requestId:" + se.getRequestId(), se);
           if (se.getErrorCode() != null) {
               if (se.getErrorCode().equals("QueueNotExist"))
               {
                   System.out.println("Queue is not exist.Please create before use");
               } else if (se.getErrorCode().equals("TimeExpired"))
               {
                   System.out.println("The request is time expired. Please check your local machine timeclock");
               }
            /*
            you can get more MNS service error code from following link:
            https://help.aliyun.com/document_detail/mns/api_reference/error_code/error_code.html
            */
           }
       } catch (Exception e)
       {
           System.out.println("Unknown exception happened!");
           e.printStackTrace();
       }
       //client.close();//配置文件中创建client的话方法应注释掉close 不然调用一次后close了就无法调用第二次了。还要重新new
   }
}

第六步调试发送接收消息(注此处调用发送接收要用注入的方式引入发送接收类不能用new 否则注入失效报null指针异常

import com.renrenche.databus.consumer.MnsConsumer;
import com.renrenche.databus.producer.MnsProducer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
    @Autowired
    private MnsProducer mnsProducer;
    @Autowired
    private MnsConsumer mnsConsumer;

    @RequestMapping(value = "/sendMessageByConfig", method = RequestMethod.GET)
    public void sendMessageByConfig() {

        mnsProducer.sendMessageByConfig("MyQueue","配置文件注入和消费");

    }
    @RequestMapping(value = "/getMessageByMns", method = RequestMethod.GET)
    public void getMessageByMns() {
        mnsConsumer.getMessage("MyQueue");

    }

}

启动项目可以查看到队列运行日志



postman调用调用发送消息 发送成功返回messageID



postman调用调用接收消息 发送成功返回message信息



二、springboot配置MNS的Topic模式发布订阅

首先与第一种queue第一步和第二步一样。

此处暂留本人还未调试过,等调试之后再补充,

可以参考其他文章 https://blog.csdn.net/syx1065001748/article/details/77453563

点击打开链接

结束!

感谢观看

猜你喜欢

转载自blog.csdn.net/alice_qixin/article/details/80897389