生产者
1.依赖
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-common</artifactId>
<version>4.5.1</version>
</dependency>
2.配置文件
- 为了方便修改 并不是springboot的配置
# NameServer地址
apache.rocketmq.namesrvAddr=192.168.56.129:9876
# 生产者的组名
apache.rocketmq.producer.producerGroup=test_Producer
发送非事务消息
第一步:编写配置类
import org.apache.rocketmq.client.exception.MQClientException;
import org.apache.rocketmq.client.producer.DefaultMQProducer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class MsgProducer {
@Value("${apache.rocketmq.producer.producerGroup}")
private String producerGroup;
@Value("${apache.rocketmq.namesrvAddr}")
private String namesrvAddr;
private DefaultMQProducer mqProducer;
//调用方注入MsgProducer后 通过这个方法获取配置好的DefaultMQProducer
public DefaultMQProducer getMqProducer(){
return mqProducer;
}
@PostConstruct
public void initMQ(){
mqProducer=new DefaultMQProducer(producerGroup);
mqProducer.setNamesrvAddr(namesrvAddr);
mqProducer.setVipChannelEnabled(false);
try {
mqProducer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
}
@PreDestroy
public void destory(){
mqProducer.shutdown();
}
}
第二步:发送消息
- 同步、非顺序
@Autowired
private MsgProducer msgProducer;
public void sendMsg() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
//消息体
String msg="hello";
//包装成消息
Message message=new Message("test_topic_2","test",msg.getBytes());
//调用配置好的DefaultMQProducer发送消息
SendResult result=msgProducer.getMqProducer().send(message);
}
-
异步、非顺序
- 就是send()的参数多加个callback 省略…
-
同步、顺序
@Autowired
private MsgProducer msgProducer;
public void sendMsg() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
//发100条消息测试
for(int i=1;i<=100;i++){
/**
* 消息
* 因为默认自动创建的topic有四个队列 所以type表示队列id、value表示值
* 如果按照队列读取 那么同一个type下的value一定按照接收的顺序从小到大
* /
String msg="type:"+i%4+" value:"+i;
Message message=new Message("test_topic_2","test",msg.getBytes());
SendResult result=msgProducer.getMqProducer().send(message, new MessageQueueSelector() {
@Override
//args一般是唯一id 用send的第三个参数传入(这里指的i)
public MessageQueue select(List<MessageQueue> mqs, Message msg, Object arg) {
int queueNum = Integer.valueOf(String.valueOf(arg)) % 4;
System.out.println("队列id:"+queueNum+" 消息:"+new String(msg.getBody()));
return mqs.get(queueNum);
}
},i);
}
}
发送事务消息
(即消息先不发到broker的目的队列,而是包装一层放到中间队列,待提交之后再放到目的队列。)
第一步:配置类
@Component
public class TxMsgProducer {
@Value("${apache.rocketmq.producer.producerGroup}")
private String producerGroup;
@Value("${apache.rocketmq.namesrvAddr}")
private String namesrvAddr;
private TransactionMQProducer mqProducer;
public DefaultMQProducer getMqProducer(){
return mqProducer;
}
@PostConstruct
public void initMQ(){
mqProducer=new TransactionMQProducer(producerGroup);
mqProducer.setNamesrvAddr(namesrvAddr);
mqProducer.setVipChannelEnabled(false);
mqProducer.setNamesrvAddr(namesrvAddr);
//下面两个时新增的
mqProducer.setExecutorService(getExecutorService());
mqProducer.setTransactionListener(new TransactionListenerImpl());
try {
mqProducer.start();
} catch (MQClientException e) {
e.printStackTrace();
}
}
@PreDestroy//在程序运行结束时执行
public void destory(){
mqProducer.shutdown();
}
/**
* 事务监听
*/
class TransactionListenerImpl implements TransactionListener {
/**
* 第一次判断是否提交或回滚
*
* @param message
* @param arg
* @return
*/
@Override
public LocalTransactionState executeLocalTransaction(Message message, Object arg){
//message就是那个半发送的消息 arg是在transcationProducter.send(Message,Object)时的另外一个携带参数)
//执行本地事务或调用其他为服务
if(true) return LocalTransactionState.COMMIT_MESSAGE;
if(true) return LocalTransactionState.ROLLBACK_MESSAGE;
//如果在检查事务时数据库出现宕机可以让broker过一段时间回查 和return null 效果相同
return LocalTransactionState.UNKNOW;
}
/**
* 返回UNKOWN时回查!
* @param messageExt
* @return
*/
@Override
public LocalTransactionState checkLocalTransaction(MessageExt messageExt) {
//只去返回commit或者rollback
return LocalTransactionState.COMMIT_MESSAGE;
}
}
/**
* 定义一个线程池 让broker用来执行回调和回查
*
* @return
*/
public ExecutorService getExecutorService(){
return new ThreadPoolExecutor(2, 5, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(2000));
}
}
第二步:发送消息
@Autowired
private TxMsgProducer msgProducer;
public void sendMsg() throws InterruptedException, RemotingException, MQClientException, MQBrokerException {
String msg="hello";
Message message=new Message("test_topic_2","test",msg.getBytes());
//调用配置好的TxMsgProducer 发送消息
SendResult result=msgProducer.getMqProducer().send(message);
}
消费者
1.依赖
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-common</artifactId>
<version>4.5.1</version>
</dependency>
2.配置文件
- 为了方便修改 并不是springboot的配置
# NameServer地址
apache.rocketmq.namesrvAddr=192.168.56.129:9876
# 消费者的组名
apache.rocketmq.consumer.PushConsumer=test_Consumer
3.消费消息
@Component
public class MsgConsumer {
@Value("${apache.rocketmq.consumer.PushConsumer}")
private String consumerGroup;
@Value("${apache.rocketmq.namesrvAddr}")
private String namesrvAddr;
private DefaultMQPushConsumer consumer;
@PostConstruct
public void init() throws MQClientException {
consumer=new DefaultMQPushConsumer(consumerGroup);
consumer.setNamesrvAddr(namesrvAddr);
//设置consumer所订阅的Topic和Tag,*代表全部的Tag
consumer.subscribe("test_topic_2", "*");
/**
* CONSUME_FROM_LAST_OFFSET 默认策略,从该队列最尾开始消费,跳过历史消息
* CONSUME_FROM_FIRST_OFFSET 从队列最开始开始消费,即历史消息(还储存在broker的)全部消费一遍
* /
consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_LAST_OFFSET);
consumer.registerMessageListener(new MessageListenerConcurrently() {
@Override
public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> list, ConsumeOrderlyContext consumeOrderlyContext) {
try{
System.out.println("接受:"+new String(list.get(0).getBody()));
}catch (Exception e){
return ConsumeConcurrentlyStatus.SUSPEND_CURRENT_QUEUE_A_MOMENT;
}
return ConsumeConcurrentlyStatus.SUCCESS;
}
});
consumer.start();
}
@PreDestroy
public void destory(){
consumer.shutdown();
}
}
4.其他消费情况说明
- 顺序消费
- 只用把 consumer.registerMessageListener(new MessageListenerConcurrently(){}) 改成consumer.registerMessageListener(new MessageListenerOrderly(){})
- 事务消费
- 不用改变消费者 如果事务的监听rollback了 消费者的消费结果会自动回滚
- 广播消费
consumer.setMessageMode(MessageMode.BROADCASTING) consumer.setOffsetStore(OffsetStore.LocalFileOffsetStore)