这一篇我们来把消息中间件整合到springboot中

=====================================================================

首先在服务器上安装rabbitmq的服务,用docker拉取即可,不再详细描述。

直接来撸代码

首先我们先添加rabbitmq的依赖

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

在配置文件中添加必要的配置信息

spring.rabbitmq.host=192.168.0.86
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=123456

好了,基本的配置就已经配置完毕了

rabbitmq有六种模式

我们逐个来看springboot是怎么实现的呢

1.hello world

P代表生产者,C代表消费者,红色代码消息队列。P将消息发送到消息队列,C对消息进行处理。

我们先创建一个队列

@Bean
public Queue Queue() {
return new Queue("hello");
}

然后我再创建一个生产者

@Controller
public class HelloSender { @Autowired
private AmqpTemplate rabbitTemplate; public void send() {
String context = "hello " + new Date();
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("hello", context);
}
}

再创建一个消费者

@Component
@RabbitListener(queues = "hello")
public class HelloReceiver {
@RabbitHandler
public void process(String hello) {
System.out.println("Receiver : " + hello);
}
}

再写一个测试用例看看

@RunWith(SpringRunner.class)
@SpringBootTest
public class RabbitmqApplicationTests {
@Autowired
private HelloSender helloSender; @Test
public void hello() throws Exception {
helloSender.send();
}
}

成功!

2.工作模式(竞争)

一个消息产生者,多个消息的消费者。竞争抢消息

我们先创建一个队列

@Bean
public Queue Queue2() {
return new Queue("neo");
}

再创建一个消息生产者

@Controller
public class NeoSender {
@Autowired
private AmqpTemplate rabbitTemplate; public void send(int i) {
String context = "spirng boot neo queue"+" ****** "+i;
System.out.println("Sender1 : " + context);
this.rabbitTemplate.convertAndSend("neo", context);
}
}

再创建两个消息的消费者

 @Component
@RabbitListener(queues = "neo")
public class NeoReceiver1 {
@RabbitHandler
public void process(String neo) {
System.out.println("Receiver 1: " + neo);
}
} @Component
@RabbitListener(queues = "neo")
public class NeoReceiver2 {
@RabbitHandler
public void process(String neo) {
System.out.println("Receiver 2: " + neo);
} }

我们写一个测试用例

@Test
public void oneToMany() throws Exception {
for (int i=0;i<100;i++){
// Thread.sleep(10);
neoSender.send(i);
}
}

运行

可以看到消息均匀的被两个消费者消费了。

通过这个例子我们可以看做高并发情况下的消息产生和消费,这会产生一个消息丢失的问题。万一客户端在处理消息的时候挂了,那这条消息就相当于被浪费了,针对这种情况,rabbitmq推出了消息ack机制,熟悉tcp三次握手的一定不会陌生。

我们看看springboot是实现ack的

很简单,在我们的配置类中,配置一个新的消费者,将原先的消费者先都去掉:

@Bean
public SimpleMessageListenerContainer messageContainer() {
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory());
container.setQueues(Queue());
container.setExposeListenerChannel(true);
container.setMaxConcurrentConsumers(1);
container.setConcurrentConsumers(1);
container.setAcknowledgeMode(AcknowledgeMode.MANUAL);//消息确认后才能删除
container.setPrefetchCount(5);//每次处理5条消息
container.setMessageListener(new ChannelAwareMessageListener() { public void onMessage(Message message, com.rabbitmq.client.Channel channel) throws Exception {
byte[] body = message.getBody();
System.out.println("消费端接收到消息 : " + new String(body));
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
});
return container;
}

但这里会有个问题,test模式下消息发送完毕系统就会直接shutdown,所以只能消费部分消息,不过等真正启动项目,这个问题就不存在了。

3.发布订阅模式

生产者将消息不是直接发送到队列,而是发送到X交换机,然后由交换机发送给两个队列,两个消费者各自监听一个队列,来消费消息。

这种方式实现同一个消息被多个消费者消费。工作模式是同一个消息只能有一个消费者。

我们新建三个队列

@Bean
public Queue AMessage() {
return new Queue("fanout.A");
} @Bean
public Queue BMessage() {
return new Queue("fanout.B");
} @Bean
public Queue CMessage() {
return new Queue("fanout.C");
}

再新建一个交换机

@Bean
FanoutExchange fanoutExchange() {
return new FanoutExchange("fanoutExchange");
}

再把这些队列绑定到交换机上去

