详解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#

标签:spring,boot
0
投稿

猜你喜欢

  • SpringMVC HttpMessageConverter消息转换器

    2023-01-13 04:57:45
  • Android异步回调中的UI同步性问题分析

    2022-07-31 14:10:51
  • 完美解决Android App启动页有白屏闪过的问题

    2021-11-18 02:12:31
  • 基于C#实现FTP下载文件

    2021-07-09 20:10:01
  • opencv配置的完整步骤(win10+VS2015+OpenCV3.1.0)

    2023-06-28 14:55:19
  • 详解spring boot配置单点登录

    2022-07-27 11:50:11
  • elasticsearch数据信息索引操作action support示例分析

    2022-03-18 02:09:07
  • Java Spring的使用注解开发详解

    2023-04-27 03:00:40
  • Java毕业设计实战之二手书商城系统的实现

    2022-03-21 14:06:20
  • JavaMail实现带附件的邮件发送

    2021-10-21 15:00:09
  • Springboot引用外部配置文件的方法步骤

    2022-06-14 13:29:35
  • 深入探讨JAVA中的异常与错误处理

    2023-06-11 00:30:24
  • Android开发实现webview中img标签加载本地图片的方法

    2023-03-15 01:33:40
  • spring boot 配置动态刷新详解

    2023-09-26 10:24:42
  • Android简单实现菜单拖拽排序的功能

    2023-03-10 22:32:31
  • Android中生成、使用Json数据实例

    2023-02-04 15:01:24
  • C#设计模式之ChainOfResponsibility职责链模式解决真假美猴王问题实例

    2023-04-01 00:39:00
  • C#实现XML文件操作详解

    2023-07-16 12:36:52
  • Maven聚合开发实例详解

    2023-07-14 11:18:12
  • Android中Uri和Path之间的转换的示例代码

    2022-01-25 10:22:48
  • asp之家 软件编程 m.aspxhome.com