系列文章目录
提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加
例如:第一章 Python 机器学习入门之pandas的使用
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
提示:以下是本篇文章正文内容,下面案例可供参考
一、配置链接
yml配置
spring:
application: rabbitMq
rabbitmq:
host: 127.0.0.1
port: 5672
username: admin
password: admin
virtual-host: rabbit1
#配置消费消息使用手动确认模式
listener:
type: simple
simple:
acknowledge-mode: manual
配置链接 &关闭链接 &
@Configuration
public class MqConnect {
/**地址 */
@Value("${spring.rabbitmq.host}")
public static String host;
/**端口 */
@Value("${spring.rabbitmq.host}")
public static Integer post;
/**虚拟机 */
@Value("${spring.rabbitmq.virtual-host}")
public static String virtualHost;
/**用户名 */
@Value("${spring.rabbitmq.username}")
public static String userName;
/**密码 */
@Value("${spring.rabbitmq.password}")
public static String psd;
/**链接 */
public static Connection connect() throws IOException, TimeoutException {
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost(host);
connectionFactory.setPort(post);
//设置虚拟主机
connectionFactory.setVirtualHost("rabbit1");
//用户名密码
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
Connection connection = connectionFactory.newConnection();
return connection;
}
/**关闭链接 */
public static void closeConnect(Channel channel, Connection connection) throws IOException, TimeoutException {
if (null!=channel){
channel.close();
}
if (null!=connection){
connection.close();
}
}
}
public class QueueKey {
//------------------queue
public static final String queue_name="queue_type";
//
public static final String work_queue_name="queue_work";
public static final String direct_queue_name="queue_direct";
public static final String direct_exchange="direct_exchange";
public static final String direct_routingKey1="insert";
public static final String direct_routingKey2="update";
public static final String fanout_queue_name="queue_fanout";
public static final String fanout_queue_name2="queue_fanout2";
public static final String fanout_exchange="ex_fanout";
public static final String topic_queue_name="queue_topic";
public static final String topic_queue_name2="queue_topic2";
public static final String topic_exchange="topic_exchange";
public static final String topic_routingKey1="logs.insert.product";
public static final String topic_routingKey2="logs.update.product";
public static final String topic_dlx_exchange="dlx_exchange";
public static final String topic_dlx_queue="dlx_queue";
public static final String topic_dlx_key="dlx-routing-key";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection= MqConnect.connect();
Channel channel = connection.createChannel();
channel.exchangeDelete(direct_exchange);
channel.exchangeDelete(fanout_exchange);
channel.exchangeDelete(topic_exchange);
channel.exchangeDelete(topic_dlx_exchange);
channel.queueDelete(queue_name);
channel.queueDelete(topic_dlx_queue);
channel.queueDelete(topic_queue_name);
channel.queueDelete(work_queue_name);
channel.queueDelete(direct_queue_name);
channel.queueDelete(fanout_queue_name);
channel.queueDelete(fanout_queue_name2);
MqConnect.closeConnect(channel,connection);
}
二、JAVA_API代码
1.声明交换机 exchangeDeclare
/**
* 声明一个交换器(Exchange),通过完整的参数集;
* exchange: 交换器的名称
* type: 交换器类型
* durable: true 如果声明一个持久化的交换器(服务端重启交换器仍然存在)
* autoDelete: true 如果服务器不在使用交换器时删除它
* internal: true 如果交换器是内置的,则表示客户端无法直接发送消息到这个交换器中,
* 只能通过交换器路由到交换器的方式
* arguments: 交换器的其它属性(构造参数)
*/
channel.exchangeDeclare("exchange","direct",false,false,false,null);//路由模式
2.声明队列& 队列属性 queueDeclare
/**
* 声明队列
* durable: true 如果我们声明一个持久化队列(队列将会在服务重启后任然存在)
* exclusive: true 如果我们声明一个独占队列(仅限于此链接)
* autoDelete: true 声明一个自动删除队列(服务器将在不使用它时删除,即队列的连接数为0)
* arguments: 队列的其它属性(构造参数)
*/
channel.queueDeclare("mydirect",false,false,false,null);
Map<String, Object> ttlQueue = new HashMap<String, Object>();
/** 死信交换器,消息被拒绝或过期时将会重新发送到的交换器 */
ttlQueue.put("x-dead-letter-exchange",dlx_exchange);
/** 当消息是死信时使用的可选替换路由 */
ttlQueue.put("x-dead-letter-routing-key", dlx_key);
/** 设置消息发送到队列中在被丢弃之前可以存活的时间,单位:毫秒 */
ttlQueue.put("x-message-ttl", 10*60*1000);
/** 设置一个队列多长时间未被使用将会被删除,单位:毫秒 */
ttlQueue.put("x-expires", 15*60*1000);
/** queue中可以存储处于ready状态的消息数量 */
ttlQueue.put("x-max-length", 6);
/** queue中可以存储处于ready状态的消息占用的内存空间 */
ttlQueue.put("x-max-length-bytes", 1024);
/** queue溢出行为,这将决定当队列达到设置的最大长度或者最大的存储空间时发送到消息队列的消息的处理方式; 有效的值是:drop-head(删除queue头部的消息)、reject-publish(拒绝发送来的消息)、reject-publish-dlx(拒绝发送消息到死信交换器) 类型为quorum 的queue只支持drop-head; */
ttlQueue.put("x-overflow", "reject-publish");
/** 惰性队列 惰性队列会将接收到的消息直接存入文件系统,而不管是持久化的或者是非持久化的,这样可以减少内存的消耗,但是会增加I/O的使用,如果消息是持久化的,那么这样的I/O操作不可避免,惰性队列和持久化的消息可谓是“最佳拍档”。注意如果惰性队列中存储的是非持久化的消息,内存的使用率会一直很稳定,但是重启之后消息一样会丢失。*/
ttlQueue.put("x-queue-mode", "lazy");
3.队列绑定交换机 queueBind
/**
* queue:队列名称
* exchange:交换器名称
* routingKey:用于绑定的路由key
*/
String routingKey="waring";
channel.queueBind("mydirect",logs,routingKey);
4.消息确认机制
/**消息确认机制
* prefetchSize:服务器传送最大内容量(以八位字节计算),如果没有限制,则为0
* prefetchCount:服务器每次传递的最大消息数,如果没有限制,则为0;
* global:如果为true,则当前设置将会应用于整个Channel(频道)
* void basicQos ( int prefetchSize, int prefetchCount, boolean global)
* channel.basicQos(1);和channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);是配套使用,
只有在channel.basicQos被使用的时候channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false)才起到作用。
*/
channel.basicQos(1);//每次只能消费1个消息
5.confiem模式
channel.confirmSelect();
6.推送消息&推送配置 BasicProperties
/**
* contentType:消息的内容类型,如:text/plain
* contentEncoding:消息内容编码
* headers:设置消息的header,类型为Map<String,Object>
* deliveryMode:1(nopersistent)非持久化,2(persistent)持久化
* priority:消息的优先级
* correlationId:关联ID
* replyTo:用于指定回复的队列的名称
* expiration:消息的失效时间
* messageId:消息ID
* timestamp:消息的时间戳
* type:类型
* userId:用户ID //mq用户
* appId:应用程序ID
* custerId:集群ID
*/
AMQP.BasicProperties properties=new AMQP.BasicProperties.Builder().expiration("50000").build();
/**
* 发布消息
* 发布到不存在的交换器将导致信道级协议异常,该协议关闭信道,
* exchange: 要将消息发送到的交换器
* routingKey: 路由KEY
* mandatory:如果为true, 消息不能路由到指定的队列时,则会调用basic.return方法将消息返回给生产者,
* 会触发addReturnListener注册的监听器;如果为false,则broker会直接将消息丢弃
* immediate:如果为true,当exchange将消息路由到queue时发现queue上没有消费者,
那么这条消息不会放入队列中,该消息会通过basic.return方法返还给生产者。
在RabbitMQ3.0以后的版本里去掉了immediate参数的支持,
* props: 消息的其它属性,如:路由头等
* body: 消息体
*/
channel.basicPublish(logs,routingKey,true,false,properties, "这是个消息".getBytes());//bytes消息
7.监听消息发送同步、异步 addConfirmListener
如果异步输出的结果与实际的数量不一样可能是因为,还没来得及回掉就关闭的链接通道
可以加个 Thread.sleep(500);试一试最后的结果就全了
/**
阻塞方法,直到mq服务器确认消息
单个确认
for{basicPublish;waitForConfirms}
批量
for{basicPublish}
waitForConfirms
*/
if(channel.waitForConfirms()){
System.out.println("已发送");
}
//异步实现1
channel.addConfirmListener((sequenceNumber, multiple) -> {
// code when message is confirmed
System.out.println("未确认消息,标识:" + sequenceNumber);
}, (sequenceNumber, multiple) -> {
System.out.println(String.format("已确认消息,标识:%d,多个消息:%b", sequenceNumber, multiple));
});
//异步实现2
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleNack(long deliveryTag, boolean multiple) throws IOException {
System.out.println("nack: deliveryTag = "+deliveryTag+" multiple: "+multiple);
}
@Override
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
System.out.println("ack: deliveryTag = "+deliveryTag+" multiple: "+multiple);
}
});
8.监听回退消息
channel.addReturnListener((returnMessage)-> {
System.out.println("第二个监听器执行了---");
});
/**
* channel.addReturnListener((replyCode, replyText, exchange, routingKey, properties, body) -> {
* System.out.println("第一个监听器执行了---");
* });
*/
9.接收消息 basicConsume
/**
* queue:队列名
* autoAck:true 接收到传递过来的消息后acknowledged(应答服务器),false 接收到消息后不应答服务器
* BasicProperties properties 队列携带的配置
*/
channel.basicConsume("topic",false,new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
super.handleDelivery(consumerTag, envelope, properties, body);
try{
// if (new String(body).equals("我是topic:98")){
// int i=1/0;
// }
System.out.println(new String(body));
channel.basicAck(envelope.getDeliveryTag(),false);
}catch (Exception e){
e.printStackTrace();
channel.basicNack(envelope.getDeliveryTag(),false,true);
System.out.println("执行了");
}
}
});
String basicConsume(String var1, boolean var2, DeliverCallback var3, CancelCallback var4) throws IOException;
我们也可以使用这个方法
channel.basicConsume(queue_name, false, (s, delivery) -> {
//amq.ctag-Iz60x-dGXbD2LPnV6vOyDQ
System.out.println(s);
System.out.println("接收body:"+new String(delivery.getBody()));
/**Envelope(deliveryTag=1, redeliver=false, exchange=, routingKey=queue_type) */
System.out.println(delivery.getEnvelope());
/**#contentHeader<basic>(content-type=null, content-encoding=null, headers=null,
delivery-mode=null, priority=null, correlation-id=null, reply-to=null, expiration=50000, message-id=70380994-acfd-48a6-9828-2e45414dda65, timestamp=Thu Sep 10 17:10:27 CST 2020, type=null, user-id=null, app-id=null, cluster-id=null)
*/
System.out.println(delivery.getProperties());
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
},(handle)->{
System.out.println(handle);
});
10.消息确认方式
/**确认消息*/
channel.basicAck(envelope.getDeliveryTag(),false);
/**
* 拒绝接收到的一个或者多个消息
* deliveryTag:接收到消息的唯一标识
* multiple: true表示拒绝所有的消息,包括提供的deliveryTag;false表示仅拒绝提供的deliveryTag
* requeue:true 获取消息,但是不做ack应答确认,消息重新入队进行消费,直到ack
* false 获取消息,应答确认,消息不重新入队,将会从队列中删除
*
*
*/
channel.basicNack(long deliveryTag, boolean multiple, boolean requeue)
/**
* 拒绝接收到的一个或者多个消息
* deliveryTag:接收到消息的唯一标识
* requeue:true 拒绝获取消息,消息重新入队
* false 拒绝获取消息,消息不重新入队,将会被删除
*
*/
channel.basicReject(long deliveryTag, boolean requeue)
11.删除队列
/**
* 删除一个队列
* queue:队列名
* ifUnused:true 只有队列不在使用的时候才允许删除
* ifEmpty:true 只有在队列是空的时候才允许删除
* @return 返回一个队列已经成功删除的确认类
*/
AMQP.Queue.DeleteOk deleteOk = channel.queueDelete(name, true, true);
12.清空队列消息
channel.queuePurge(name);
三 代码
0.创建链接,关闭链接,key设置,删除exchang,queue
public class MqConnect {
/**链接 */
public static Connection connect() throws IOException, TimeoutException {
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
//设置虚拟主机
connectionFactory.setVirtualHost("rabbit1");
//用户名密码
connectionFactory.setUsername("admin");
connectionFactory.setPassword("admin");
Connection connection = connectionFactory.newConnection();
return connection;
}
/**关闭链接 */
public static void closeConnect(Channel channel, Connection connection) throws IOException, TimeoutException {
if (null!=channel){
channel.close();
}
if (null!=connection){
connection.close();
}
}
}
public class QueueKey {
//------------------queue
public static final String queue_name="queue_type";
//
public static final String work_queue_name="queue_work";
public static final String direct_queue_name="queue_direct";
public static final String direct_exchange="direct_exchange";
public static final String direct_routingKey1="insert";
public static final String direct_routingKey2="update";
public static final String fanout_queue_name="queue_fanout";
public static final String fanout_queue_name2="queue_fanout2";
public static final String fanout_exchange="ex_fanout";
public static final String topic_queue_name="queue_topic";
public static final String topic_queue_name2="queue_topic2";
public static final String topic_exchange="topic_exchange";
public static final String topic_routingKey1="logs.insert.product";
public static final String topic_routingKey2="logs.update.product";
public static final String topic_dlx_exchange="dlx_exchange";
public static final String topic_dlx_queue="dlx_queue";
public static final String topic_dlx_key="dlx-routing-key";
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection= MqConnect.connect();
Channel channel = connection.createChannel();
channel.exchangeDelete(direct_exchange);
channel.exchangeDelete(fanout_exchange);
channel.exchangeDelete(topic_exchange);
channel.exchangeDelete(topic_dlx_exchange);
channel.queueDelete(queue_name);
channel.queueDelete(topic_dlx_queue);
channel.queueDelete(topic_queue_name);
channel.queueDelete(work_queue_name);
channel.queueDelete(direct_queue_name);
channel.queueDelete(fanout_queue_name);
channel.queueDelete(fanout_queue_name2);
MqConnect.closeConnect(channel,connection);
}
}
1.queue队列(点对点)
public class QueueTest {
@Test
public void send() throws Exception {
producer("我是queue队列");
}
public void producer( String body) throws Exception{
Connection connection= MqConnect.connect();
Channel channel = connection.createChannel();
channel.queueDeclare(QueueKey.queue_name,true,false,false,null);
AMQP.BasicProperties properties= new AMQP.BasicProperties.Builder()
.expiration("50000")
.timestamp(new Date())
.messageId(UUID.randomUUID().toString())
.build();
channel.basicQos(1);
channel.basicPublish("", QueueKey.queue_name,false,properties,body.getBytes());
MqConnect.closeConnect(channel,connection);
}
public static void main(String[] args)throws Exception{
Connection connection=MqConnect.connect();
Channel channel = connection.createChannel();
channel.queueDeclare(QueueKey.queue_name,true,false,false,null);
channel.basicConsume(QueueKey.queue_name, false, (s, delivery) -> {
//amq.ctag-Iz60x-dGXbD2LPnV6vOyDQ
System.out.println(s);
System.out.println("接收body:"+new String(delivery.getBody()));
/**Envelope(deliveryTag=1, redeliver=false, exchange=, routingKey=queue_type)
* deliveryTag 每次接收消息+1 可以用来回传告诉 rabbitmq 这个消息处理成功 清除此消息(basicAck方法)
* */
System.out.println(delivery.getEnvelope());
/**#contentHeader<basic>(content-type=null, content-encoding=null, headers=null,
delivery-mode=null, priority=null, correlation-id=null, reply-to=null, expiration=50000, message-id=70380994-acfd-48a6-9828-2e45414dda65, timestamp=Thu Sep 10 17:10:27 CST 2020, type=null, user-id=null, app-id=null, cluster-id=null)
*/
System.out.println(delivery.getProperties());
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
},(handle)->{
System.out.println(handle);
});
}
}
2.queue队列(work模式)
public class WorkTest {
@Test
public void send() throws Exception {
Long a=System.currentTimeMillis();
producer("workMode");
Long b=System.currentTimeMillis();
System.out.println("总用时="+(b-a)+"ms");
}
private void producer(String workMode) throws Exception {
Connection connection= MqConnect.connect();
Channel channel = connection.createChannel();
channel.queueDeclare(QueueKey.work_queue_name,false,false,false,null);
AMQP.BasicProperties properties=new AMQP.BasicProperties.Builder()
.messageId(UUID.randomUUID().toString()).timestamp(new Date())
.build();
channel.confirmSelect();
for (int i = 0; i <10 ; i++) {
String body=workMode+"--"+i;
channel.basicPublish("",QueueKey.work_queue_name,properties,body.getBytes());
if(channel.waitForConfirms()){
System.out.println("发送成功"+i);
}
}
MqConnect.closeConnect(channel,connection);
}
public static void main(String[] args) throws Exception {
Connection connection=MqConnect.connect();
Channel channel = connection.createChannel();
channel.queueDeclare(QueueKey.work_queue_name,true,false,false,null);
channel.basicQos(1);
channel.basicConsume(QueueKey.work_queue_name,false,(s, delivery) ->{
System.out.println(new String(delivery.getBody()));
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
},(h)->{
System.out.println(h);
});
}
}
消费者2
public static void main(String[] args) throws Exception {
Connection connection= MqConnect.connect();
Channel channel = connection.createChannel();
channel.queueDeclare(QueueKey.work_queue_name,true,false,false,null);
channel.basicConsume(QueueKey.work_queue_name,false,(s, delivery) ->{
System.out.println(new String(delivery.getBody()));
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
channel.basicAck(delivery.getEnvelope().getDeliveryTag(),false);
},(h)->{
System.out.println(h);
});
}