package com.example.demo.RabbitMQ;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;
/**
* RabbitMq 消息队列 生产者
*/
public class Producer{
final static String EXCHANGE_NAME="main-exchange";
final static String BACK_EXCHANGE_NAME="back";
public static void main(String[] args) throws IOException, TimeoutException {
//连接工厂
ConnectionFactory connectionFactory=new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
connectionFactory.setVirtualHost("/");
//打开新连接
Connection connection=connectionFactory.newConnection();
//获取通道
Channel channel=connection.createChannel();
//声明备用交换器
Map<String,Object> argsMap=new HashMap<String,Object>();
argsMap.put("alternate-exchange",BACK_EXCHANGE_NAME);
//声明信道 交换器 类型:direct 名称:EXCHANGE_NAME 第三个参数是否持久化
//主交换器
channel.exchangeDeclare(EXCHANGE_NAME,"direct",true,false,argsMap);
//备用交换器
channel.exchangeDeclare(BACK_EXCHANGE_NAME,BuiltinExchangeType.FANOUT,true,false,null);
//启用发送者确认模式
//channel.confirmSelect();
//预取模式 前提条件 关闭自动应答 autoAck=false
//channel.basicQos(1);
//DIRECT Fanout 测试
//所有日志严重性级别
String[] severities={"error","info","warning"};
for(int i=0;i<3;i++){
//每一次发送一条不同严重性的日志
String severity = severities[i%3];
// 发送的消息
String message = "Hello World_"+(i+1);
//参数1:exchange name
//参数2:routing key
channel.basicPublish(EXCHANGE_NAME, severity,
null, message.getBytes());
System.out.println(" [x] Sent '" + severity +"':'"
+ message + "'");
}
// 关闭频道和连接
channel.close();
connectionFactory.clone();
/**
1.交换器默认类别 Exchange DIRECT RabbitMQ默认的交换机模式,也是最简单的模式,根据key全文匹配去寻找队列。
交换器默认类别 Exchange Fanout 消息广播的模式,不管路由键或者是路由模式,会把消息发给绑定给它的全部队列,如果配置了routing_key会被忽略。
交换器默认类别 Exchange TOPIC 转发消息主要是根据通配符* #。 在这种交换机下,队列和交换机的绑定会定义一种路由模式,那么,通配符就要在这种路由模式和路由键之间匹配后交换机才能转发消息。
①*(星号)仅代表一个单词
②#(井号)代表任意个单词
2.队列和交换器的多重绑定
3.一个链接多个信道
4.一个队列多个消费者
5.保证消息发布可靠性 常用a、b 不常用e、f
a.失败通知 通过设置mandatory=true; channel.basicPublish(EXCHANGE_NAME,serverity,mandatory,null,msg.getBytes());
b.发布确认 启动 channel.confirmSelect(); 一条一条确认 channel.waitForConfirms(), 批量确认 channel.waitForConfirmsOrDie();
c.备用交换机
d.高可用队列 集群使用
e.事务 在生产者中定义 启用:channel.txSelect(); 提交:channel.txCommit(); 回滚:channel.txRollback();
f.事务+高可用队列
h.消息队列持久化
队列持久化第二个参数 true:channel.queueDeclare(qname,true,false,false,null);
交换机持久化第三个参数 true: channel.exchangeDeclare(EXCHANGE_NAME,"direct",true,false,argsMap);
6.消费者手动确认 channel.basicAck(envelope.getDeliveryTag(),false);
7.消费者 预取模式 channel.basicQos(1,true); 前提条件 关闭自动应答 autoAck=false
**/
//连接关闭时执行
/*
connection.addShutdownListener(new ShutdownListener() {
@Override
public void shutdownCompleted(ShutdownSignalException e) {
System.out.println(e.getMessage());
}
});
//通道关闭时执行
channel.addShutdownListener(new ShutdownListener() {
@Override
public void shutdownCompleted(ShutdownSignalException e) {
System.out.println(e.getMessage());
}
});
*/
//执行失败 返回失败信息
/*channel.addReturnListener(new ReturnListener() {
@Override
public void handleReturn(int replyCode,
String replyText,
String exchange,
String routingKey,
AMQP.BasicProperties basicProperties,
byte[] bytes) throws IOException {
String message=new String(bytes);
System.out.println("返回的replyText:"+replyText);
System.out.println("返回的exchange:"+exchange);
System.out.println("返回的routingKey :"+routingKey);
System.out.println("返回的message :"+message);
}
});
channel.addConfirmListener(new ConfirmListener() {
@Override
public void handleAck(long deliveryTag, boolean multiple) throws IOException {
System.out.println("deliveryTag"+deliveryTag +",multiple"+multiple);
}
@Override
public void handleNack(long l, boolean b) throws IOException {
}
});
channel.addReturnListener(new ReturnListener() {
@Override
public void handleReturn(int i, String s, String s1, String s2, AMQP.BasicProperties basicProperties, byte[] bytes) throws IOException {
System.out.println("路由失败");
}
});*/
/*
String[] server={"error","info","warning"};
String[] modules={"user","order","email"};
String[] titles={"A","B","C"};
for (int i=0;i<3;i++){
String serverity=server[i%3];
String msg="RabbitMq 发送消息"+(i+1);
//mandatory:执行失败 返回错误通知
boolean mandatory=true;
//需要参数:1.交换器 2.路由键 3.执行失败 返回错误通知
channel.basicPublish(EXCHANGE_NAME,serverity,mandatory,null,msg.getBytes());
*//*if(channel.waitForConfirms()){
System.out.println("信息发送成功");
}else {
System.out.println("信息发送失败");
}*//*
//Thread.sleep(200);
}*/
//TOPIC 测试
//日志消息 路由键形式 info.order.B
/*for (int i=0;i<3;i++){
for (int j=0;j<3;j++){
for (int k=0;k<3;k++){
String message="Hello Topic_["+i+","+j+","+k+"]";
String routey=server[i%3]+"."+modules[j%3]+"."+titles[k%3];
channel.basicPublish(EXCHANGE_NAME,routey,null,message.getBytes());
System.out.println("[x] sent ' " + routey +":'"+message+"'");
}
}
}*/
//批量确认
//channel.waitForConfirmsOrDie();
}
}
package com.example.demo.RabbitMQ;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* RabbitMq 消息队列 消息者
*/
public class Consumers {
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
/**
* 生产者-消费者 创建消息队列一致
**/
//连接工厂
ConnectionFactory factory=new ConnectionFactory();
factory.setHost("127.0.0.1");
factory.setUsername("guest");
factory.setPassword("guest");
factory.setVirtualHost("/");
//打开新连接
Connection connection=factory.newConnection();
//创建信道
Channel channel=connection.createChannel();
/**
* 生产者-消费者 创建消息队列一致
**/
//声明一个队列 随机生成队列 channel.queueDeclare().getQueue();
String qname="qname_error";
channel.queueDeclare(qname,true,false,false,null);
//绑定:将队列和交换器通过路由键进行绑定
String rockey="error";
channel.queueBind(qname,Producer.EXCHANGE_NAME,rockey);
//预取模式 前提条件 关闭自动应答 autoAck=false
//channel.basicQos(1);
//生产者 拉取模式
/*while(true){
GetResponse getResponse =channel.basicGet(qname, true);
if(null!=getResponse){
System.out.println("received["+getResponse.getEnvelope().getRoutingKey()+"]" +new String(getResponse.getBody()));
}
Thread.sleep(1000);
}*/
//声明消费者
final Consumer consumerA=new DefaultConsumer(channel){
//消息到达出发这个方法
@Override
public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body) throws IOException{
String message=new String(body, StandardCharsets.UTF_8);
System.out.println("RabbitMq 接收消息-["+envelope.getRoutingKey()+"]:"+message);
//消费者手动确认 channel.basicAck(envelope.getDeliveryTag(),false);
}
};
//System.out.println("RabbitMq 等等发送消息"+qname);
//消费者 正式开始在指 定队列进行消费
boolean autoAck=true;//自动确认
channel.basicConsume(qname,autoAck,consumerA);
}
}
package com.example.demo.RabbitMQ;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.TimeoutException;
/**
* RabbitMq 消息队列 消息者
*/
public class Consumers2 {
public static void main(String[] args) throws IOException, TimeoutException {
/**
* 生产者-消费者 创建消息队列一致
**/
ConnectionFactory Factory=new ConnectionFactory();
Factory.setHost("127.0.0.1");
Factory.setUsername("guest");
Factory.setPassword("guest");
Factory.setVirtualHost("/");
//打开新连接
Connection connection=Factory.newConnection();
//创建信道
final Channel channel=connection.createChannel();
//创建交换器
channel.exchangeDeclare(Producer.BACK_EXCHANGE_NAME,BuiltinExchangeType.FANOUT,true,false,null);
/**
* 生产者-消费者 创建消息队列一致
**/
//声明一个队列 随机生成队列 channel.queueDeclare().getQueue();
String qname="other";
channel.queueDeclare(qname,true,false,false,null);
//绑定:将队列和交换器通过路由键进行绑定
String rockey="#";
channel.queueBind(qname,Producer.BACK_EXCHANGE_NAME,rockey);
//保证一次只分发一个 前提条件 关闭自动应答 autoAck=false
//channel.basicQos(1);
//声明消费者
final Consumer consumer=new DefaultConsumer(channel){
//消息到达出发这个方法
@Override
public void handleDelivery(String consumerTag,Envelope envelope,AMQP.BasicProperties properties,byte[] body) throws IOException{
String message=new String(body, StandardCharsets.UTF_8);
System.out.println("RabbitMq 接收消息["+envelope.getRoutingKey()+"]:"+message);
}
};
System.out.println("RabbitMq 等等发送消息"+qname);
//消费者 正式开始在指 定队列进行消费
boolean autoAck=true;//自动确认
channel.basicConsume(qname,autoAck,consumer);
}
}