1、简介
RabbitMQ 是一个由 Erlang 语言开发的 AMQP 的开源实现。
AMQP :Advanced Message Queue,高级消息队列协议。它是应用层协议的一个开放标准,为面向消息的中间件设计,基于此协议的客户端与消息中间件可传递消息,并不受产品、开发语言等条件的限制。
RabbitMQ 最初起源于金融系统,用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。
2、RabbitMQ整体结构图
2.1、队列Queue
Queue(队列)RabbitMQ的作用是存储消息,队列的特性是先进先出。
2.2、交换机Exchange
exchange的作用就是类似路由器,routing key 就是路由键,服务器会根据路由键将消息从交换器路由到队列上去。
exchange有多个种类:direct,fanout,topic,header。
-
direct: 1:1类似完全匹配
-
fanout1:N 可以把一个消息并行发布到多个队列上去,简单的说就是,当多个队列绑定到fanout的交换器,那么交换器一次性拷贝多个消息分别发送到绑定的队列上,每个队列有这个消息的副本。
-
topic N:1 ,多个交换器可以路由消息到同一个队列。根据模糊匹配,比如一个队列的routing key 为*.test ,那么凡是到达交换器的消息中的routing key 后缀.test都被路由到这个队列上。
3、DirectExchange消费示例
3.0、pom增加rabbitmq的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
3.1、application.properties增加rabbitmq的配置
####################RabbitMQ相关配置#################
spring.rabbitmq.host=192.168.10.177
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=123456
spring.rabbitmq.virtual-host=/
spring.rabbitmq.publisher-confirms=true
spring.rabbitmq.connection-timeout=60000
####################RabbitMQ相关配置#################
3.2、消息队列配置
package com.vesus.springbootrabbitmq.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Description: 消息队列配置
* Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
* Queue:消息的载体,每个消息都会被投到一个或多个队列。
* Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来.
* Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
* vhost:虚拟主机,一个broker里可以有多个vhost,用作不同用户的权限分离。
* Producer:消息生产者,就是投递消息的程序.
* Consumer:消息消费者,就是接受消息的程序.
* Channel:消息通道,在客户端的每个连接里,可建立多个channel.
* @Author: vesus
* @CreateDate: 2018/11/26 上午11:48
* @Version: 1.0
*/
@Configuration
public class RabbitConfig {
//定义任务消息交换
public static final String JOB_EXCHANGE="job-exchange" ;
//定义任务消息队列
public static final String JOB_QUEUE="job-queue" ;
//定义路由key
public static final String JOB_ROUTEKEY="job-routekey";
/**
* 设置交换机
* @return
*/
@Bean
public DirectExchange directExchange(){
return new DirectExchange(JOB_EXCHANGE);
}
/**
* 设置队列
* @return
*/
@Bean
public Queue queue(){
return new Queue(JOB_QUEUE,true);
}
/**
* 将队列和路由做绑定,支持绑定多个队列
* @return
*/
@Bean
public Binding binding(){
return BindingBuilder.bind(queue()).to(directExchange()).with(JOB_ROUTEKEY);
}
}
3.3、定义任务消息服务类
package com.vesus.springbootrabbitmq.service;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
/**
* @Description: 定义任务消息服务类
* @Author: vesus
* @CreateDate: 2018/11/26 下午3:59
* @Version: 1.0
*/
public interface JobMessageService extends RabbitTemplate.ConfirmCallback {
/**
* 发送消息到rabbitmq消息队列
* @param message 消息体
*/
public void sendMsg(String message);
}
3.4、定义消息生产者
package com.vesus.springbootrabbitmq.producer;
import com.vesus.springbootrabbitmq.config.RabbitConfig;
import com.vesus.springbootrabbitmq.service.JobMessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.UUID;
/**
* @Description: 定义消息生产者
* @Author: vesus
* @CreateDate: 2018/11/26 下午2:29
* @Version: 1.0
*/
@Component
public class JobProducer implements JobMessageService {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private RabbitTemplate rabbitTemplate ;
/**
* 发送消息到消息队列
* @param message 消息体
*/
public void sendMsg(String message){
//设置回调为当前类对象
rabbitTemplate.setConfirmCallback(this);
//构建回调id为uuid
CorrelationData correlationId = new CorrelationData(UUID.randomUUID().toString());
//发送消息到消息队列
rabbitTemplate.convertAndSend(RabbitConfig.JOB_EXCHANGE,RabbitConfig.JOB_ROUTEKEY,message,correlationId);
}
/**
* 消息回调确认方法
* @param correlationData 消息回调对象
* @param ack 是否发送成功
* @param cause 错误信息
*/
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
logger.info(" 回调id:" + correlationData.getId());
if (ack) {
logger.info("消息成功消费");
} else {
logger.info("消息消费失败:" + cause);
}
}
}
3.5、定义消息消费者
package com.vesus.springbootrabbitmq.consumer;
import com.vesus.springbootrabbitmq.config.RabbitConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @Description: 定义消息消费者
* @Author: vesus
* @CreateDate: 2018/11/26 下午3:08
* @Version: 1.0
*/
@Component
@RabbitListener(queues = RabbitConfig.JOB_QUEUE)
public class JobReceiver {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@RabbitHandler
public void process(String content){
logger.info("接收处理队列A当中的消息: " + content);
try {
logger.info("处理消息=============");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("处理结束=============");
}
}
3.6、测试
package com.vesus.springbootrabbitmq;
import com.vesus.springbootrabbitmq.producer.JobProducer;
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.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootRabbitmqApplicationTests {
@Autowired
JobProducer jobProducer ;
@Test
public void sendMsg() {
for (int i = 0; i <100 ; i++) {
jobProducer.sendMsg("cesh"+i);
}
}
}
2018-11-26 16:37:24.874 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 接收处理队列A当中的消息: cesh94
2018-11-26 16:37:24.874 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 处理消息=============
2018-11-26 16:37:26.876 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 处理结束=============
2018-11-26 16:37:26.878 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 接收处理队列A当中的消息: cesh95
2018-11-26 16:37:26.878 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 处理消息=============
2018-11-26 16:37:28.881 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 处理结束=============
2018-11-26 16:37:28.883 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 接收处理队列A当中的消息: cesh96
2018-11-26 16:37:28.884 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 处理消息=============
2018-11-26 16:37:30.886 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 处理结束=============
2018-11-26 16:37:30.888 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 接收处理队列A当中的消息: cesh97
2018-11-26 16:37:30.888 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 处理消息=============
2018-11-26 16:37:32.890 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 处理结束=============
2018-11-26 16:37:32.892 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 接收处理队列A当中的消息: cesh98
2018-11-26 16:37:32.892 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 处理消息=============
2018-11-26 16:37:34.896 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 处理结束=============
2018-11-26 16:37:34.898 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 接收处理队列A当中的消息: cesh99
2018-11-26 16:37:34.898 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 处理消息=============
2018-11-26 16:37:36.902 INFO 10948 --- [cTaskExecutor-1] c.v.s.consumer.JobReceiver : 处理结束=============