@Bean
Binding bindingExchangeA(Queue AMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(AMessage).to(fanoutExchange);
} @Bean
Binding bindingExchangeB(Queue BMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(BMessage).to(fanoutExchange);
} @Bean
Binding bindingExchangeC(Queue CMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(CMessage).to(fanoutExchange);
}

基本的配置完成后,再新建一个消息生产者

@Component
public class FanoutSender {
@Autowired
private AmqpTemplate rabbitTemplate; public void send() {
String context = "hi, fanout msg ";
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("fanoutExchange","", context);
}
}

同样的,我们再新建三个消息消费者

 @Component
@RabbitListener(queues = "fanout.A")
public class FanoutReceiveA { @RabbitHandler
public void process(String message) {
System.out.println("fanout Receiver A : " + message);
}
} @Component
@RabbitListener(queues = "fanout.B")
public class FanoutReceiverB {
@RabbitHandler
public void process(String message) {
System.out.println("fanout Receiver B: " + message);
}
} @Component
@RabbitListener(queues = "fanout.C")
public class FanoutReceiverC {
@RabbitHandler
public void process(String message) {
System.out.println("fanout Receiver C: " + message);
}
}

三个消费者分别监听3个队列的内容

新建一个测试用例:

@RunWith(SpringRunner.class)
@SpringBootTest
public class FanoutTest {
@Autowired
private FanoutSender fanoutSender; @Test
public void setFanoutSender(){
fanoutSender.send();
} }

三个队列都接受到了消息

4:路由模式

需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配,这是一个完整的匹配。

5.主题模式

发送端不只按固定的routing key发送消息,而是按字符串匹配发送,接收端同样如此

符号#匹配一个或多个词,符号*匹配不多不少一个词。

4/5两者模式很相似,我们放在一起演示

新建两个队列

final static String message = "topic.A";
final static String messages = "topic.B"; @Bean
public Queue queueMessage() {
return new Queue(TopicRabbitConfig.message);
} @Bean
public Queue queueMessages() {
return new Queue(TopicRabbitConfig.messages);
}

新建一个交换机

@Bean
TopicExchange exchange() {
return new TopicExchange("topicExchange");
}

绑定队列到交换机上,路由模式,需要完整匹配topic.message,才能接受

@Bean
Binding bindingExchangeMessage(Queue queueMessage, TopicExchange exchange) {
return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
}

topic模式,前缀匹配到topic.即可接受

@Bean
Binding bindingExchangeMessages(Queue queueMessages, TopicExchange exchange) {
return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
}

我们新建三个消息生产者

@Component
public class TopicSend {
@Autowired
private AmqpTemplate rabbitTemplate; public void send() {
String context = "hi, i am message all";
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("topicExchange", "topic.1", context);
} public void send1() {
String context = "hi, i am message 1";
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("topicExchange", "topic.message", context);
} public void send2() {
String context = "hi, i am messages 2";
System.out.println("Sender : " + context);
this.rabbitTemplate.convertAndSend("topicExchange", "topic.messages", context);
}
}

send的key是topic.1  send1的key是topic.message,send2的key是topic.messages

所以理论上send会被两个队列消费,1.2都应该只有一个队列消费

我们再新建两个消费者

@Component
@RabbitListener(queues = "topic.A")
public class TopicReceiver {
@RabbitHandler
public void process(String message) {
System.out.println("Topic Receiver1 : " + message);
} } @Component
@RabbitListener(queues = "topic.B")
public class TopicReceiver2 {
@RabbitHandler
public void process(String message) {
System.out.println("Topic Receiver2 : " + message);
}
}

写三个测试用例

@RunWith(SpringRunner.class)
@SpringBootTest
public class TopicTest {
@Autowired
private TopicSend sender; @Test
public void topic() throws Exception {
sender.send();
} @Test
public void topic1() throws Exception {
sender.send1();
} @Test
public void topic2() throws Exception {
sender.send2();
} }

send的运行结果

send1的运行结果

send2的运行结果

结果符合预期。







