消息中间件-RocketMQ
消息中间件简介
应用场景
- 异步解耦
- 削峰填谷
- 数据分发
常见消息中间件
-
ActiveMQ
ActiveMQ是Apache出品,比较老的一个开源的消息中间件,以前在中小企业应用广泛.
-
Kafka
Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。
-
RabbitMQ
RabbitMQ 是一个基于Erlang 语言开发的消息中间件,
RabbitMQ 最初起源于金融系统,用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。
对数据的一致性,稳定性和可靠性要求比较高的场景
-
RocketMQ
RocketMQ 是阿里巴巴在 2012 年开源的分布式消息中间件,目前已经捐赠给 Apache 软件基金会,并于 2017 年 9 月 25 日成为 Apache 的顶级项目。作为经历过多次阿里巴巴双十一这种“超级工程”的洗礼并有稳定出色表现的国产中间件,以其高性能、低延时和高可靠等特性近年来已经也被越来越多的国内企业使用。
淘宝内部的交易系统使用了淘宝自主研发的 Notify 消息中间件,使用 MySQL 作为消息存储媒介,可完全水平扩容,为了进一步降低成本,我们认为存储部分可以进一步优化,2011 年初,Linkin开源了 Kafka 这个优秀的消息中间件,淘宝中间件团队在对 Kafka 做过充分 Review 之后, Kafka 无限消息堆积,高效的持久化速度吸引了我们,但是同时发现这个消息系统主要定位于日志传输,对于使用在淘宝交易、订单、充值等场景下还有诸多特性不满足,为此我们重新用 Java 语言编写了 RocketMQ ,定位于非日志的可靠消息传输(日志场景也OK),目前 RocketMQ 在阿里集团被广泛应用在订单,交易,充值,流计算,消息推送,日志流式处理, binlog 分发等场景。
-
消息中间件对比
RocketMQ的核心概念
-
生产者Producer
负责生产消息,一般由业务系统负责生产消息。一个消息生产者会把业务应用系统里产生的消息发送到broker服务器。RocketMQ提供多种发送方式,同步发送、异步发送、顺序发送、单向发送。同步和异步方式均需要Broker返回确认信息,单向发送不需要。
-
消费者Consumer
负责消费消息,一般是后台系统负责异步消费。一个消息消费者会从Broker服务器拉取消息、并将其提供给应用程序。从用户应用的角度而言提供了两种消费形式:拉取式消费、推动式消费。
-
名字服务Name Server
名称服务充当路由消息的提供者。生产者或消费者能够通过名字服务查找各主题相应的Broker IP列表。多个Namesrv实例组成集群,但相互独立,没有信息交换。
-
代理服务器Broker Server
消息中转角色,负责存储消息、转发消息。代理服务器在RocketMQ系统中负责接收从生产者发送来的消息并存储、同时为消费者的拉取请求作准备。代理服务器也存储消息相关的元数据,包括消费者组、消费进度偏移和主题和队列消息等。
-
消息主题Topic
表示一类消息的集合,每个主题包含若干条消息,每条消息只能属于一个主题,是RocketMQ进行消息订阅的基本单位。
-
消息队列MessageQueue
对于每个Topic都可以设置一定数量的消息队列用来进行数据的读取
-
消息内容Message
消息系统所传输信息的物理载体,生产和消费数据的最小单位,每条消息必须属于一个主题。RocketMQ中每个消息拥有唯一的Message ID,且可以携带具有业务标识的Key。系统提供了通过Message ID和Key查询消息的功能。
-
标签Tag
为消息设置的标志,用于同一主题下区分不同类型的消息。来自同一业务单元的消息,可以根据不同业务目的在同一主题下设置不同标签。标签能够有效地保持代码的清晰度和连贯性,并优化RocketMQ提供的查询系统。消费者可以根据Tag实现对不同子主题的不同消费逻辑,实现更好的扩展性。
RocketMQ环境搭建
RocketMQ下载
http://rocketmq.apache.org/release_notes/release-notes-4.4.0/
单机部署
-
环境要求
Linux64位系统
JDK1.8(64位)
-
安装步骤
上传
rocketmq-all-4.4.0-bin-release.zip到/usr/local
使用解压命令进行解压
unzip /usr/local/rocketmq-all-4.4.0-bin-release.zip
软件文件名重命名
mv /usr/local/rocketmq-all-4.4.0-bin-release/ /usr/local/rocketmq-4.4/
设置环境变量
export JAVA_HOME=/usr/local/jdk1.8
export ROCKETMQ_HOME=/usr/local/rocketmq-4.4
export PATH= J A V A H O M E / b i n : JAVA_HOME/bin: JAVAHOME/bin:ROCKETMQ_HOME/bin:$PATH
-
启动RocketMQ
修改脚本中的JVM相关参数,修改文件如下
vi /usr/local/rocketmq-4.4/bin/runbroker.sh
vi /usr/local/rocketmq-4.4/bin/runserver.sh
修改启动参数配置
JAVA_OPT=“${JAVA_OPT} -server -Xms1g -Xmx1g -Xmn512m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=320m”
启动NameServer
1.启动NameServer
nohup sh mqnamesrv &
2.查看启动日志
tail -f ~/logs/rocketmqlogs/namesrv.log
启动Broker
1.启动Broker
nohup sh mqbroker -n localhost:9876 -c /usr/local/rocketmq-4.4/conf/broker.conf &
2.查看启动日志
tail -f ~/logs/rocketmqlogs/broker.log
-
关闭RocketMQ
关闭nameserver:
sh mqshutdown namesrv
关闭broker
sh mqshutdown broker
监控平台
https://github.com/apache/rocketmq-externals/tree/master/rocketmq-console
核心基础使用
入门案例
-
依赖
<groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-client</artifactId> <version>4.4.0</version>
-
发送消息
public class SyncProducer {
public static void main(String[] args) throws Exception { // 实例化消息生产者Producer DefaultMQProducer producer = new DefaultMQProducer("wolfcode_producer"); // 设置NameServer的地址 producer.setNamesrvAddr("192.168.20.161:9876"); // 启动Producer实例 producer.start(); for(int i=0;i<10;i++){ // 创建消息,并指定Topic,Tag和消息体 Message msg = new Message("TopicTest","TagA",("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET)); // 发送消息到一个Broker SendResult sendResult = producer.send(msg); // 通过sendResult返回消息是否成功送达 System.out.println(sendResult); } // 如果不再发送消息,关闭Producer实例。 producer.shutdown(); }
}
-
消费消息
public class Consumer {
public static void main(String[] args) throws Exception { // 实例化消息生产者Producer DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("wolfcode_consumer"); // 设置NameServer的地址 consumer.setNamesrvAddr("192.168.20.161:9876"); // 订阅一个或者多个Topic,以及Tag来过滤需要消费的消息 consumer.subscribe("TopicTest", "*"); consumer.registerMessageListener(new MessageListenerConcurrently() { public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { for(MessageExt messageExt:msgs){ System.out.println("消费线程:"+Thread.currentThread().getName()+",消息ID:"+messageExt.getMsgId()+",消息内容:"+new String(messageExt.getBody())); } return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } }); // 启动消费者实例 consumer.start(); System.out.printf("Consumer Started.%n"); }
}
消息发送方式
-
同步消息
这种可靠性同步地发送方式使用的比较广泛,比如:重要的消息通知,短信通知。
-
异步消息
异步消息通常用在对响应时间敏感的业务场景,即发送端不能容忍长时间地等待Broker的响应。
-
AsyncProducer
public class AsyncProducer {
public static void main(String[] args) throws Exception { // 实例化消息生产者Producer DefaultMQProducer producer = new DefaultMQProducer("wolfcode_producer"); // 设置NameServer的地址 producer.setNamesrvAddr("192.168.20.161:9876"); // 启动Producer实例 producer.start(); for(int i=0;i<10;i++){ // 创建消息,并指定Topic,Tag和消息体 Message msg = new Message("TopicTest","TagA",("异步消息" + i).getBytes(RemotingHelper.DEFAULT_CHARSET)); // 发送消息到一个Broker producer.send(msg, new SendCallback() { @Override public void onSuccess(SendResult sendResult) { System.out.println("消费线程:"+Thread.currentThread().getName()+"发送成功,消息ID:"+sendResult.getMsgId()); } @Override public void onException(Throwable e) { System.out.println("消费线程:"+Thread.currentThread().getName()+"发送失败"); e.printStackTrace(); } }); } // 等待5s TimeUnit.SECONDS.sleep(5); // 如果不再发送消息,关闭Producer实例。 producer.shutdown(); }
}
-
-
一次性消息
这种方式主要用在不特别关心发送结果的场景,例如日志发送。
-
OnewayProducer
public class OnewayProducer {
public static void main(String[] args) throws Exception{ // 实例化消息生产者Producer DefaultMQProducer producer = new DefaultMQProducer("wolfcode_producer"); // 设置NameServer的地址 producer.setNamesrvAddr("192.168.20.161:9876"); // 启动Producer实例 producer.start(); for (int i = 0; i < 10; i++) { // 创建消息,并指定Topic,Tag和消息体 Message msg = new Message("TopicTest" , "TagA" , ("一次性消息 " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) ); // 发送单向消息,没有任何返回结果 producer.sendOneway(msg); } // 如果不再发送消息,关闭Producer实例。 producer.shutdown(); }
}
-
消息消费方式
-
集群模式
消费者采用负载均衡方式消费消息,多个消费者共同消费队列消息,每个消费者处理的消息不同
MessageModel.CLUSTERING
-
广播模式
消费者采用广播的方式消费消息,每个消费者消费的消息都是相同的
MessageModel.BROADCASTING
顺序消息
消息有序指的是可以按照消息的发送顺序来消费(FIFO)。RocketMQ可以严格的保证消息有序,可以分为分区有序或者全局有序。
顺序消费的原理解析,在默认的情况下消息发送会采取Round Robin轮询方式把消息发送到不同的queue(分区队列);而消费消息的时候从多个queue上拉取消息,这种情况发送和消费是不能保证顺序。但是如果控制发送的顺序消息只依次发送到同一个queue中,消费的时候只从这个queue上依次拉取,则就保证了顺序。当发送和消费参与的queue只有一个,则是全局有序;如果多个queue参与,则为分区有序,即相对每个queue,消息都是有序的。
下面用订单进行分区有序的示例。一个订单的顺序流程是:创建、付款、推送、完成。订单号相同的消息会被先后发送到同一个队列中,消费时,同一个OrderId获取到的肯定是同一个队列。
-
生产者
public class Producer {
public static void main(String[] args) throws Exception { DefaultMQProducer producer = new DefaultMQProducer("wolfcode_producer2"); producer.setNamesrvAddr("192.168.20.161:9876"); producer.start(); // 订单列表 List<OrderStep> orderList = OrderUtil.buildOrders(); Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateStr = sdf.format(date); for (int i = 0; i < orderList.size(); i++) { // 加个时间前缀 String body = dateStr + " Hello RocketMQ " + orderList.get(i); Message msg = new Message("TopicTest", "TagA", body.getBytes()); SendResult sendResult = producer.send(msg, new MessageQueueSelector() { @Override public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) { Long id = (Long) arg; //根据订单id选择发送queue long index = id % mqs.size(); return mqs.get((int) index); } }, orderList.get(i).getOrderId());//订单id System.out.println(String.format("SendResult status:%s, queueId:%d, body:%s", sendResult.getSendStatus(), sendResult.getMessageQueue().getQueueId(), body)); } producer.shutdown(); }
}
-
消费者
public class ConsumerInOrder {
public static void main(String[] args) throws Exception { DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("wolfcode_consumer3"); consumer.setNamesrvAddr("192.168.20.161:9876"); /** * 设置Consumer第一次启动是从队列头部开始消费还是队列尾部开始消费<br> * 如果非第一次启动,那么按照上次消费的位置继续消费 */ consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET); consumer.subscribe("TopicTest", "*"); consumer.registerMessageListener(new MessageListenerOrderly() { Random random = new Random(); @Override public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) { context.setAutoCommit(true); try { //模拟业务逻辑处理中... TimeUnit.SECONDS.sleep(random.nextInt(3)); } catch (Exception e) { e.printStackTrace(); } for (MessageExt msg : msgs) { // 可以看到每个queue有唯一的consume线程来消费, 订单对每个queue(分区)有序 System.out.println("consumeThread=" + Thread.currentThread().getName() + "queueId=" + msg.getQueueId() + ", content:" + new String(msg.getBody())); } return ConsumeOrderlyStatus.SUCCESS; } }); consumer.start(); System.out.println("Consumer Started."); }
}
-
其他类
-
OrderStep
@Setter@Getter
public class OrderStep {
private long orderId; private String desc; @Override public String toString() { return "OrderStep{" + "orderId=" + orderId + ", desc='" + desc + '\'' + '}'; }
}
-
OrderUtil
public class OrderUtil {
/** * 生成模拟订单数据 */ public static List<OrderStep> buildOrders() { List<OrderStep> orderList = new ArrayList<OrderStep>(); OrderStep orderDemo = new OrderStep(); orderDemo.setOrderId(15103111039L); orderDemo.setDesc("创建"); orderList.add(orderDemo); orderDemo = new OrderStep(); orderDemo.setOrderId(15103111065L); orderDemo.setDesc("创建"); orderList.add(orderDemo); orderDemo = new OrderStep(); orderDemo.setOrderId(15103111039L); orderDemo.setDesc("付款"); orderList.add(orderDemo); orderDemo = new OrderStep(); orderDemo.setOrderId(15103117235L); orderDemo.setDesc("创建"); orderList.add(orderDemo); orderDemo = new OrderStep(); orderDemo.setOrderId(15103111065L); orderDemo.setDesc("付款"); orderList.add(orderDemo); orderDemo = new OrderStep(); orderDemo.setOrderId(15103117235L); orderDemo.setDesc("付款"); orderList.add(orderDemo); orderDemo = new OrderStep(); orderDemo.setOrderId(15103111065L); orderDemo.setDesc("完成"); orderList.add(orderDemo); orderDemo = new OrderStep(); orderDemo.setOrderId(15103111039L); orderDemo.setDesc("推送"); orderList.add(orderDemo); orderDemo = new OrderStep(); orderDemo.setOrderId(15103117235L); orderDemo.setDesc("完成"); orderList.add(orderDemo); orderDemo = new OrderStep(); orderDemo.setOrderId(15103111039L); orderDemo.setDesc("完成"); orderList.add(orderDemo); return orderList; }
}
-
延迟消息
现在RocketMq并不支持任意时间的延时,需要设置几个固定的延时等级,从1s到2h分别对应着等级1到18
“1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h”;
-
生产者
public class ScheduledMessageProducer {
public static void main(String[] args) throws Exception { // 实例化一个生产者来产生延时消息 DefaultMQProducer producer = new DefaultMQProducer("wolfcode_producer"); producer.setNamesrvAddr("192.168.20.161:9876"); // 启动生产者 producer.start(); int totalMessagesToSend = 10; for (int i = 0; i < totalMessagesToSend; i++) { Message message = new Message("TestTopic", ("发送延时消息" + i+",发送时间:"+new Date()).getBytes()); // 设置延时等级3,这个消息将在10s之后发送(现在只支持固定的几个时间,详看delayTimeLevel) message.setDelayTimeLevel(3); // 发送消息 producer.send(message); } // 关闭生产者 producer.shutdown(); }
}
-
消费者
public class ScheduledMessageConsumer {
public static void main(String[] args) throws Exception { // 实例化消费者 DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("wolfcode_consumer"); consumer.setNamesrvAddr("192.168.20.161:9876"); // 订阅Topics consumer.subscribe("TestTopic", "*"); // 注册消息监听者 consumer.registerMessageListener(new MessageListenerConcurrently() { public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> messages, ConsumeConcurrentlyContext context) { for (MessageExt message : messages) { // Print approximate delay time period System.out.println("消息内容:"+new String(message.getBody())+",消费时间:" +new Date()); } return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } }); // 启动消费者 consumer.start(); }
}
消息过滤
在大多数情况下,TAG是一个简单而有用的设计,其可以来选择您想要的消息。例如:
DefaultMQPushConsumer consumer = new DefaultMQPushConsumer(“CID_EXAMPLE”);
consumer.subscribe(“TOPIC”, “TAGA || TAGB || TAGC”);
消费者将接收包含TAGA或TAGB或TAGC的消息。但是限制是一个消息只能有一个标签,这对于复杂的场景可能不起作用。在这种情况下,可以使用SQL表达式筛选消息。SQL特性可以通过发送消息时的属性来进行计算。在RocketMQ定义的语法下,可以实现一些简单的逻辑。下面是一个例子:
| message |
|----------| a > 5 AND b = ‘abc’
| a = 10 | --------------------> Gotten
| b = ‘abc’|
| c = true |
| message |
|----------| a > 5 AND b = ‘abc’
| a = 1 | --------------------> Missed
| b = ‘abc’|
| c = true |
-
Tag标签过滤
-
SQL92过滤
-
基本语法
RocketMQ只定义了一些基本语法来支持这个特性。你也可以很容易地扩展它。
数值比较,比如:>,>=,<,<=,BETWEEN,=;
字符比较,比如:=,<>,IN;
IS NULL** 或者 IS NOT NULL;
逻辑符号 AND,OR,NOT;
常量支持类型为:
数值,比如:**123,3.1415;
字符,比如:‘abc’,必须用单引号包裹起来;
NULL,特殊的常量
布尔值,TRUE 或 FALSE
只有使用push模式的消费者才能用使用SQL92标准的sql语句,接口如下:
public void subscribe(finalString topic, final MessageSelector messageSelector)
注意: 在使用SQL过滤的时候, 需要配置参数enablePropertyFilter=true
-
生产者
public class Producer {
public static void main(String[] args) throws Exception { // 实例化消息生产者Producer DefaultMQProducer producer = new DefaultMQProducer("wolfcode_producer"); // 设置NameServer的地址 producer.setNamesrvAddr("192.168.20.161:9876"); // 启动Producer实例 producer.start(); try { for(int i=0;i<10;i++){ Message msg1 = new Message("filterTest", "Tag", new String("过滤消息"+i).getBytes(Charset.forName("utf-8"))); msg1.putUserProperty("i",String.valueOf(i)); producer.send(msg1); } } catch (Exception e) { e.printStackTrace(); //处理error } // 如果不再发送消息,关闭Producer实例。 producer.shutdown(); }
}
-
消费者
public class Consumer {
public static void main(String[] args) throws Exception { // 实例化消息生产者Producer DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("wolfcode_consumer"); // 设置NameServer的地址 consumer.setNamesrvAddr("192.168.20.161:9876"); // 订阅一个或者多个Topic,以及Tag来过滤需要消费的消息 consumer.subscribe("filterTest", MessageSelector.bySql("i>3 and i<8")); consumer.registerMessageListener(new MessageListenerConcurrently() { public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { for(MessageExt messageExt:msgs){ System.out.println("消息内容:"+new String(messageExt.getBody())); } return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } }); // 启动消费者实例 consumer.start(); System.out.printf("Consumer Started.%n"); }
}
-
SpringBoot集成
导入依赖
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.0.4</version>
</dependency>
相关配置
-
生产者
rocketmq.name-server=192.168.20.161:9876
rocketmq.producer.group=my-group
-
消费者
rocketmq.name-server=192.168.20.161:9876
消息发送方式
-
同步消息
@Test
public void testSyncMessage() throws Exception { SendResult result = rocketMQTemplate.syncSend("springboot-hello2", "springboot发送同步消息"); System.out.println("发送状态:"+result.getSendStatus()); }
-
异步消息
@Test
public void testASyncMessage() throws Exception { rocketMQTemplate.asyncSend("springboot-hello2", "springboot发送异步消息", new SendCallback() { @Override public void onSuccess(SendResult sendResult) { System.out.println(sendResult.getMsgId()+"发送成功"); } @Override public void onException(Throwable e) { System.out.println("发送是吧"); } }); TimeUnit.SECONDS.sleep(5); }
-
一次性消息
@Test
public void testOnewayMessage() throws Exception { for(int i=0;i<10;i++){ rocketMQTemplate.sendOneWay("springboot-hello2", "springboot发送一次性消息"+i+",发送时间:"+new Date()); } }
消息消费方式
-
集群模式
@Component
@RocketMQMessageListener(consumerGroup = “hello-Consumer”,topic = “springboot-hello2”)
public class HelloConsumer implements RocketMQListener {
@Override public void onMessage(MessageExt message) { System.out.println("内容为:"+new String(message.getBody())); }
}
-
广播模式
@RocketMQMessageListener(consumerGroup = “hello-Consumer”,topic = “springboot-hello2”,messageModel = MessageModel.BROADCASTING)
顺序消息
-
生产者
@Test
public void testOrderlyMessage() throws Exception { List<OrderStep> orderSteps = OrderUtil.buildOrders(); rocketMQTemplate.setMessageQueueSelector(new MessageQueueSelector() { @Override public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) { String orderId = (String) arg; Long index = Long.parseLong(orderId)%mqs.size(); return mqs.get(index.intValue()); } }); for(OrderStep orderStep:orderSteps){ rocketMQTemplate.sendOneWayOrderly("springboot-orderTopic",orderStep,orderStep.getOrderId()+""); } }
-
消费者
@Component
@RocketMQMessageListener(consumerGroup = “order-consumer”,topic = “springboot-orderTopic”,consumeMode = ConsumeMode.ORDERLY)
public class OrderlyConsumer implements RocketMQListener {
@Override public void onMessage(OrderStep message) { System.out.println(message); }
}
延迟消息
-
生产者
@Test
public void testDelayMessage() throws Exception { org.springframework.messaging.Message<String> msg = MessageBuilder.withPayload("springboot发送延迟" + ",发送时间:" + new Date()).build(); rocketMQTemplate.syncSend("springboot-delayTopic", msg,3000,3); }
-
消费者
@Component
@RocketMQMessageListener(consumerGroup = “delay-consumer”,topic = “springboot-delayTopic”)
public class DelayConsumer implements RocketMQListener {
@Override public void onMessage(String message) { System.out.println("收到消息:"+message+",消费时间:"+new Date()); }
}
消息过滤
-
Tag标签过滤
-
生产者
@Test
public void testFilterByTagMessage() throws Exception { rocketMQTemplate.sendOneWay("springboot-filter-tag:Tag1","我是Tag1消息"); rocketMQTemplate.sendOneWay("springboot-filter-tag:Tag2","我是Tag2消息"); rocketMQTemplate.sendOneWay("springboot-filter-tag:Tag3","我是Tag3消息"); rocketMQTemplate.sendOneWay("springboot-filter-tag:Tag1","Hello--->Tag1"); rocketMQTemplate.sendOneWay("springboot-filter-tag:Tag1:mykey","Hello--->Tag1:mykey"); }
-
消费者
@Component
@RocketMQMessageListener(consumerGroup = “filter-Consumer”,topic = “springboot-filter-tag”,selectorExpression = “Tag1 || Tag2”)
public class FilterByTagConsumer implements RocketMQListener {
@Override public void onMessage(MessageExt message) { System.out.println("内容为:"+new String(message.getBody())); }
}
-
-
SQL92过滤
-
生产者
@Test
public void testFilterBySQLMessage() throws Exception { for(int i=0;i<10;i++){ rocketMQTemplate.sendOneWay("springboot-filter-sql",MessageBuilder.withPayload("我是消息"+i).setHeader("i",i)); } }
-
消费者
@Component
@RocketMQMessageListener(consumerGroup = “filter-Consumer02”,topic = “springboot-filter-sql”,selectorType = SelectorType.SQL92,selectorExpression = “i>3 and i<8”)
public class FilterBySQL92Consumer implements RocketMQListener {
@Override public void onMessage(MessageExt message) { System.out.println("内容为:"+new String(message.getBody())); }
}
-