RabbitMQ(二)Spring Boot集成
Spring Boot
集成RabbitMQ
非常简单,如果只是简单的使用配置非常少,Spring Boot
提供了spring-boot-starter-amqp
项目对消息各种支持。
简单使用
1、配置pom包
主要是添加spring-boot-starter-amqp
的支持
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
2、配置文件
配置rabbitmq
的安装地址、端口以及账户信息
spring.application.name=rabbitmq
server.port=8080
spring.rabbitmq.host=192.168.3.253
spring.rabbitmq.port=5672
spring.rabbitmq.username=admin
spring.rabbitmq.password=123456
3、队列配置
package com.lay.rabbitmq.queue.config;
/**
* @Description:
* @Author: lay
* @Date: Created in 18:36 2018/12/18
* @Modified By:IntelliJ IDEA
*/
@Configuration
public class RabbitConfig {
@Bean
public Queue queue(){
return new Queue("hello");
}
}
4、发送者
AmqpTemplate
是springboot
提供的默认实现,RabbitTemplate
是对AmqpTemplate
的又一次封装(两者都可以实现发送的基本功能,这里使用前者)。
package com.lay.rabbitmq.queue.sender;
/**
* @Description:
* @Author: lay
* @Date: Created in 18:50 2018/12/18
* @Modified By:IntelliJ IDEA
*/
@Component
public class HelloSender {
@Autowired
private AmqpTemplate rabbitTemplate;
public void send(){
String context="hello"+new Date();
System.out.println("Sender:"+context);
rabbitTemplate.convertAndSend("hello",context);
}
public void send(int i){
String context="Spring boot queue *****"+i;
//System.out.println("Sender:"+context);
rabbitTemplate.convertAndSend("hello",context);
}
}
5、接收者
package com.lay.rabbitmq.queue.receiver;
/**
* @Description:
* @Author: lay
* @Date: Created in 18:54 2018/12/18
* @Modified By:IntelliJ IDEA
*/
@Component
@RabbitListener(queues = "hello")
public class HelloReceiver {
@RabbitHandler
public void process(String hello){
System.out.println("Receiver1 : " + hello);
}
}
6、测试
package com.lay.rabbitmq;
/**
* @Description:
* @Author: lay
* @Date: Created in 18:57 2018/12/18
* @Modified By:IntelliJ IDEA
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class RabbitMqHelloTest {
@Autowired
private HelloSender helloSender;
@Test
public void hello() throws Exception{
helloSender.send();
}
}
注意,发送者和接收者的queue name必须一致,不然不能接收
多对多使用
一个发送者,N个接收者或者N个发送者和N个接收者会出现什么情况呢?
一对多发送
对上面的代码进行了小改造,接收端注册了两个Receiver,Receiver1和Receiver2,发送端加入参数计数,接收端打印接收到的参数,下面是测试代码,发送一百条消息,来观察两个接收端的执行效果
@Test
public void oneToMany() throws Exception {
for (int i=0;i<100;i++){
helloSender.send(i);
}
}
结果如下:
Receiver 1: Spring boot neo queue ****** 11
Receiver 2: Spring boot neo queue ****** 12
Receiver 2: Spring boot neo queue ****** 14
Receiver 1: Spring boot neo queue ****** 13
Receiver 2: Spring boot neo queue ****** 15
Receiver 1: Spring boot neo queue ****** 16
Receiver 1: Spring boot neo queue ****** 18
Receiver 2: Spring boot neo queue ****** 17
Receiver 2: Spring boot neo queue ****** 19
Receiver 1: Spring boot neo queue ****** 20
根据返回结果得到以下结论
一个发送者,N个接受者,经过测试会均匀的将消息发送到N个接收者中
多对多发送
复制了一份发送者,加入标记,在一百个循环中相互交替发送
@Test
public void manyToMany() throws Exception {
for (int i=0;i<100;i++){
helloSender.send(i);
helloSender2.send(i);
}
}
结果如下:
Receiver 1: Spring boot neo queue ****** 20
Receiver 2: Spring boot neo queue ****** 20
Receiver 1: Spring boot neo queue ****** 21
Receiver 2: Spring boot neo queue ****** 21
Receiver 1: Spring boot neo queue ****** 22
Receiver 2: Spring boot neo queue ****** 22
Receiver 1: Spring boot neo queue ****** 23
Receiver 2: Spring boot neo queue ****** 23
Receiver 1: Spring boot neo queue ****** 24
Receiver 2: Spring boot neo queue ****** 24
Receiver 1: Spring boot neo queue ****** 25
Receiver 2: Spring boot neo queue ****** 25
结论:和一对多一样,接收端仍然会均匀接收到消息
高级使用
对象的支持
springboot以及完美的支持对象的发送和接收,不需要格外的配置。
先定义一个用户对象User
package com.lay.rabbitmq.object.entity;
/**
* @Description:
* @Author: lay
* @Date: Created in 19:17 2018/12/18
* @Modified By:IntelliJ IDEA
*/
public class User implements Serializable {
private static final long serialVersionUID = 426370694438321946L;
private Long id;
private String userName;
private String sex;
private Integer age;
public static long getSerialVersionUID() {
return serialVersionUID;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", userName='" + userName + '\'' +
", sex='" + sex + '\'' +
", age=" + age +
'}';
}
}
配置队列:
package com.lay.rabbitmq.object.config;
/**
* @Description:
* @Author: lay
* @Date: Created in 18:36 2018/12/18
* @Modified By:IntelliJ IDEA
*/
@Configuration
public class RabbitObjectConfig {
@Bean
public Queue userQueue(){
return new Queue("user");
}
}
发送者:
package com.lay.rabbitmq.object.sender;
/**
* @Description:
* @Author: lay
* @Date: Created in 19:23 2018/12/18
* @Modified By:IntelliJ IDEA
*/
@Component
public class UserSender {
@Autowired
private AmqpTemplate rabbitTemplate;
public void send(User user){
System.out.println("Sender User: "+user.toString());
rabbitTemplate.convertAndSend("user",user);
try {
Thread.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
接收者:
package com.lay.rabbitmq.object.receiver;
/**
* @Description:
* @Author: lay
* @Date: Created in 19:25 2018/12/18
* @Modified By:IntelliJ IDEA
*/
@Component
@RabbitListener(queues = "user")
public class UserReceiver {
@RabbitHandler
public void process(User user) {
System.out.println("UserReceiver : " + user.toString());
}
}
Topic Exchange
topic
是RabbitMQ
中最灵活的一种方式,可以根据routing_key
自由的绑定不同的队列
首先对topic
规则配置,这里使用两个队列来测试
队列和交换机配置
package com.lay.rabbitmq.topic.config;
/**
* @Description:
* @Author: lay
* @Date: Created in 18:36 2018/12/18
* @Modified By:IntelliJ IDEA
*/
@Configuration
public class TopicRabbitConfig {
public final static String message = "topic.message";
public final static String messages = "topic.messages";
@Bean
public Queue queueMessage(){
return new Queue(TopicRabbitConfig.message);
}
@Bean
public Queue queueMessages(){
return new Queue(TopicRabbitConfig.messages);
}
@Bean
public TopicExchange exchange(){
return new TopicExchange("topicExchange");
}
@Bean
public Binding bindExchangeMessage(Queue queueMessage,TopicExchange exchange){
return BindingBuilder.bind(queueMessage).to(exchange).with("topic.message");
}
@Bean
public Binding bindExchangeMessages(Queue queueMessages,TopicExchange exchange){
return BindingBuilder.bind(queueMessages).to(exchange).with("topic.#");
}
}
使用queueMessages同时匹配两个队列,queueMessage只匹配”topic.message”队列
生产者:
package com.lay.rabbitmq.topic.sender;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @Description:
* @Author: lay
* @Date: Created in 19:46 2018/12/18
* @Modified By:IntelliJ IDEA
*/
@Component
public class TopicSender {
@Autowired
private AmqpTemplate rabbitTemplate;
public void send1(){
String conText="this is message 1";
System.out.println("Sender: "+conText);
rabbitTemplate.convertAndSend("topicExchange","topic.message",conText);
}
public void send2(){
String conText="this is messages 2";
System.out.println("Sender: "+conText);
rabbitTemplate.convertAndSend("topicExchange","topic.messages",conText);
}
}
发送send1会匹配到topic.#和topic.message 两个Receiver都可以收到消息,发送send2只有topic.#可以匹配所有只有Receiver2监听到消息
消费者1:
package com.lay.rabbitmq.topic.receiver;
/**
* @Description:
* @Author: lay
* @Date: Created in 19:49 2018/12/18
* @Modified By:IntelliJ IDEA
*/
@Component
@RabbitListener(queues = TopicRabbitConfig.message)
public class TopicReceiver1 {
@RabbitHandler
public void process(String context){
System.out.println("TopicReceiver 1: "+context);
}
}
消费者2:
package com.lay.rabbitmq.topic.receiver;
/**
* @Description:
* @Author: lay
* @Date: Created in 19:49 2018/12/18
* @Modified By:IntelliJ IDEA
*/
@Component
@RabbitListener(queues = TopicRabbitConfig.messages)
public class TopicReceiver2 {
@RabbitHandler
public void process(String context){
System.out.println("TopicReceiver 2: "+context);
}
}
Fanout Exchange
Fanout
就是我们熟悉的广播模式或者订阅模式,给Fanout
交换机发送消息,绑定了这个交换机的所有队列都收到这个消息。
Fanout 相关配置
package com.lay.rabbitmq.fanout.config;
/**
* @Description:
* @Author: lay
* @Date: Created in 10:13 2018/12/20
* @Modified By:IntelliJ IDEA
*/
@Configuration
public class FanoutRabbitConfig {
public static final String QUEUE_A = "fanout.A";
public static final String QUEUE_B = "fanout.B";
public static final String QUEUE_C = "fanout.C";
public static final String FANOUT_EXCHANGE = "fanoutExchange";
@Bean
public Queue AMessage() {
return new Queue(QUEUE_A);
}
@Bean
public Queue BMessage() {
return new Queue(QUEUE_B);
}
@Bean
public Queue CMessage() {
return new Queue(QUEUE_C);
}
@Bean
FanoutExchange fanoutExchange() {
return new FanoutExchange(FANOUT_EXCHANGE);
}
@Bean
Binding bindingExchangeA(Queue AMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(AMessage).to(fanoutExchange);
}
@Bean
Binding bindingExchangeB(Queue BMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(BMessage).to(fanoutExchange);
}
@Bean
Binding bindingExchangeC(Queue CMessage, FanoutExchange fanoutExchange) {
return BindingBuilder.bind(CMessage).to(fanoutExchange);
}
}
这里使用了A、B、C三个队列绑定到Fanout交换机上面,发送端的routing_key写任何字符都会被忽略:
生产者:
package com.lay.rabbitmq.fanout.sender;
/**
* @Description:
* @Author: lay
* @Date: Created in 13:42 2018/12/19
* @Modified By:IntelliJ IDEA
*/
@Component
public class FanoutSender {
@Autowired
@Lazy
RabbitTemplate rabbitTemplate;
public void send(){
String context="this is a fanout message";
System.out.println("Sender"+context);
rabbitTemplate.convertAndSend(FanoutRabbitConfig.FANOUT_EXCHANGE,"",context);
}
}
消费者A:
package com.lay.rabbitmq.fanout.receiver;
import com.lay.rabbitmq.fanout.config.FanoutRabbitConfig;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @Description:
* @Author: lay
* @Date: Created in 13:44 2018/12/19
* @Modified By:IntelliJ IDEA
*/
@Component
public class FanoutReceiverA {
@RabbitListener(queues = FanoutRabbitConfig.QUEUE_A)
public void process(String context){
System.out.println("ReceiverA: "+context);
}
@RabbitListener(queues = FanoutRabbitConfig.QUEUE_A)
public void process2(String context){
System.out.println("ReceiverD: "+context);
}
}
消费者B:
package com.lay.rabbitmq.fanout.receiver;
import com.lay.rabbitmq.fanout.config.FanoutRabbitConfig;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @Description:
* @Author: lay
* @Date: Created in 13:49 2018/12/19
* @Modified By:IntelliJ IDEA
*/
@Component
@RabbitListener(queues = FanoutRabbitConfig.QUEUE_B)
public class FanoutReceiverB {
@RabbitHandler
public void process(String context){
//System.out.println("ReceiverB: "+context);
}
}
消费者C:
package com.lay.rabbitmq.fanout.receiver;
import com.lay.rabbitmq.fanout.config.FanoutRabbitConfig;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @Description:
* @Author: lay
* @Date: Created in 13:50 2018/12/19
* @Modified By:IntelliJ IDEA
*/
@Component
@RabbitListener(queues = FanoutRabbitConfig.QUEUE_C)
public class FanoutReceiverC {
@RabbitHandler
public void process(String context){
//System.out.println("ReceiverC: "+context);
}
}
结果绑定到fanout交换机上面的队列都收到了消息