Simple Message Queue (SMQ, formerly MNS) supports a combined topic-and-queue pattern: a topic distributes each published message to multiple queues via push, and consumers pull from their own private queues. This tutorial implements that fan-out architecture using the SMQ Java SDK.
This tutorial uses the SDK for Java. For SDKs in other languages, see Reference for New Version SDKs (Recommended).
Messaging model comparison
SMQ provides two base messaging models. The right choice depends on how consumers receive messages, whether their endpoints can be exposed, and whether selective delivery is needed.
|
Model |
How it works |
Consumer visibility |
Message filtering |
Best for |
|
Queue-based |
One client sends messages to a queue. Multiple consumers pull messages, but each message goes to only one consumer. |
Endpoints stay private |
Not supported |
Point-to-point task distribution |
|
Topic-based |
One client publishes messages to a topic. SMQ pushes messages to all subscribed consumers. |
Endpoints must be exposed |
Supported via subscription filters |
Real-time push notifications |
|
Combined (this tutorial) |
One client publishes to a topic. The topic pushes messages into multiple queues. Each consumer pulls from its own queue. |
Endpoints stay private |
Supported via subscription filters |
Fan-out with private consumers |
The combined pattern suits scenarios where a message must reach multiple consumers whose endpoints cannot be exposed — for example, consumers running inside a private network.
Example scenario: An order processing system publishes each new order to a topic. Separate queues feed into fulfillment, analytics, and notification services. Each service pulls orders from its own queue independently, without exposing an inbound endpoint.
How it works
The combined pattern connects a topic to multiple queues through subscriptions. A subscription acts as a virtual queue: it receives a copy of every message published to the topic, and consumers pull from it exactly as they would from a regular queue.
The setup follows these steps:
Create a topic and one queue per consumer.
Subscribe each queue to the topic. The queue endpoint becomes the subscription target.
The producer publishes a message to the topic.
SMQ copies the message into every subscribed queue.
Each consumer pulls its copy from its own queue.

