生产者发送消息到交换机并指定一个路由key,消费者队列绑定到交换机时要指定路由key(key匹配就能接受消息,key不匹配就不能接受消息)
比如我们把用户注册的信息通过短信验证码发给用户,只把 key 为 register 的发到 SMS 队列,如果系统报错了,就把错误信息发给邮件队列,方便开发者及时收到消息。这样就很好的控制了不同的队列接收不同的消息了。
整体代码结构如下:
bootstrap.yml 配置如下:
spring:
rabbitmq:
#主机名
host: 127.0.0.1
#端口号
port: 5672
#账号
username: guest
#密码
password: guest
#虚拟主机,这里配置的是我们的测试主机
virtual-host: /test_host
# 自定义配置信息
queueConfig:
# 邮件队列名
emailQueue: directEmailQueue
# 短信队列名
SMSQueue: directSMSQueue
# 交换机名称
directExchangeName: directExchangeName
# info 路由
infoRoute: infoRoute
# error 路由
errorRoute: errorRoute
server:
port: 8080
# 将SpringBoot项目作为单实例部署调试时,不需要注册到注册中心
eureka:
client:
fetch-registry: false
register-with-eureka: false
配置类 QueueConfig 代码如下(直接为队列绑定路由):
package com.study.config;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.Connection;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author biandan
* @description
* @signature 让天下没有难写的代码
* @create 2021-04-05 上午 12:39
*/
@Configuration
public class QueueConfig {
@Value("${spring.rabbitmq.host}")
private String host;
@Value("${spring.rabbitmq.port}")
private Integer port;
@Value("${spring.rabbitmq.username}")
private String username;
@Value("${spring.rabbitmq.password}")
private String password;
@Value("${spring.rabbitmq.virtual-host}")
private String virtualHost;
//邮件队列名
@Value("${queueConfig.emailQueue}")
private String emailQueue;
//短信队列名
@Value("${queueConfig.SMSQueue}")
private String SMSQueue;
//扇形交换机名称
@Value("${queueConfig.directExchangeName}")
private String directExchangeName;
//info 路由
@Value("${queueConfig.infoRoute}")
private String infoRoute;
//error 路由
@Value("${queueConfig.errorRoute}")
private String errorRoute;
/**
* 封装连接类
*
* @return
*/
@Bean
public CachingConnectionFactory connectionFactory() {
CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
connectionFactory.setHost(host);
connectionFactory.setPort(port);
connectionFactory.setUsername(username);
connectionFactory.setPassword(password);
connectionFactory.setVirtualHost(virtualHost);
return connectionFactory;
}
/**
* 动态的创建队列(这里仅创建配置文件里的一个)
*
* @return
* @throws Exception
*/
@Bean
public String getQueueName() throws Exception {
//获取连接
Connection connection = connectionFactory().createConnection();
//创建通道。true表示有事务功能
Channel channel = connection.createChannel(true);
/*
创建队列声明,参数说明:
1.队列名queue
2.是否持久化durable。是否持久化, 队列的声明默认是存放到内存中的,
如果rabbitmq重启会丢失,如果想重启之后还存在就要使队列持久化,
保存到Erlang自带的Mnesia数据库中,当rabbitmq重启之后会读取该数据库
3.是否排外exclusive。有两个作用,一:当连接关闭时connection.close()该队列是否会自动删除;二:该队列是否是私有的private,
如果不是排外的,可以使用两个消费者都访问同一个队列,没有任何问题,
如果是排外的,会对当前队列加锁,其他通道channel是不能访问的,如果强制访问会报异常。
一般等于true的话用于一个队列只能有一个消费者来消费的场景
4.是否自动删除autoDelete。当最后一个消费者断开连接之后队列是否自动被删除,
可以通过RabbitMQ Management,查看某个队列的消费者数量,当consumers = 0时队列就会自动删除
5.其它参数 Map<String, Object> arguments
*/
channel.queueDeclare(emailQueue, true, false, false, null);//创建邮件队列
channel.queueDeclare(SMSQueue, true, false, false, null);//创建短信队列
//创建扇形的交换机
channel.exchangeDeclare(directExchangeName, BuiltinExchangeType.DIRECT, true, false, null);
//为短信队列绑定 info 路由
channel.queueBind(SMSQueue, directExchangeName, infoRoute);
//为邮件队列绑定 info、error 路由
channel.queueBind(emailQueue, directExchangeName, infoRoute);
channel.queueBind(emailQueue, directExchangeName, errorRoute);
//关闭通道
channel.close();
//关闭连接
connection.close();
return "";
}
}
生产者 DirectProducer 代码:注意,发消息的是往交换机发消息,并指定路由规则,而不是往队列发消息。
package com.study.producer;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author biandan
* @description 消息生产者(扇形交换机)
* @signature 让天下没有难写的代码
* @create 2021-04-04 下午 10:49
*/
@Component
public class DirectProducer {
private SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//交换机名称
@Value("${queueConfig.directExchangeName}")
private String directExchangeName;
//info 路由
@Value("${queueConfig.infoRoute}")
private String infoRoute;
//error 路由
@Value("${queueConfig.errorRoute}")
private String errorRoute;
/**
* 注入 AMQP 消息模板
*/
@Autowired
private AmqpTemplate template;
/**
* 每隔5秒产生一条消息
*/
@Scheduled(fixedRate = 1000 * 5)
public void sendMsg() {
String infoMsg = "直连交换机消息生产者 info:" + SDF.format(new Date());
String errorMsg = "直连交换机消息生产者 error:" + SDF.format(new Date());
System.out.println(infoMsg);
System.out.println(errorMsg);
//发送消息(往路由发消息,而不是往队列发消息)
template.convertAndSend(directExchangeName, infoRoute, infoMsg);
template.convertAndSend(directExchangeName, errorRoute, errorMsg);
}
}
启动类:
package com.study;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling //启用任务调度
@EnableEurekaClient
public class RabbitMQRoutingApplication {
public static void main(String[] args) {
SpringApplication.run(RabbitMQRoutingApplication.class, args);
}
}
OK,我们启动项目,看下控制台输出:OK,可以正常启动,发消息。
查看 RabbitMQ 后台,查看交换机页面:
队列页面:
OK,我们继续编写消费者类:
邮件消费者:
package com.study.consumer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @author biandan
* @description 邮件消费者
* @signature 让天下没有难写的代码
* @create 2021-04-04 下午 11:39
*/
@Component
@RabbitListener(queues = "${queueConfig.emailQueue}")
public class Consumer_Email {
@RabbitHandler
public void receiveMsg(String msg) {
System.out.println("邮件消费者_消费掉的消息:" + msg);
}
}
SMS 消费者:
package com.study.consumer;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
/**
* @author biandan
* @description 短信消费者
* @signature 让天下没有难写的代码
* @create 2021-04-04 下午 11:39
*/
@Component
@RabbitListener(queues = "${queueConfig.SMSQueue}")
public class Consumer_SMS {
@RabbitHandler
public void receiveMsg(String msg) {
System.out.println("短信消费者_消费掉的消息:" + msg);
}
}
启动项目,控制台输出:说明邮件消费者可以获得 info、error 的消息。
代码在百度网盘连接:https://pan.baidu.com/s/1Izb0WbsuLCJJXlm445xjrw 提取码:xnjd