利用SpringAMQP依赖使用RabbitMQ
不通过交换机情况下使用
消息消费端和提供端需要引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
都需要在application.yml进行如下配置
spring:
rabbitmq:
host: 192.168.230.100 #rabbitMQ的主机名
port: 5672 #rabbitMQ的消息通信端口
username: cyk #用户名
password: 123 #密码
virtual-host: / #虚拟主机(请确保消息发布端和消费端的连接参数一致,账户拥有该虚拟主机的使用权)
listener:
simple:
prefetch: 1 #这条只需要消费端配置,用于限制每次拿取的信息条数,处理完才能再次拿取
消息提供端
package com.cyk.publisher;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class PublisherApplicationTests {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
//如果不想在管理端手动创建队列,也可以使用下列注解自动创建队列,不过奇怪的是,这条注解运行后会导致有好多重复消息,慎用吧
@RabbitListener(queuesToDeclare = {@Queue("simple.queue")})
void contextLoads() {
String QueueName = "simple.queue"; //队列名字(请确该队列存在)
String message = "hello,spring amqp!"; //需要发送的消息
rabbitTemplate.convertAndSend(QueueName,message);
}
}
消息消费端
package com.cyk.consumer.listener;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class SpringRabbitLIstener {
@RabbitListener(queues = "simple.queue")
void contextLoads(String msg) {
System.out.println("接收到消息:"+msg);
}
}
通过交换机情况下使用
交换机有三种,Fanout(广播),Direct(路由),Topic(话题)
Fanout
fanout就是一个最单纯的具有发布功能的交换机,可以发布给所有与其绑定的消息队列
在配置类进行配置,创建交换机和消息队列,并进行绑定
package com.cyk.consumer.config;
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("cyk.fanout"); //创建一个名为cyk.fanout的交换机
}
@Bean //会根据下列方法名,创建一个消息队列
public Queue fanoutQueue1(){
return new Queue("fanout.queue1"); //创建一个名为fanout.queue1的交换机
}
@Bean
public Queue fanoutQueue2(){
return new Queue("fanout.queue2");
}
@Bean
//将需要的交换机和消息队列进行绑定(fanoutQueue1,fanoutExchange必须与上述方法名一样)
public Binding fanoutBinding1(Queue fanoutQueue1,FanoutExchange fanoutExchange){
return BindingBuilder.bind(fanoutQueue1).to(fanoutExchange);
}
@Bean
public Binding fanoutBinding2(Queue fanoutQueue2,FanoutExchange fanoutExchange){
return BindingBuilder.bind(fanoutQueue2).to(fanoutExchange);
}
}
消息提供端
package com.cyk.publisher;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class PublisherApplicationTests {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
void contextLoads() {
String ExangeName = "cyk.fanout";
String message = "hello,spring amqp!";
for (int i=1;i<=1;i++){
System.out.println(message+i);
rabbitTemplate.convertAndSend(ExangeName,"",message+i);
}
}
}
消息消费端
package com.cyk.consumer.listener;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class SpringRabbitLIstener {
@RabbitListener(queues = "fanout.queue1")
void ListenFanoutQueue1(String msg) throws InterruptedException {
System.out.println("1号接收到消息:"+msg);
}
@RabbitListener(queues = "fanout.queue2")
void ListenFanoutQueue2(String msg) throws InterruptedException {
System.out.println("2号接收到消息:"+msg);
}
}
Direct
Direct会根据交换机收到的消息中,携带的key值来判断消息的发送,只有绑定该交换机的消息队列中,具有相同key值的消息队列才会收到消息
消息提供端
package com.cyk.publisher;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class PublisherApplicationTests {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
void contextLoads() {
String ExangeName = "cyk.direct";
String message = "hello,spring amqp!";
for (int i=1;i<=1;i++){
System.out.println(message+i);
rabbitTemplate.convertAndSend(ExangeName,"red",message+i);
}
}
}
消息消费端
package com.cyk.consumer.listener;
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 SpringRabbitLIstener {
//使用@RabbitListener+@QueueBinding配合,就无需像上述使用fanout交换机时一样,在配置类中一个个设置Bean,来创建交换机和消息队列
@RabbitListener(bindings = @QueueBinding(
value = @Queue("direct.queue1"),
exchange = @Exchange(name = "cyk.direct",type = ExchangeTypes.DIRECT),
key = {"red","blue"}))
void ListenDirectQueue1(String msg) throws InterruptedException {
System.out.println("blue队列接收到消息:"+msg);
}
@RabbitListener(bindings = @QueueBinding(
value = @Queue("direct.queue2"),
exchange = @Exchange(name = "cyk.direct",type = ExchangeTypes.DIRECT),
key = {"red","yellow"}))
void ListenDirectQueue2(String msg) throws InterruptedException {
System.out.println("yellow队列接收到消息:"+msg);
}
}
Topic
topic和direct交换机几乎一样,不过topic的key名是*.*的形式,还可以用#和*来代替字符,#代表0或多个单词,*代表一个单词
消息提供端
package com.cyk.publisher;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class PublisherApplicationTests {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
void contextLoads() {
String ExangeName = "cyk.topic";
String message = "hello,spring amqp!";
for (int i=1;i<=1;i++){
System.out.println(message+i);
rabbitTemplate.convertAndSend(ExangeName,"china.news",message+i);
}
}
}
消息消费端
package com.cyk.consumer.listener;
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 SpringRabbitLIstener {
@RabbitListener(bindings = @QueueBinding(
value = @Queue("topic.queue1"),
exchange = @Exchange(name = "cyk.topic",type = ExchangeTypes.TOPIC),
key = "china.#"))
void ListenTopicQueue1(String msg) throws InterruptedException {
System.out.println("china队列接收到消息:"+msg);
}
@RabbitListener(bindings = @QueueBinding(
value = @Queue("topic.queue2"),
exchange = @Exchange(name = "cyk.topic",type = ExchangeTypes.TOPIC),
key = "#.news"))
void ListenTopicQueue2(String msg) throws InterruptedException {
System.out.println("news队列接收到消息:"+msg);
}
}
消息转换器
在SpringAMQP中,消息不一定要是字符串,可以用任意类型进行传递,SpringAMQP会自动帮我们将消息进行序列化传递,但SpringAMQP是基于objectOutputStream来实现的序列化,性能和安全性都不高。我们可以采用JSON序列化方式来提高效率
引入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
在配置类中声明Bean,来覆盖默认Bean
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
//这里是我懒得写类了,并不是配置类可以这样写
@Bean
public MessageConverter messageConverter(){
return new Jackson2JsonMessageConverter();
}
直接向消息队列发送消息(接收时候注意类型一致)
package com.cyk.publisher;
import org.junit.jupiter.api.Test;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.HashMap;
import java.util.Map;
@SpringBootTest
class PublisherApplicationTests {
@Autowired
private RabbitTemplate rabbitTemplate;
@Test
void contextLoads() {
Map<String,Object> msg=new HashMap<>();
msg.put("name","牛马");
msg.put("age",11);
rabbitTemplate.convertAndSend("object.queue",msg);
}
}