springboot rabbitmq整合的更多相关文章

  1. SpringBoot RabbitMQ 整合使用

    ![](http://ww2.sinaimg.cn/large/006tNc79ly1g5jjb62t88j30u00gwdi2.jpg) ### 前提 上次写了篇文章,[<SpringBoot ...

  2. springboot+rabbitmq整合示例程

    关于什么是rabbitmq,请看另一篇文: http://www.cnblogs.com/boshen-hzb/p/6840064.html 一.新建maven工程:springboot-rabbit ...

  3. springboot + rabbitmq 整合示例

    几个概念说明:Broker:简单来说就是消息队列服务器实体.Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列.Queue:消息队列载体,每个消息都会被投入到一个或多个队列.Bindi ...

  4. 消息中间件——RabbitMQ(十)RabbitMQ整合SpringBoot实战!(全)

    前言 1. SpringBoot整合配置详解 publisher-confirms,实现一个监听器用于监听Broker端给我们返回的确认请求:RabbitTemplate.ConfirmCallbac ...

  5. 带着新人学springboot的应用07(springboot+RabbitMQ 下)

    说一两句废话,强烈推荐各位小伙伴空闲时候也可以写写自己的博客!不管水平高低,不管写的怎么样,不要觉得写不好或者水平不够就不写了(咳,我以前就是这样的想法...自我反省!). 但是开始写博客之后,你会发 ...

  6. 带着新人学springboot的应用06(springboot+RabbitMQ 中)

    上一节说了这么多废话,看也看烦了,现在我们就来用鼠标点点点,来简单玩一下这个RabbitMQ. 注意:这一节还是不用敲什么代码,因为上一节我们设置了那个可视化工具,我们先用用可视化工具熟悉一下流程. ...

  7. RabbitMQ交换机、RabbitMQ整合springCloud

    目标 1.交换机 2.RabbitMQ整合springCloud 交换机 蓝色区域===生产者 红色区域===Server:又称Broker,接受客户端的连接,实现AMQP实体服务 绿色区域===消费 ...

  8. RabbitMQ 整合 SpringCloud实战

    RabbitMQ 整合 SpringCloud实战RabbitMQ 整合 SpringCloud实战rabbitmq-common 子项目rabbitmq-springcloud-consumer 子 ...

  9. 刚体验完RabbitMQ?一文带你SpringBoot+RabbitMQ方式收发消息

    人生终将是场单人旅途,孤独之前是迷茫,孤独过后是成长. 楔子 这篇是消息队列RabbitMQ的第二弹. 上一篇的结尾我也预告了本篇的内容:利用RabbitTemplate和注解进行收发消息,还有一个我 ...

随机推荐

  1. ContentType与SpiringMvc

    转载https://blog.csdn.net/mingtianhaiyouwo/article/details/51459764

  2. java 基本原则

    开闭原则:当应用的需求改变时,在不修改软件实体的源代码或者二进制代码的前提下,可以扩展模块的功能,使其满足新的需求. 可以通过“抽象约束.封装变化”来实现开闭原则,即通过接口或者抽象类为软件实体定义一 ...

  3. 在centos7上配置jenkins

    在Linux(centos7)环境下配置jenkins,并用github作为仓库. 配置jenkins https://blog.csdn.net/wangfei0904306/article/det ...

  4. Sublime 中文乱码问题

    今天在Windows上使用Sublime Text 3的时候,发现一些txt文本打开以后,中文都是乱码.于是搜了一下,找到了解决方案. 步骤: 在Sublime Text里,按ctrl+`,打开Con ...

  5. gitlab的安装和基本使用

    一.gitlab的安装 1)安装依赖包 sudo yum install git vim gcc glibc-statc telnet -y sudo yum install -y curl poli ...

  6. T-4-java核心API-集合类

    一.集合 用于存储类型一致的一组对象的数据结构. 类似于数组,但是集合提供了操作算法:集合=数据存储+操作算法.集合的用途极其广泛,如歌曲列表,联系人列表对话记录等. 集合比数组多了操作算法,便于提高 ...

  7. 2019.03.29 bzoj5463: [APIO2018] 铁人两项(圆方树+树形dp)

    传送门 题意简述:给你一张无向图,问你满足存在从a−>b−>ca->b->ca−>b−>c且不经过重复节点的路径的有序点对(a,b,c)(a,b,c)(a,b,c) ...

  8. 2019浙大校赛--J--Extended Twin Composite Number(毒瘤水题)

    毒瘤出题人,坑了我们好久,从基本的素数筛选,到埃氏筛法,到随机数快速素数判定,到费马小定理,好好的水题做成了数论题. 结果答案是 2*n=n+3*n,特判1,2. 以下为毒瘤题目: 题目大意: 输入一 ...

  9. sort()方法的应用(二)

    引用:函数作为参数 var fn_by = function(id) { return function(o, p) { var a, b; if (typeof o === "object ...

  10. 抄一篇maven的备忘

    标注下来源:http://www.trinea.cn/android/maven/ 由浅入深,主要介绍maven的用途.核心概念(Pom.Repositories.Artifact.Build Lif ...