一、Linux安装
Centos7下基于jdk11 安装RocketMQ_rocketmq支持jdk11吗_刚仔灬的博客-CSDN博客
嘎嘎权威
二、创建maven父子工程
rocketmq_master(下面的src文件夹可以删除,因为不在父工程中写代码)
rocker_provider :生产者
rocket_consumer:消费者
1.依赖管理
rocketmq_master
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.1</version>
</dependency>
</dependencies>
rocker_provider
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.1</version>
</dependency>
</dependencies>
rocket_consume
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-spring-boot-starter</artifactId>
<version>2.2.1</version>
</dependency>
</dependencies>
2.provider建立application 启动类
@SpringBootApplication
public class ProviderApp {
public static void main(String[] args) {
SpringApplication.run(ProviderApp.class);
}
}
3.provider建立controller
@RestController
public class ProviderController {
}
4.消费者建立application
@SpringBootApplication
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class);
}
}
三、消息发送与接收
1.README.md
RocketMQ的发消息
消息本身分类
普通消息
延时消息 生产者向broker发送延时消息 消息发送成功后 消费者无法消费 时间过去后 消费者才能消费
顺序消息
事务消息
。。。
消息发送的方式
同步发消息 生产者向broker发消息 线程必须等待 等到broker响应为止
异步发消息 生产者向broker发消息 不等待 代码继续向下执行 消息是否发送成功通过回调函数告知
单向发消息 生产者向broker发消息 不等待 代码继续向下执行 也不关注是否发送成功 也不需要broker告知是否成功
2.设置生产者组(application.yml)
server:
port: 9000
#因为依赖中有web启动项,会启动内置tomcat,用8080端口会被占用
rocketmq:
name-server: 192.168.8.128:9876
producer:
group: abc
#设置生产者组、:不设置会报错 目前来说没有意义
3.设置消费者(application.yml)
这里不需要设置生产者组,因为是消费者
server:
port: 9100
rocketmq:
name-server: 192.168.8.128:9876
4.同步发送普通字符串消息
Controller
@RestController
public class ProviderController {
//
@Autowired
private RocketMQTemplate rocketMQTemplate;
/**
* 发普通的字符串消息
*/
@GetMapping("syncSendMessageString")
public String syncSendMessageString(){
//消息本身
String message = "这是一个普通字符串消息";
//主题 生产者从nameServer获取broker地址,向broker发送消息
//为了把消息进行分类,消费消息时,可以指定主题消费
String topic = "syncSendMessageStringTopic";
SendResult sendResult = rocketMQTemplate.syncSend(topic, message);
return "success";
}
}
注:RocketMQTemplate是RocketMQ的一个Spring集成模块,它提供了对RocketMQ进行操作和发送消息的简化方式。使用RocketMQTemplate可以通过Spring的方式方便地将消息发送到RocketMQ,并且可以根据需要进行配置和管理。
5.在浏览器中输入ip:端口号/请求路径触发消息发送
6.同步接收普通字符串(无需建立controller)
建立components
@Component
@RocketMQMessageListener(topic = "syncSendMessageStringTopic", consumerGroup = "receiveSyncMessageByString")
//消费者组想写啥写啥
public class receiveSyncMessageByString implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
System.out.println("接受的消息: " + s);
}
}
@RocketMQListener<String> 实现接消息的接口 泛型写发消息的类型
@Compoent :将其注入容器
@RocketMQMessageListener:
topic:provicer生产者中的controller中设置的的topic主题
comsumerGroup:消费者组(随便写,想写啥写啥)
接收消息测试(还是刷新浏览器的地址)
注:如何让控制台出现多个可运行的SpringBootApplication
view--->Tool Windows----->Services
点击加号----->RunConfiguration Type---->Add Configuration Type----->Spring Boot
7.同步发送实体类消息
先建立实体类model
pom依赖
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
实体类
@Data
@Accessors(chain = true)
public class Xiaoer {
private Integer id;
private String xiaoerName;
}
provider和consumer引入entity依赖(pom引入的都一样)
<dependency>
<groupId>org.example</groupId>
<artifactId>rocketmq_entity</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
provider的controller
@GetMapping("syncSendMessageByObj")
public String syncSendMessageByObj(){
Xiaoer xiaoer = new Xiaoer().setId(1).setXiaoerName("小二");
SendResult result = rocketMQTemplate.syncSend("syncSendMessageByObjTopic", xiaoer);
// 获取结果状态
System.out.println(result.getSendStatus());
return "success";
}
consumer的receviceSyncMessageByObject
@Component
@RocketMQMessageListener(topic = "syncSendMessageByObjTopic", consumerGroup = "receiveSyncMessageByObject")
public class receiveSyncMessageByObject implements RocketMQListener<Xiaoer> {
@Override
public void onMessage(Xiaoer xiaoer) {
System.out.println("这是个实体类: " + xiaoer);
}
}
启动测试(无需去浏览器输入)
启动providerApp
启动consumerApp
8.异步执行发送普通字符串消息
provider的Controller
由代码可以看出,异步发送消息与同步发送消息不同的是,asyncSend方法内多了个回调函数
他的作用就是告知异步发送消息是否成功
@GetMapping("asyncSendMessageByStr")
public String asyncSendMessageByStr(){
System.out.println("准备发送消息了");
rocketMQTemplate.asyncSend("asyncSendMessageByStrTopic", "这是一个异步消息", new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
System.out.println("onSuccess执行l");
}
@Override
public void onException(Throwable throwable) {
}
});
System.out.println("准备返回了");
return "success";
}
consumer的receiveAsyncSendMessageByStr
@Component
@RocketMQMessageListener(topic = "asyncSendMessageByStrTopic", consumerGroup = "receiveAsyncSendMessageByStr")
public class receiveAsyncSendMessageByStr implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
System.out.println("异步执行成功" + s);
}
}
9.单向发送消息(异步)
provider的Controller
@GetMapping("sendMessageOneWay")
public String sendMessageOneWay(){
rocketMQTemplate.sendOneWay("sendMessageOneWayTopic", "我是个单向消息");
return "success";
}
consumer的receiveSendMessageOneWay
@Component
@RocketMQMessageListener(topic = "sendMessageOneWayTopic", consumerGroup = "receiveSendMessageOneWay")
public class receiveSendMessageOneWay implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
System.out.println("单向发了一条消息:" + s);
}
}
10.发送顺序消息(队列:先进先出)
provider的controller
@GetMapping("sendMessageOrderly")
public String sendMessageOrderly(){
rocketMQTemplate.syncSend("sendMessageOrderlyTopic","下单成功");
rocketMQTemplate.syncSend("sendMessageOrderlyTopic","付款成功");
rocketMQTemplate.syncSend("sendMessageOrderlyTopic","收货成功");
rocketMQTemplate.syncSend("sendMessageOrderlyTopic","退货失败");
rocketMQTemplate.syncSend("sendMessageOrderlyTopic","=================");
return "success";
}
consumer的_5receiveSendMessageOrderly
@Component
@RocketMQMessageListener(topic = "sendMessageOrderlyTopic", consumerGroup = "_5recsiveSendMessageOrderly")
public class _5recsiveSendMessageOrderly implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
System.out.println("顺序消息: " + s);
}
}
测试
测试出来的问题
这时出现了个问题:明明我发送的是顺序消息,应该按照,下单成功,付款成功,收货成功,退货失败,========几个来按顺序发送
但顺序明显是不对的
在最开始,提到了这里用的消息队列,队列的特性就是先进先出,但是这里只有一个队列吗,我觉得咱们最开始的想法是如下图的
一个队列,按顺序排几个消息
但事实上,有四个队列!!!! 并且还是同时读取的
解决办法:把消息放到一个队列里就可以了!!!!
但是万一还有其他消息怎么办呢,消费者是从四个队列同时获取,这时候该怎么办
四个队列不能同时读=======>消费消息有顺序=======>一个队列一个队列读
总结:
发送者只能把消息放入一个队列里,读取者只能读这个队列====>负载均衡(默认哈希)
修改代码
修改后的provider的controller
@GetMapping("sendMessageOrderly")
public String sendMessageOrderly(){
rocketMQTemplate.syncSendOrderly("sendMessageOrderlyTopic","下单成功","1");
rocketMQTemplate.syncSendOrderly("sendMessageOrderlyTopic","付款成功","1");
rocketMQTemplate.syncSendOrderly("sendMessageOrderlyTopic","收货成功","1");
rocketMQTemplate.syncSendOrderly("sendMessageOrderlyTopic","退货失败","1");
rocketMQTemplate.syncSendOrderly("sendMessageOrderlyTopic","=================","1");
return "success";
}
将syncSend方法修改为syncSendOrdely,并且这时后面还要加一个类型为String的相同的hashKey,这样就保证了发送的时候发送在一个队列里
修改后的consumer的_5receiveSendMessageOrderly
@Component
@RocketMQMessageListener(topic = "sendMessageOrderlyTopic", consumerGroup = "_5recsiveSendMessageOrderly", consumeMode = Co)
public class _5recsiveSendMessageOrderly implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
System.out.println("顺序消息: " + s);
}
}
consumeMode = ConsumeMode.ORDERLY 代表消息topic的消息只能读那一个队列的
consumeMode是枚举类,内部一共有两个值
concurrently:同时读几个队列
orderly:只读那一个队列
修改后的测试
11.延时消息(常用:12306抢票)
生产者向broker发送延时消息 消息发送成功后 消费者无法消费 时间过去后 消费者才能消费、
并且rocketmq定义好了时间,供选择 用1-18数字代替 表示等级 代码中要写的就是等级 而不是时间
provider的controller
@GetMapping("sendMessageDelay")
public String sendMessageDelay(){
GenericMessage<String> message = new GenericMessage<>("我是延时消息");
rocketMQTemplate.syncSend("sendMessageDelayTopic", message, 5000,4);
return "success";
}
consumer的_6recsiveSendMessageDelay
@Component
@RocketMQMessageListener(topic = "sendMessageOrderlyTopic", consumerGroup = "_5recsiveSendMessageOrderly", consumeMode = ConsumeMode.ORDERLY)
public class _6recsiveSendMessageDelay implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
System.out.println("我是延时消息: " + s);
}
}
12.消息过滤
只想收取某些消息
provider的Controller
@GetMapping("sendMessageByTag")
public String sendMessageByTag(){
rocketMQTemplate.syncSend("sendMessageByTagTopic:a", "11111");
rocketMQTemplate.syncSend("sendMessageByTagTopic:b", "22222");
rocketMQTemplate.syncSend("sendMessageByTagTopic:c", "33333");
rocketMQTemplate.syncSend("sendMessageByTagTopic:d", "44444");
return "success";
}
sendMessageByTagTopic:a 冒号后面的为此消息的标签
/**
* 标签支持 或 非 等于
*/
@Component
@RocketMQMessageListener(topic = "sendMessageByTagTopic", consumerGroup = "_7recsiveSendMessageByTag", selectorExpression = "a || c")
public class _7recsiveSendMessageByTag implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
System.out.println("我会过滤消息" + s);
}
}
consumer的_7recsiveSendMessageByTag
/**
* 标签支持 或 非 等于
*/
@Component
@RocketMQMessageListener(topic = "sendMessageByTagTopic", consumerGroup = "_7recsiveSendMessageByTag", selectorExpression = "a || c")
public class _7recsiveSendMessageByTag implements RocketMQListener<String> {
@Override
public void onMessage(String s) {
System.out.println("我会过滤消息" + s);
}
}
selectorExpression = "a || c" 指定消息为a c的