1.什么是MQ,为什么要用MQ
MQ:MessageQueue,消息队列。 队列,是一种FIFO 先进先出的数据结构。消息由生产者发送
到MQ 进行排队,然后按原来的顺序交由消息的消费者进行处理。QQ和微信就是典型的MQ。
MQ的作用主要有以下三个方面:
异步
例子:快递员发快递,直接到客户家效率会很低。引入菜鸟驿站后,快递员只需要把快递放到菜鸟
驿站,就可以继续发其他快递去了。客户再按自己的时间安排去菜鸟驿站取快递。
作用:异步能提高系统的响应速度、吞吐量。
![](https://img-blog.csdnimg.cn/img_convert/8c46b84fdcb459011b71e96e0a34acaf.png)
![](https://img-blog.csdnimg.cn/img_convert/0155852424a21d09197e674c16ae8664.gif)
编辑
![](https://img-blog.csdnimg.cn/img_convert/772f47c8d3089680842a1f7d30c7a2f3.png)
![](https://img-blog.csdnimg.cn/img_convert/9d6104ad7ec3bbe0efac5cf995152f74.gif)
编辑
解耦
例子:《Thinking in JAVA》很经典,但是都是英文,我们看不懂,所以需要编辑社,将文章翻译
成其他语言,这样就可以完成英语与其他语言的交流。
作用:
服务之间进行解耦,才可以减少服务之间的影响。提高系统整体的稳定性以及可扩展性。
另外,解耦后可以实现数据分发。生产者发送一个消息后,可以由一个或者多个消费者进行消费,并且消费者的增加或者减少对生产者没有影响。
![](https://img-blog.csdnimg.cn/img_convert/8e2c48f2973f64fc30820b0698908356.gif)
编辑
削峰
例子:长江每年都会涨水,但是下游出水口的速度是基本稳定的,所以会涨水。引入三峡大坝后,
可以把水储存起来,下游慢慢排水。
作用:以稳定的系统资源应对突发的流量冲击
![](https://img-blog.csdnimg.cn/img_convert/5888dedc6932b96813fa3c0df104ae77.jpeg)
![](https://img-blog.csdnimg.cn/img_convert/cc35e17ef9b6767a1317fe54433408d3.gif)
编辑
![](https://img-blog.csdnimg.cn/img_convert/ea7a3c89c1e5e699c61ed2ea0cfc89d1.jpeg)
![](https://img-blog.csdnimg.cn/img_convert/30566d33c478bca58a2c514c64c7c30f.gif)
编辑
2.MQ的优缺点
上面MQ的所用也就是使用MQ的优点。 但是引入MQ也是有他的缺点的:
系统可用性降低
系统引入的外部依赖增多,系统的稳定性就会变差。一旦MQ宕机,对业务会产生影响。这就需要考虑 如何保证MQ的高可用。
系统复杂度提高
引入MQ后系统的复杂度会大大提高。以前服务之间可以进行同步的服务调用,引入MQ后,会变为异步调用,数据的链路就会变得更复杂。并且还会带来其他一些问题。比如:如何保证消费不会丢失?不会被重复调用?怎么保证消息的顺序性等问题。
消息一致性问题
A系统处理完业务,通过MQ发送消息给B、C系统进行后续的业务处理。如果B系统处理成功,C系统处理失败怎么办?这就需要考虑如何保证消息数据处理的一致性。
3.几大产品MQ的特点比较
![](https://img-blog.csdnimg.cn/img_convert/ee2d18e5e359fa86a63039d9556945ee.png)
![](https://img-blog.csdnimg.cn/img_convert/c763a756c1f05c976313448cfd5f7ed9.gif)
编辑
4.RockerMQ的几种发送模式
--------------------------------------------------------消费者--------------------------------------------------
publicclassConsumer {
publicstaticvoidmain(String[] args)throws InterruptedException, MQClientException {
/*
* Instantiate with specified consumer group name.
*/DefaultMQPushConsumerconsumer=newDefaultMQPushConsumer("please_rename_unique_group_name_4");
/*
* Specify name server addresses.
* <p/>
*
* Alternatively, you may specify name server addresses via exporting environmental variable: NAMESRV_ADDR
* <pre>
* {@code
* consumer.setNamesrvAddr("name-server1-ip:9876;name-server2-ip:9876");
* }
* </pre>
*/
consumer.setNamesrvAddr("192.168.232.128:9876");
/*
* Specify where to start in case the specified consumer group is a brand new one.
*/
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
/*
* Subscribe one more more topics to consume.
*/
consumer.subscribe("TopicTest", "*");
/*
* Register callback to execute on arrival of messages fetched from brokers.
*/
consumer.registerMessageListener(newMessageListenerConcurrently() {
@Overridepublic ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
/*
* Launch the consumer instance.
*/
consumer.start();
System.out.printf("Consumer Started.%n");
}
}
![](https://img-blog.csdnimg.cn/img_convert/97b61a5507219073861a2d83799ae6c0.gif)
---------------------------------------------------生产者----------------------------------------------------
//简单样例:同步发送消息publicclassProducer {
publicstaticvoidmain(String[] args)throws MQClientException, InterruptedException {
DefaultMQProducerproducer=newDefaultMQProducer("ProducerGroupName");
//nameserver有两种方式指定//1.setNamesrvAddr//producer.setNamesrvAddr("192.168.232.128:9876");//2.配置环境变量
producer.start();
for (inti=0; i < 20; i++)
try {
{
Messagemsg=newMessage("TopicTest",
"TagA",
"OrderID188",
"Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
//同步传递消息,消息会发给集群中的一个Broker节点。// SendResult sendResult = producer.send(msg);// System.out.printf("%s%n", sendResult);
producer.sendOneway(msg);
}
} catch (Exception e) {
e.printStackTrace();
}
producer.shutdown();
}
}
![](https://img-blog.csdnimg.cn/img_convert/4da58cec398fab2ab663ae4421bcea51.gif)
单向发送,同步发送,异步发送
单向发送:生产者把消息往mq那里一发,后续就不管了,这种效率最高,sendOneway 没有返回值
同步发送:你发的消息,有没有成功,mq是知道的,必须等到发送完毕且结果返回
代码改成 有返回值
SendResult sendResult = producer.send(msg); System.out.printf("%s%n", sendResult);
异步发送:producer在发送完之后,就不管了,去做自己的事情,但是它会给MQ一个回调函数
主要代码
producer.send(msg, new SendCallback() { @Override public void onSuccess(SendResult sendResult) { countDownLatch.countDown(); System.out.printf("%-10d OK %s %n", index, sendResult.getMsgId()); }
注意还使用了countdownlatch 为了保证全部消息发送完毕后 ,再停止producer服务
//简单样例:异步发送消息publicclassAsyncProducer {
publicstaticvoidmain(
String[] args)throws MQClientException, InterruptedException, UnsupportedEncodingException {
//实例化一个实例DefaultMQProducerproducer=newDefaultMQProducer("Jodie_Daily_test");
// producer.setNamesrvAddr("192.168.232.128:9876");
producer.start();
producer.setRetryTimesWhenSendAsyncFailed(0);
intmessageCount=100;
//由于是异步发送,这里引入一个countDownLatch,保证所有Producer发送消息的回调方法都执行完了再停止Producer服务。finalCountDownLatchcountDownLatch=newCountDownLatch(messageCount);
for (inti=0; i < messageCount; i++) {
try {
finalintindex= i;
Messagemsg=newMessage("TopicTest",
"TagA",
"OrderID188",
"Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
producer.send(msg, newSendCallback() {
@OverridepublicvoidonSuccess(SendResult sendResult) {
countDownLatch.countDown();
System.out.printf("%-10d OK %s %n", index, sendResult.getMsgId());
}
@OverridepublicvoidonException(Throwable e) {
countDownLatch.countDown();
System.out.printf("%-10d Exception %s %n", index, e);
e.printStackTrace();
}
});
System.out.println("消息发送完成");
} catch (Exception e) {
e.printStackTrace();
}
}
countDownLatch.await(5, TimeUnit.SECONDS);
producer.shutdown();
}
}
![](https://img-blog.csdnimg.cn/img_convert/9b7581b88a4b99f494c8cf66889e0412.gif)
5.rocketMQ的两种接收模式
推模式,拉模式
拉模式:消费者主动去broker上拉去消息
publicclassPullConsumer {
privatestaticfinal Map<MessageQueue, Long> OFFSE_TABLE = newHashMap<MessageQueue, Long>();
publicstaticvoidmain(String[] args)throws MQClientException {
DefaultMQPullConsumerconsumer=newDefaultMQPullConsumer("please_rename_unique_group_name_5");
consumer.setNamesrvAddr("192.168.232.128:9876");
consumer.start();
Set<MessageQueue> mqs = consumer.fetchSubscribeMessageQueues("TopicTest");
for (MessageQueue mq : mqs) {
System.out.printf("Consume from the queue: %s%n", mq);
SINGLE_MQ:
while (true) {
try {
PullResultpullResult=//参数2:offset 偏移量//参数3:每一次最多拿32条消息
consumer.pullBlockIfNotFound(mq, null, getMessageQueueOffset(mq), 32);
System.out.printf("%s%n", pullResult);
putMessageQueueOffset(mq, pullResult.getNextBeginOffset());
switch (pullResult.getPullStatus()) {
case FOUND:
break;
case NO_MATCHED_MSG:
break;
case NO_NEW_MSG:
break SINGLE_MQ;
case OFFSET_ILLEGAL:
break;
default:
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
consumer.shutdown();
}
privatestaticlonggetMessageQueueOffset(MessageQueue mq) {
Longoffset= OFFSE_TABLE.get(mq);
if (offset != null)
return offset;
return0;
}
privatestaticvoidputMessageQueueOffset(MessageQueue mq, long offset) {
OFFSE_TABLE.put(mq, offset);
}
}
![](https://img-blog.csdnimg.cn/img_convert/64a4481b7465fd6feee8650ae1d87c84.gif)
傻瓜模式,不需要自己去设置offset
publicclassLitePullConsumerAssign {
publicstaticvolatilebooleanrunning=true;
publicstaticvoidmain(String[] args)throws Exception {
DefaultLitePullConsumerlitePullConsumer=newDefaultLitePullConsumer("please_rename_unique_group_name");
litePullConsumer.setAutoCommit(false);
litePullConsumer.start();
Collection<MessageQueue> mqSet = litePullConsumer.fetchMessageQueues("TopicTest");
List<MessageQueue> list = newArrayList<>(mqSet);
List<MessageQueue> assignList = newArrayList<>();
for (inti=0; i < list.size() / 2; i++) {
assignList.add(list.get(i));
}
litePullConsumer.assign(assignList);
litePullConsumer.seek(assignList.get(0), 10);
try {
while (running) {
List<MessageExt> messageExts = litePullConsumer.poll();
System.out.printf("%s %n", messageExts);
litePullConsumer.commitSync();
}
} finally {
litePullConsumer.shutdown();
}
}
}
![](https://img-blog.csdnimg.cn/img_convert/b40ef2fe8d9fae9c5ace4243ab8ad9ca.gif)
这个可以定制自己的消费的起点
DefaultLitePullConsumer
publicclassLitePullConsumerSubscribe {
publicstaticvolatilebooleanrunning=true;
publicstaticvoidmain(String[] args)throws Exception {
DefaultLitePullConsumerlitePullConsumer=newDefaultLitePullConsumer("lite_pull_consumer_test");
litePullConsumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
litePullConsumer.subscribe("TopicTest", "*");
litePullConsumer.start();
try {
while (running) {
List<MessageExt> messageExts = litePullConsumer.poll();
System.out.printf("%s%n", messageExts);
}
} finally {
litePullConsumer.shutdown();
}
}
}
![](https://img-blog.csdnimg.cn/img_convert/83bd1fc14fca9a3e8ee9795acf8fde6c.gif)
推模式:由broker收到消息后,主动推送给消费者
主要代码
consumer.registerMessageListener(new MessageListenerConcurrently() { @Override public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs); return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; } });
首先listener监听
然后执行里面的方法,返回他的状态ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
publicclassPushConsumer {
publicstaticvoidmain(String[] args)throws InterruptedException, MQClientException {
DefaultMQPushConsumerconsumer=newDefaultMQPushConsumer("CID_JODIE_1");
// consumer.setNamesrvAddr("192.168.232.128:9876");
consumer.subscribe("TopicTest", "*");
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
//wrong time format 2017_0422_221800
consumer.setConsumeTimestamp("20181109221800");
consumer.registerMessageListener(newMessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
System.out.printf("Consumer Started.%n");
}
}
![](https://img-blog.csdnimg.cn/img_convert/d2b498ec6bdb88c7cee6d61519c44705.gif)
消息顺序
主要使用监听器newMessageListenerOrderly 来保证先从一个一个队列拿,就能保证局部有序
局部有序,全局不一定有序
核心代码
SendResult sendResult = producer.send(msg, new MessageQueueSelector() { @Override public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) { Integer id = (Integer) arg; int index = id % mqs.size(); return mqs.get(index); } }, orderId);
要保证同一个orderID 都放在同一个队列里面去
publicclassProducer {
publicstaticvoidmain(String[] args)throws UnsupportedEncodingException {
try {
DefaultMQProducerproducer=newDefaultMQProducer("please_rename_unique_group_name");
// producer.setNamesrvAddr("192.168.232.128:9876");
producer.start();
for (inti=0; i < 10; i++) {
intorderId= i;
for(intj=0 ; j <= 5 ; j ++){
Messagemsg=new Message("OrderTopicTest", "order_"+orderId, "KEY" + orderId,
("order_"+orderId+" step " + j).getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResultsendResult= producer.send(msg, newMessageQueueSelector() {
@Override
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
Integerid= (Integer) arg;
intindex= id % mqs.size();
return mqs.get(index);
}
}, orderId);
System.out.printf("%s%n", sendResult);
}
}
producer.shutdown();
} catch (MQClientException | RemotingException | MQBrokerException | InterruptedException e) {
e.printStackTrace();
}
}
}
--------------------------------------------消费者--------------------------------------
核心代码
consumer.registerMessageListener(new MessageListenerOrderly() { @Override public ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) { context.setAutoCommit(true); for(MessageExt msg:msgs){ System.out.println("收到消息内容 "+new String(msg.getBody())); } return ConsumeOrderlyStatus.SUCCESS; } });
new MessageListenerOrderly()这个是会帮我们从同一个消息队列里面拿消息,
MessageListenerConcurrently是做不到这点的
publicclassConsumer {
publicstaticvoidmain(String[] args)throws MQClientException {
DefaultMQPushConsumerconsumer=newDefaultMQPushConsumer("please_rename_unique_group_name_3");
consumer.setNamesrvAddr("192.168.232.128:9876");
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
consumer.subscribe("OrderTopicTest", "*");
consumer.registerMessageListener(newMessageListenerOrderly() {
@Overridepublic ConsumeOrderlyStatus consumeMessage(List<MessageExt> msgs, ConsumeOrderlyContext context) {
context.setAutoCommit(true);
for(MessageExt msg:msgs){
System.out.println("收到消息内容 "+newString(msg.getBody()));
}
return ConsumeOrderlyStatus.SUCCESS;
}
});
// 这样是保证不了最终消费顺序的。
// consumer.registerMessageListener(new MessageListenerConcurrently() {
// @Override
// public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) {
// for(MessageExt msg:msgs){
// System.out.println("收到消息内容 "+new String(msg.getBody()));// }
// return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;// }
// });
consumer.start();
System.out.printf("Consumer Started.%n");
}
}
![](https://img-blog.csdnimg.cn/img_convert/35f3f0cc00916da141b8c069db78ced3.gif)
7.广播消息
会收到所有的producer的消息
核心代码
consumer.setMessageModel(MessageModel.BROADCASTING);
在所有的producer共享
publicclassPushConsumer {
publicstaticvoidmain(String[] args)throws InterruptedException, MQClientException {
DefaultMQPushConsumerconsumer=newDefaultMQPushConsumer("please_rename_unique_group_name_1");
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
consumer.setMessageModel(MessageModel.BROADCASTING);
consumer.subscribe("TopicTest", "*");
consumer.registerMessageListener(newMessageListenerConcurrently() {
@Overridepublic ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
System.out.printf("Broadcast Consumer Started.%n");
}
}
![](https://img-blog.csdnimg.cn/img_convert/a3578217193931bbe14eabd3aef01945.gif)
8.延迟消息
核心代码
//messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2 hmsg.setDelayTimeLevel(3);
publicclassProducer {
publicstaticvoidmain(String[] args)throws MQClientException, InterruptedException {
/*
* Instantiate with a producer group name.
*/DefaultMQProducerproducer=newDefaultMQProducer("please_rename_unique_group_name");
/*
* Specify name server addresses.
* <p/>
*
* Alternatively, you may specify name server addresses via exporting environmental variable: NAMESRV_ADDR
* <pre>
* {@code
* producer.setNamesrvAddr("name-server1-ip:9876;name-server2-ip:9876");
* }
* </pre>
*/
producer.setNamesrvAddr("192.168.232.128:9876");
/*
* Launch the instance.
*/
producer.start();
for (inti=0; i < 2; i++) {
try {
/*
* Create a message instance, specifying topic, tag and message body.
*/Messagemsg=newMessage("TopicTest"/* Topic */,
"TagA"/* Tag */,
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET) /* Message body */
);
//messageDelayLevel=1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h
msg.setDelayTimeLevel(3);
/*
* Call send message to deliver message to one of brokers.
*/SendResultsendResult= producer.send(msg);
System.out.printf("%s%n", sendResult);
} catch (Exception e) {
e.printStackTrace();
Thread.sleep(1000);
}
}
/*
* Shut down once the producer instance is not longer in use.
*/
producer.shutdown();
}
}
![](https://img-blog.csdnimg.cn/img_convert/60a96e29f575efb757a6f65ff29f51f8.gif)
批量消息
批量消息有限制,不能超过1兆,必须是相同的topic,相同的waitStoreMsgOk,且不能是延迟消息,事务消息
将多条消息合成一个批量消息,一次性发送出去,减少网络IO
核心代码 List<Message> messages = new ArrayList<>(); messages.add(new Message(topic, "Tag", "OrderID001", "Hello world 0".getBytes())); messages.add(new Message(topic, "Tag", "OrderID002", "Hello world 1".getBytes())); messages.add(new Message(topic, "Tag", "OrderID003", "Hello world 2".getBytes())); producer.send(messages);
publicclassSimpleBatchProducer {
publicstaticvoidmain(String[] args)throws Exception {
DefaultMQProducerproducer=newDefaultMQProducer("BatchProducerGroupName");
producer.start();
//If you just send messages of no more than 1MiB at a time, it is easy to use batch//Messages of the same batch should have: same topic, same waitStoreMsgOK and no schedule supportStringtopic="BatchTest";
List<Message> messages = newArrayList<>();
messages.add(newMessage(topic, "Tag", "OrderID001", "Hello world 0".getBytes()));
messages.add(newMessage(topic, "Tag", "OrderID002", "Hello world 1".getBytes()));
messages.add(newMessage(topic, "Tag", "OrderID003", "Hello world 2".getBytes()));
producer.send(messages);
producer.shutdown();
}
}
![](https://img-blog.csdnimg.cn/img_convert/d0a781ba86b2baa2ebe8d71230982da2.gif)
10.过滤消息
好处:在发送之前进行过滤,只发送对方想要的消息,减少IO
------------------------------------------------------消费者------------------------------------------------
consumer.subscribe("TagFilterTest", "TagA || TagC");
publicclassTagFilterConsumer {
publicstaticvoidmain(String[] args)throws InterruptedException, MQClientException, IOException {
DefaultMQPushConsumerconsumer=newDefaultMQPushConsumer("please_rename_unique_group_name");
consumer.subscribe("TagFilterTest", "TagA || TagC");
consumer.registerMessageListener(newMessageListenerConcurrently() {
@Overridepublic ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
System.out.printf("Consumer Started.%n");
}
}
![](https://img-blog.csdnimg.cn/img_convert/d7833458a5279e302964d674446d3ae0.gif)
------------------------------------------------------生产者------------------------------------------------
publicclassTagFilterProducer {
publicstaticvoidmain(String[] args)throws Exception {
DefaultMQProducerproducer=newDefaultMQProducer("please_rename_unique_group_name");
producer.start();
String[] tags = newString[] {"TagA", "TagB", "TagC"};
for (inti=0; i < 15; i++) {
Messagemsg=newMessage("TagFilterTest",
tags[i % tags.length],
"Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResultsendResult= producer.send(msg);
System.out.printf("%s%n", sendResult);
}
producer.shutdown();
}
}
![](https://img-blog.csdnimg.cn/img_convert/bf68adcc6c6c4d7e38f7f6ef7ad05d6b.gif)
SQL过滤
consumer.subscribe("SqlFilterTest", MessageSelector.bySql("(TAGS is not null and TAGS in ('TagA', 'TagB'))" + "and (a is not null and a between 0 and 3)"));
可以像写SQL语句一样去过滤
publicclassSqlFilterConsumer {
publicstaticvoidmain(String[] args)throws Exception {
DefaultMQPushConsumerconsumer=newDefaultMQPushConsumer("please_rename_unique_group_name");
// Don't forget to set enablePropertyFilter=true in broker
consumer.subscribe("SqlFilterTest",
MessageSelector.bySql("(TAGS is not null and TAGS in ('TagA', 'TagB'))" +
"and (a is not null and a between 0 and 3)"));
consumer.registerMessageListener(newMessageListenerConcurrently() {
@Overridepublic ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs,
ConsumeConcurrentlyContext context) {
System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
}
});
consumer.start();
System.out.printf("Consumer Started.%n");
}
}
![](https://img-blog.csdnimg.cn/img_convert/e67ba50b7235967772ed86d988378443.gif)
11.事务消息
事务消息只跟发送者有关,和消费者没太大关系
TransactionListener transactionListener = new TransactionListenerImpl(); 这个类里面做的事情 String tags = msg.getTags(); if(StringUtils.contains(tags,"TagA")){ return LocalTransactionState.COMMIT_MESSAGE; }else if(StringUtils.contains(tags,"TagB")){ return LocalTransactionState.ROLLBACK_MESSAGE; }else{ return LocalTransactionState.UNKNOW; } TransactionMQProducer producer = new TransactionMQProducer("please_rename_unique_group_name");
SendResult sendResult = producer.sendMessageInTransaction(msg, null);
publicclassTransactionProducer {
publicstaticvoidmain(String[] args)throws MQClientException, InterruptedException {
TransactionListenertransactionListener=newTransactionListenerImpl();
TransactionMQProducerproducer=newTransactionMQProducer("please_rename_unique_group_name");
// producer.setNamesrvAddr("127.0.0.1:9876");ExecutorServiceexecutorService=newThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS, newArrayBlockingQueue<Runnable>(2000), newThreadFactory() {
@Overridepublic Thread newThread(Runnable r) {
Threadthread=newThread(r);
thread.setName("client-transaction-msg-check-thread");
return thread;
}
});
producer.setExecutorService(executorService);
producer.setTransactionListener(transactionListener);
producer.start();
String[] tags = newString[] {"TagA", "TagB", "TagC", "TagD", "TagE"};
for (inti=0; i < 10; i++) {
try {
Messagemsg=newMessage("TopicTest", tags[i % tags.length], "KEY" + i,
("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResultsendResult= producer.sendMessageInTransaction(msg, null);
System.out.printf("%s%n", sendResult);
Thread.sleep(10);
} catch (MQClientException | UnsupportedEncodingException e) {
e.printStackTrace();
}
}
for (inti=0; i < 100000; i++) {
Thread.sleep(1000);
}
producer.shutdown();
}
}
![](https://img-blog.csdnimg.cn/img_convert/72af7361692b37b8354f1cecde61dc73.gif)
publicclassTransactionListenerImplimplementsTransactionListener {
privateAtomicIntegertransactionIndex=newAtomicInteger(0);
private ConcurrentHashMap<String, Integer> localTrans = newConcurrentHashMap<>();
@Overridepublic LocalTransactionState executeLocalTransaction(Message msg, Object arg) {
// int value = transactionIndex.getAndIncrement();// int status = value % 3;// localTrans.put(msg.getTransactionId(), status);// return LocalTransactionState.UNKNOW;Stringtags= msg.getTags();
if(StringUtils.contains(tags,"TagA")){
return LocalTransactionState.COMMIT_MESSAGE;
}elseif(StringUtils.contains(tags,"TagB")){
return LocalTransactionState.ROLLBACK_MESSAGE;
}else{
return LocalTransactionState.UNKNOW;
}
}
@Overridepublic LocalTransactionState checkLocalTransaction(MessageExt msg) {
// Integer status = localTrans.get(msg.getTransactionId());// if (null != status) {// switch (status) {// case 0:// return LocalTransactionState.UNKNOW;// case 1:// return LocalTransactionState.COMMIT_MESSAGE;// case 2:// return LocalTransactionState.ROLLBACK_MESSAGE;// default:// return LocalTransactionState.COMMIT_MESSAGE;// }// }// return LocalTransactionState.COMMIT_MESSAGE;Stringtags= msg.getTags();
if(StringUtils.contains(tags,"TagC")){
return LocalTransactionState.COMMIT_MESSAGE;
}elseif(StringUtils.contains(tags,"TagD")){
return LocalTransactionState.ROLLBACK_MESSAGE;
}else{
return LocalTransactionState.UNKNOW;
}
}
}
![](https://img-blog.csdnimg.cn/img_convert/a5985bd23ae6ca8a8e7a3ac91994a237.gif)
![](https://img-blog.csdnimg.cn/img_convert/d6cf46fb87fee563c23a997a3e88f837.png)
![](https://img-blog.csdnimg.cn/img_convert/31877cc6c061729f09ce35131c6ade10.gif)
rocketMQ和SpringBoot的整合
(1)引入依赖
(2)配置文件
![](https://img-blog.csdnimg.cn/img_convert/35be80b1c14c881554d368fc78c3e2a1.png)
12.rocketMQ和SpringCloud的整合
1.导包
2.启动类
![](https://img-blog.csdnimg.cn/img_convert/7965504e5afe91cc01f456a295995ce0.png)
![](https://img-blog.csdnimg.cn/img_convert/fe41f8a8e583c4b801056b7e6bfaaf8b.gif)
编辑
3.配置类
input 消息接收者 对应启动类上面的Source.class
output 消息发送者 对应启动类上面的Sink.class
name-server 指定地址
![](https://img-blog.csdnimg.cn/img_convert/85de6b7e40a3383983f75e9faa29a51f.png)
![](https://img-blog.csdnimg.cn/img_convert/f7549c8593b42a8f107ead37d0a8f5c6.gif)
编辑
![](https://img-blog.csdnimg.cn/img_convert/9f28e42838fb877b569b33ed52ca6e20.png)
![](https://img-blog.csdnimg.cn/img_convert/3c382e45095d0ae3405e63f4eadd2d3a.gif)
编辑
生产者
source.output().send(message)
![](https://img-blog.csdnimg.cn/img_convert/f2cb1a9cbbf1ffb5e8249812a2dfd24b.png)
![](https://img-blog.csdnimg.cn/img_convert/efe0dc0ca7c055bc10fb90786e0427d3.gif)
编辑
消费者
![](https://img-blog.csdnimg.cn/img_convert/758cdc5c17ce45dc35409dd73ff96c2b.png)
![](https://img-blog.csdnimg.cn/img_convert/56e3ca8fd67a348615b0f94cd8d2ef56.gif)
编辑
如果哪天不用rocketMQ,换成别的,我们只需要换掉pom依赖,改一下配置即可