详解spring boot集成RabbitMQ
作者:SamHxm 发布时间:2022-06-25 17:56:07
RabbitMQ作为AMQP的代表性产品,在项目中大量使用。结合现在主流的spring boot,极大简化了开发过程中所涉及到的消息通信问题。
首先正确的安装RabbitMQ及运行正常。
RabbitMQ需啊erlang环境,所以首先安装对应版本的erlang,可在RabbitMQ官网下载
# rpm -ivh erlang-19.0.4-1.el7.centos.x86_64.rpm
使用yum安装RabbitMQ,避免缺少依赖包引起的安装失败
# yum install rabbitmq-server-3.6.6-1.el7.noarch.rpm
启动RabbitMQ
# /sbin/service rabbitmq-server start
由于RabbitMQ默认提供的guest用户只能本地访问,所以额外创建用户用于测试
# /sbin/rabbitmqctl add_user test test123
用户名:test,密码:test123
开启web管理插件
# rabbitmq-plugins enable rabbitmq_management
并使用之前创建的用户登录,并设置该用户为administrator,虚拟主机地址为/
spring boot 引入相关依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
</dependencies>
消息生产者
application.properties添加一下配置
spring.rabbitmq.host=192.168.1.107
spring.rabbitmq.port=5672
spring.rabbitmq.username=test
spring.rabbitmq.password=test123
spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.publisher-returns=true
spring.rabbitmq.template.mandatory=true
spring boot配置类,作用为指定队列,交换器类型及绑定操作
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitConfig {
//声明队列
@Bean
public Queue queue1() {
return new Queue("hello.queue1", true); // true表示持久化该队列
}
@Bean
public Queue queue2() {
return new Queue("hello.queue2", true);
}
//声明交互器
@Bean
TopicExchange topicExchange() {
return new TopicExchange("topicExchange");
}
//绑定
@Bean
public Binding binding1() {
return BindingBuilder.bind(queue1()).to(topicExchange()).with("key.1");
}
@Bean
public Binding binding2() {
return BindingBuilder.bind(queue2()).to(topicExchange()).with("key.#");
}
}
共声明了2个队列,分别是hello.queue1,hello.queue2,交换器类型为TopicExchange,并与hello.queue1,hello.queue2队列分别绑定。
生产者类
import java.util.UUID;
import javax.annotation.PostConstruct;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.core.RabbitTemplate.ReturnCallback;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class Sender implements RabbitTemplate.ConfirmCallback, ReturnCallback {
@Autowired
private RabbitTemplate rabbitTemplate;
@PostConstruct
public void init() {
rabbitTemplate.setConfirmCallback(this);
rabbitTemplate.setReturnCallback(this);
}
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
if (ack) {
System.out.println("消息发送成功:" + correlationData);
} else {
System.out.println("消息发送失败:" + cause);
}
}
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
System.out.println(message.getMessageProperties().getCorrelationIdString() + " 发送失败");
}
//发送消息,不需要实现任何接口,供外部调用。
public void send(String msg){
CorrelationData correlationId = new CorrelationData(UUID.randomUUID().toString());
System.out.println("开始发送消息 : " + msg.toLowerCase());
String response = rabbitTemplate.convertSendAndReceive("topicExchange", "key.1", msg, correlationId).toString();
System.out.println("结束发送消息 : " + msg.toLowerCase());
System.out.println("消费者响应 : " + response + " 消息处理完成");
}
}
要点:
1.注入RabbitTemplate
2.实现RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnCallback接口(非必须)。
ConfirmCallback接口用于实现消息发送到RabbitMQ交换器后接收ack回调。ReturnCallback接口用于实现消息发送到RabbitMQ交换器,但无相应队列与交换器绑定时的回调。
3.实现消息发送方法。调用rabbitTemplate相应的方法即可。rabbitTemplate常用发送方法有
rabbitTemplate.send(message); //发消息,参数类型为org.springframework.amqp.core.Message
rabbitTemplate.convertAndSend(object); //转换并发送消息。 将参数对象转换为org.springframework.amqp.core.Message后发送
rabbitTemplate.convertSendAndReceive(message) //转换并发送消息,且等待消息者返回响应消息。
针对业务场景选择合适的消息发送方式即可。
消息消费者
application.properties添加一下配置
spring.rabbitmq.host=192.168.1.107
spring.rabbitmq.port=5672
spring.rabbitmq.username=test
spring.rabbitmq.password=test123
spring.rabbitmq.listener.concurrency=2 //最小消息监听线程数
spring.rabbitmq.listener.max-concurrency=2 //最大消息监听线程数
消费者类
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class Receiver {
@RabbitListener(queues = "hello.queue1")
public String processMessage1(String msg) {
System.out.println(Thread.currentThread().getName() + " 接收到来自hello.queue1队列的消息:" + msg);
return msg.toUpperCase();
}
@RabbitListener(queues = "hello.queue2")
public void processMessage2(String msg) {
System.out.println(Thread.currentThread().getName() + " 接收到来自hello.queue2队列的消息:" + msg);
}
}
由于定义了2个队列,所以分别定义不同的 * 监听不同的队列。由于最小消息监听线程数和最大消息监听线程数都是2,所以每个 * 各有2个线程实现监听功能。
要点:
1. * 参数类型与消息实际类型匹配。在生产者中发送的消息实际类型是String,所以这里 * 参数类型也是String。
2.如果 * 需要有响应返回给生产者,直接在监听方法中return即可。
运行测试
import java.util.Date;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.sam.demo.rabbitmq.Application;
import com.sam.demo.rabbitmq.sender.Sender;
@RunWith(value=SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class RabbitTests {
@Autowired
private Sender sender;
@Test
public void sendTest() throws Exception {
while(true){
String msg = new Date().toString();
sender.send(msg);
Thread.sleep(1000);
}
}
}
输出:
开始发送消息 : wed mar 29 23:20:52 cst 2017
SimpleAsyncTaskExecutor-1 接收到来自hello.queue2队列的消息:Wed Mar 29 23:20:52 CST 2017
SimpleAsyncTaskExecutor-2 接收到来自hello.queue1队列的消息:Wed Mar 29 23:20:52 CST 2017
结束发送消息 : wed mar 29 23:20:52 cst 2017
消费者响应 : WED MAR 29 23:20:52 CST 2017 消息处理完成
------------------------------------------------
消息发送成功:CorrelationData [id=340d14e6-cfcc-4653-9f95-29b37d50f886]
开始发送消息 : wed mar 29 23:20:53 cst 2017
SimpleAsyncTaskExecutor-1 接收到来自hello.queue1队列的消息:Wed Mar 29 23:20:53 CST 2017
SimpleAsyncTaskExecutor-2 接收到来自hello.queue2队列的消息:Wed Mar 29 23:20:53 CST 2017
结束发送消息 : wed mar 29 23:20:53 cst 2017
消费者响应 : WED MAR 29 23:20:53 CST 2017 消息处理完成
------------------------------------------------
消息发送成功:CorrelationData [id=e4e01f89-d0d4-405e-80f0-85bb20238f34]
开始发送消息 : wed mar 29 23:20:54 cst 2017
SimpleAsyncTaskExecutor-2 接收到来自hello.queue1队列的消息:Wed Mar 29 23:20:54 CST 2017
SimpleAsyncTaskExecutor-1 接收到来自hello.queue2队列的消息:Wed Mar 29 23:20:54 CST 2017
结束发送消息 : wed mar 29 23:20:54 cst 2017
消费者响应 : WED MAR 29 23:20:54 CST 2017 消息处理完成
------------------------------------------------
如果需要使用的其他的交换器类型,spring中都已提供实现,所有的交换器均实现org.springframework.amqp.core.AbstractExchange接口。
常用交换器类型如下:
Direct(DirectExchange):direct 类型的行为是"先匹配, 再投送". 即在绑定时设定一个 routing_key, 消息的routing_key完全匹配时, 才会被交换器投送到绑定的队列中去。
Topic(TopicExchange):按规则转发消息(最灵活)。
Headers(HeadersExchange):设置header attribute参数类型的交换机。
Fanout(FanoutExchange):转发消息到所有绑定队列。
来源:http://www.jianshu.com/p/e1258c004314#


猜你喜欢
- 首先说明:如果没有进入调试模式的话,默认的调试窗口如下: 开始前的准备: 新建控制台程序DebugWindowDemo:修改Program.
- 不得已重新配置,这里记下详细步骤,分享给大家。一、安装jdk,具体步骤如下:1、将jdk-7u4-linux-i586.tar拷贝到linu
- 制作透明窗体办法有好几种,各有优缺点. 我们先来看看C#本身提供的办法 1:通过设置窗体的 TransparencyKey实现 例:窗体中
- 涉及到客户端的系统中经常需要用到比较版本号的功能,但是比较版本号又不能完全按照字符串比较的方式去用compareTo之类的方法;这就需要我们
- 前言假如你做了一个云盘类的app,或者可以保存用户导入的配置。用户在未来肯定需要获取这些文件,一个办法是写一个Activity,向一个文件管
- 一、字符串:1、访问String中的字符:string本身可看作一个Char数组。string s = "hello world&
- 我就废话不多说了,大家还是直接看代码吧~//returnContent为获取到的返回参数System.out.println(returnC
- 前言其实一般的程序猿根本不用了解这么深,只有当你到了一定层次,需要了解jvm内部运行机制,或者高并发多线程下,你写的代码对内存有影响,你想做
- 简介在实现登录功能时,一般为了安全都会设置验证码登录,为了防止某个用户用特定的程序暴力破解方式进行不断的尝试登录。常见验证码分为图片验证码和
- 数字9 出现的次数编写程序数一下 1到 100 的所有整数中出现多少个数字9源码public static int Getnum
- 本文实例讲述了Android显示网络图片的方法,分享给大家供大家参考。具体方法如下:一般来说,在Android中显示一张网络图片其实是非常简
- 最近几天一直在看Hadoop相关的书籍,目前稍微有点感觉,自己就仿照着WordCount程序自己编写了一个统计关联商品。需求描述:根据超市的
- 开发一个需要常住后台的App其实是一件非常头疼的事情,不仅要应对国内各大厂商的ROM,还需要应对各类的安全管家...虽然不断的研究各式各样的
- 一、Struts2文件上传 Struts2的文件上传实现非常简单,只需要简单几步就可完成;注意:(1)文件上传的struts2标签
- 这里简单介绍了一些常用的属性,以及一些术语的解释和举例说明,不太全面,希望读者多多补充。1.重载:函数名相同,参数的个数或参数类型不同; p
- 1、每帧检查定义一个时间变量 timer,每帧将此时间减去帧间隔时间 Time.deltaTime,如果小于或者等于零,说明定时器到了,执行
- 经常会遇到这样的情况,我们在响应客户端请求的数据的时候需要对数据进行处理,比如数据库中的数据是int型,它可能表示某个枚举,或者其它的逻辑意
- 在 Android 中,多数情况下每个程序都是在各自独立的 Linux 进程中运行的。当一个程序或其某些部分被请求时,它的进程就“出生”了;
- 本文章向大家介绍JAVA爬取天天基金网数据,主要包括JAVA爬取天天基金网数据使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参
- 1.Knife4j在线API文档基本使用Knife4j是一款基于Swagger 2的在线API文档框架。使用Knife4j的基础步骤:添加依