阿里云消息服务(Message Service)是一种高效、可靠、安全、便捷、可弹性扩展的分布式消息服务。MNS能够帮助应用开发者在他们应用的分布式组件上自由的传递数据、通知消息,构建松耦合系统。
消息服务同时支持各种类型消息推送,其中和短信前后端的无缝整合更高效的为用户提供了大批量短信发送能力。
消息服务提供了两种模型:
队列模型旨在提供高可靠高并发的一对一消费模型。即队列中的每一条消息都只能够被某一个消费者进行消费
消息进入队列的时候不一定是按照发送消息的顺序存储,有可能会出现消息位置倒置,所以若要遵循先进先出,则可以加个序列之类,然后根据序号进行业务处理
不可重复消费
队列接口适用于点对点的消息收发,当接收消息时,需要应用端自行轮询获取消息(拉模式)。
消息生产者生产消息发送到queue中,然后消息消费者从queue中取出并且消费消息,消息被消费以后,queue中不再有存储,所以消息消费者不可能消费到已经被消费的消息。Queue支持存在多个消费者,但是对一个消息而言,只会有一个消费者可以消费。
/**
* 创建队列
*/
public void createQueue() {
CloudAccount account = new CloudAccount("YourAccessId", "YourAccessKey", "MNSEndpoint");
MNSClient client = account.getMNSClient(); // 在程序中,CloudAccount以及MNSClient单例实现即可,多线程安全
String queueName = "TestQueue";
QueueMeta meta = new QueueMeta(); //生成本地QueueMeta属性,有关队列属性详细介绍见https://help.aliyun.com/document_detail/27476.html
meta.setQueueName(queueName); // 设置队列名
meta.setPollingWaitSeconds(15);
meta.setMaxMessageSize(2048L);
try {
CloudQueue queue = client.createQueue(meta);
} 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方法进行资源释放
}
/**
* 发送消息
*/
public void sendMessage() {
CloudAccount account = new CloudAccount("YourAccessId", "YourAccessKey", "MNSEndpoint");
MNSClient client = account.getMNSClient(); // 在程序中,CloudAccount以及MNSClient单例实现即可,多线程安全
try {
CloudQueue queue = client.getQueueRef("TestQueue");
Message message = new Message();
message.setMessageBody("I am test message ");
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方法进行资源释放
}
/**
* 接收并删除消息
*/
public void getAndDelMessage() {
CloudAccount account = new CloudAccount("YourAccessId", "YourAccessKey", "MNSEndpoint");
MNSClient client = account.getMNSClient(); // 在程序中,CloudAccount以及MNSClient单例实现即可,多线程安全
try{
CloudQueue queue = client.getQueueRef("TestQueue");
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();
}
主题订阅模型旨在提供一对多的发布订阅以及消息通知功能,支持用户实现一站式多种消息通知方式:
private static final String endPoint = "********************";
private static final String accessId = "*********************";
private static final String accessKey = "*************************";
<dependency>
<groupId>com.aliyun.mnsgroupId>
<artifactId>aliyun-sdk-mnsartifactId>
<version>1.1.8version>
dependency>
/**
* 创建topic
*/
private void createTopic() {
CloudAccount account = new CloudAccount(accessId, accessKey, endPoint);
MNSClient client = account.getMNSClient(); // 在程序中,CloudAccount以及MNSClient单例实现即可,多线程安全
String topicName = "TestTopic";
TopicMeta meta = new TopicMeta();
meta.setTopicName(topicName);
try {
CloudTopic topic = client.createTopic(meta);
} catch (Exception e) {
e.printStackTrace();
System.out.println("create topic error, " + e.getMessage());
}
client.close();// 程序退出时,需主动调用client的close 方法进行资源释放
}
/**
* 订阅topic
*/
public void subscribeTopic(){
try {
QueueMeta queueMeta = new QueueMeta();
queueMeta.setQueueName("TestSubForQueue");
this.client.createQueue(queueMeta);
CloudTopic topic = this.client.getTopicRef("TestTopic");
SubscriptionMeta subMeta = new SubscriptionMeta();
subMeta.setSubscriptionName("TestSub");
subMeta.setNotifyContentFormat(format);
subMeta.setEndpoint(topic.generateQueueEndpoint("TestSubForQueue"));
topic.subscribe(subMeta);
} catch (Exception e){
log.error("subscribe Topic error ,error:{}", e.getMessage());
e.printStackTrace();
}
this.client.close();
}
/**
* 发送消息
*/
private void PublishMessage() {
CloudTopic topic = this.client.getTopicRef("TestTopic");
try {
//可以使用TopicMessage结构,选择不进行Base64加密
TopicMessage msg = new RawTopicMessage();
msg.setMessageBody("Test Message Body: Hello World");
//设置该条发布消息的filterTag
if (StringUtils.isNotBlank(messageTag))
{
msg.setMessageTag("Hello"");
}
msg = topic.publishMessage(msg);
String messageId = msg.getMessageId();
String requestId = msg.getRequestId();
log.info("请求消息messageId:{}", messageId);
log.info("请求消息requestId:{}", requestId);
} catch (Exception e) {
log.error("send message error,{}", e.getMessage());
e.printStackTrace();
}
this.client.close();
}
/**
* 删除主题
*/
private void deleteTopic(){
CloudTopic topic = client.getTopicRef("TestTopic");
try {
topic.delete();
} catch (Exception e) {
e.printStackTrace();
log.error("delete topic error,{}", e.getMessage());
}
client.close();
}
主题还有个方式也可以实现一对多
public CloudPullTopic createPullTopic(TopicMeta topicMeta, Vector<String> queueNameList, boolean needCreateQueue, QueueMeta queueMetaTemplate)
public CloudPullTopic createPullTopic(TopicMeta topicMeta, Vector<String> queueNameList)
其中,TopicMeta 是创建topic的meta 设置, queueNameList里指定topic消息推送的队列名列表;needCreateQueue表明queueNameList是否需要创建;queueMetaTemplate是创建queue需要的queue meta 参数设置
大致意思是:直接将queue集合关联到某个topic ,也可以选择是否创建queue,默认是false不创建,个人感觉有个缺点是,我要一开始确定好我有几个queue来关联,若后面想增加一个queue就不太好做。
相对上面那种方式,可以后续加订阅关联。