安装RabbitMQ
在linux上安装RabbitMQ
,并运行
docker run \
-e RABBITMQ_DEFAULT_USER=zywzy \
-e RABBITMQ_DEFAULT_PASS=123321 \
--name mq \
--hostname mq1 \
-p 15672:15672 \
-p 5672:5672 \
-d \
rabbitmq:3-management
http://ip:15672
访问控制台, 用户名zywzy,密码123321
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
配置文件
spring:
rabbitmq:
host: 172.27.99.52 # rabbitMQ的ip地址
port: 5672 # 端口
username: abc
password: 123321
virtual-host: /
发送消息
@SpringBootTest
public class SpringAmqpTest {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
public void testSendMessage2SimpleQueue() {
String queueName = "simple.queue";
String message = "hello, spring amqp!";
rabbitTemplate.convertAndSend(queueName, message);
}
}
消费消息
@RabbitListener(queues = "simple.queue")
public void listenWorkQueue1(String msg) throws InterruptedException {
System.out.println("消费者1接收到消息:【" + msg + "】" + LocalTime.now());
}
消息预取
- 每次只能取一条消息,处理完成才能取下一条消息
spring:
rabbitmq:
listener:
simple:
prefetch: 1
常见exchange类型
- Fanout: 广播
- Direct: 路由
- Topic: 话题
Fanout Exchange
- 绑定队列和交换机
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FanoutConfig {
@Bean
public FanoutExchange fanoutExchange(){
return new FanoutExchange("itcast.fanout");
}
@Bean
public Queue fanoutQueue1(){
return new Queue("fanout.queue1");
}
/**
* 绑定队列1到交换机
*/
@Bean
public Binding fanoutBinding1(Queue fanoutQueue1, FanoutExchange fanoutExchange){
return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
}
@Bean
public Queue fanoutQueue2(){
return new Queue("fanout.queue2");
}
/**
* 绑定队列2到交换机
*/
@Bean
public Binding fanoutBinding2(Queue fanoutQueue2, FanoutExchange fanoutExchange){
return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
}
}
- 监听队列1和队列2
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class MyRabbitListener {
@RabbitListener(queues = "fanout.queue1")
public void listenFanoutQueue1(String msg){
System.out.println("消费者接收到fanout.queue1的消息: {" + msg + "}");
}
@RabbitListener(queues = "fanout.queue2")
public void listenFanoutQueue2(String msg){
System.out.println("消费者接收到fanout.queue2的消息: {" + msg + "}");
}
}
- 发布消息
@Test
void name() {
String exchangeName = "itcast.fanout";
String message = "hello , everyone!";
rabbitTemplate.convertAndSend(exchangeName, "", message);
}
- 运行结果
缺点:
不能缓存消息, 路由失败, 消息丢失
Direct Exchange
- 绑定
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class MyRabbitListener {
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct.queue1"),
exchange = @Exchange(name = "zhouyu.direct", type = ExchangeTypes.DIRECT),
key = {"red", "blue"}))
public void listenDirectQueue1(String msg){
System.out.println("消费者1接收到direct的消息: [" + msg + "]");
}
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "direct.queue2"),
exchange = @Exchange(name = "zhouyu.direct", type = ExchangeTypes.DIRECT),
key = {"red", "yellow"}))
public void listenDirectQueue2(String msg){
System.out.println("消费者2接收到direct的消息: [" + msg + "]");
}
}
- 发布消息
@Test
void name() {
String exchangeName = "zhouyu.direct";
String message = "hello red";
rabbitTemplate.convertAndSend(exchangeName, "red", message);
}
Topic Exchange
- 绑定
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class MyRabbitListener {
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic.queue1"),
exchange = @Exchange(name = "zhouyu.topic", type = ExchangeTypes.TOPIC),
key = "china.#"))
public void listenTopicQueue1(String msg){
System.out.println("消费者1接收到topic1的消息: [" + msg + "]");
}
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "topic.queue2"),
exchange = @Exchange(name = "zhouyu.topic", type = ExchangeTypes.TOPIC),
key = "#.news"))
public void listenTopicQueue2(String msg){
System.out.println("消费者2接收到topic2的消息: [" + msg + "]");
}
}
- 发布消息
@Test
void name() {
String exchangeName = "zhouyu.topic";
String message = "china.weather";
rabbitTemplate.convertAndSend(exchangeName, "china.weather", message);
}
基于bean实现topic
- MqConstants.java
public class MqConstants {
public static final String HOTEL_EXCHANGE = "hotel.topic";
public static final String HOTEL_INSERT_QUEUE = "hotel.insert.queue";
public static final String HOTEL_DELETE_QUEUE = "hotel.delete.queue";
public static final String HOTEL_INSERT_KEY = "hotel.insert.key";
public static final String HOTEL_DELETE_KEY = "hotel.delete.key";
}
- MqConfig.java
import cn.zyw.MqConstants;
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 MqConfig {
@Bean
public TopicExchange topicExchange(){
return new TopicExchange(MqConstants.HOTEL_EXCHANGE, true, false);
}
@Bean
public Queue insertQueue(){
return new Queue(MqConstants.HOTEL_INSERT_QUEUE, true);
}
@Bean
public Queue deleteQueue(){
return new Queue(MqConstants.HOTEL_DELETE_QUEUE, true);
}
@Bean
public Binding insertQueueBinding(){
return BindingBuilder.bind(insertQueue()).to(topicExchange()).with(MqConstants.HOTEL_INSERT_KEY);
}
@Bean
public Binding deleteQueueBinding(){
return BindingBuilder.bind(deleteQueue()).to(topicExchange()).with(MqConstants.HOTEL_DELETE_KEY);
}
}
- HotelListener.java
import cn.zyw.MqConstants;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class HotelListener {
@RabbitListener(queues = MqConstants.HOTEL_INSERT_QUEUE)
public void listenHotelInsertOrUpdate(Long id){
// TODO 根据id查询数据库更新缓存
System.out.println("监听到数据更新" + id);
}
@RabbitListener(queues = MqConstants.HOTEL_DELETE_QUEUE)
public void listenHotelDelete(Long id){
// TODO 根据id删除缓存
System.out.println("监听到数据删除" + id);
}
}
消息转换器
- 依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
- 声明MessageConverter
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class);
}
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
}