Because consumers pull from queues rather than receiving pushed messages, their endpoints are never exposed to SMQ or to each other.
Prerequisites
Before you begin, ensure that you have:
IntelliJ IDEA or Eclipse installed (this tutorial uses IntelliJ IDEA)
JDK 1.8 or later
Apache Maven 2.5 or later
Install the Java dependency
Add the SMQ SDK dependency to the pom.xml file of your Java project:
<dependencies>
<dependency>
<groupId>com.aliyun.mns</groupId>
<artifactId>aliyun-sdk-mns</artifactId>
<version>1.1.9.2</version>
</dependency>
</dependencies>
CloudPullTopic API reference
SDK for Java 1.1.8 introduced the CloudPullTopic class, which encapsulates the combined topic-and-queue pattern. Create a CloudPullTopic object through MNSClient:
// Full form: create queues automatically with a queue metadata template
public CloudPullTopic createPullTopic(
TopicMeta topicMeta,
Vector<String> queueNameList,
boolean needCreateQueue,
QueueMeta queueMetaTemplate
)
// Short form: use existing queues (no automatic creation)
public CloudPullTopic createPullTopic(
TopicMeta topicMeta,
Vector<String> queueNameList
)
|
Parameter |
Description |
|
|
Metadata of the topic (name, properties). |
|
|
List of queue names. Each queue receives a copy of every published message. |
|
|
Whether to create the queues listed in |
|
|
Queue metadata template applied to all auto-created queues (e.g., polling wait time). |
Publish and consume messages
The following sample uses CloudPullTopic to wire up the fan-out, publish a message, and pull it from three separate queues.
package doc;
import com.aliyun.mns.client.CloudAccount;
import com.aliyun.mns.client.MNSClient;
import com.aliyun.mns.client.CloudPullTopic;
import com.aliyun.mns.client.CloudQueue;
import com.aliyun.mns.model.QueueMeta;
import com.aliyun.mns.model.TopicMeta;
import com.aliyun.mns.model.TopicMessage;
import com.aliyun.mns.model.RawTopicMessage;
import com.aliyun.mns.model.Message;
import com.aliyun.mns.common.ServiceException;
import com.aliyun.mns.common.ClientException;
import java.util.Vector;
public class DemoTopicMessageBroadcast {
public static void main(String[] args) {
// Initialize the client with your AccessKey ID, AccessKey Secret, and endpoint.
CloudAccount account = new CloudAccount(
ServiceSettings.getMNSAccessKeyId(),
ServiceSettings.getMNSAccessKeySecret(),
ServiceSettings.getMNSAccountEndpoint());
MNSClient client = account.getMNSClient();
// Define three consumer queues.
Vector<String> consumerNameList = new Vector<String>();
String consumerName1 = "consumer001";
String consumerName2 = "consumer002";
String consumerName3 = "consumer003";
consumerNameList.add(consumerName1);
consumerNameList.add(consumerName2);
consumerNameList.add(consumerName3);
// Set long polling to 30 seconds for the auto-created queues.
QueueMeta queueMetaTemplate = new QueueMeta();
queueMetaTemplate.setPollingWaitSeconds(30);
try {
// --- Producer: create a topic and publish a message ---
String topicName = "demo-topic-for-pull";
TopicMeta topicMeta = new TopicMeta();
topicMeta.setTopicName(topicName);
// createPullTopic creates the topic, creates the three consumer queues,
// and subscribes each queue to the topic — all in one call.
CloudPullTopic pullTopic = client.createPullTopic(
topicMeta, consumerNameList, true, queueMetaTemplate);
// Publish a raw message to the topic. SMQ copies it into all subscribed queues.
String messageBody = "broadcast message to all the consumers:hello the world.";
TopicMessage tMessage = new RawTopicMessage();
tMessage.setBaseMessageBody(messageBody);
pullTopic.publishMessage(tMessage);
// --- Consumers: pull the message from each queue ---
CloudQueue queueForConsumer1 = client.getQueueRef(consumerName1);
CloudQueue queueForConsumer2 = client.getQueueRef(consumerName2);
CloudQueue queueForConsumer3 = client.getQueueRef(consumerName3);
// popMessage(30) waits up to 30 seconds for a message (long polling).
Message consumer1Msg = queueForConsumer1.popMessage(30);
if (consumer1Msg != null) {
System.out.println("consumer1 received: "
+ consumer1Msg.getMessageBodyAsRawString());
} else {
System.out.println("consumer1 queue is empty");
}
Message consumer2Msg = queueForConsumer2.popMessage(30);
if (consumer2Msg != null) {
System.out.println("consumer2 received: "
+ consumer2Msg.getMessageBodyAsRawString());
} else {
System.out.println("consumer2 queue is empty");
}
Message consumer3Msg = queueForConsumer3.popMessage(30);
if (consumer3Msg != null) {
System.out.println("consumer3 received: "
+ consumer3Msg.getMessageBodyAsRawString());
} else {
System.out.println("consumer3 queue is empty");
}
// Clean up: delete the topic, its subscriptions, and all associated queues.
pullTopic.delete();
} catch (ClientException ce) {
System.out.println("Network error between the client and SMQ. "
+ "Check your network and DNS settings.");
ce.printStackTrace();
} catch (ServiceException se) {
se.printStackTrace();
}
client.close();
}
}
Verify the result
After running the sample, confirm that each consumer received the message. Expected output:
consumer1 received: broadcast message to all the consumers:hello the world.
consumer2 received: broadcast message to all the consumers:hello the world.
consumer3 received: broadcast message to all the consumers:hello the world.
If a queue shows "queue is empty", the message may not have been delivered yet. Increase the popMessage timeout or verify that the topic and subscriptions were created correctly.
Code walkthrough
|
Step |
What happens |
|
Initialize |
Authenticates with your AccessKey ID, AccessKey Secret, and SMQ endpoint. |
|
Call |
Creates the topic, creates the three consumer queues, and subscribes each queue to the topic. |
|
Call |
Publishes a raw message ( |
|
Call |
Each consumer pulls its copy with a 30-second long-polling timeout. |
|
Call |
Deletes the topic, its subscriptions, and all associated queues. |
The sample publishes a raw message (RawTopicMessage). Parse raw messages withgetMessageBodyAsRawString(). If you useBase64TopicMessageinstead, parse withgetMessageBodyAsString().
What's next
Explore other SMQ messaging patterns in Reference for New Version SDKs (Recommended).