channle.queueDeclare() channle.exchangeDeclare() channle.queueBind()
其实随便可以写在生产者or消费者,只需要保证在channle.consumer(…)之前即可特点:
至于routingKey是什么,设或者不设都不影响
//fanout扇出 发布订阅
public static void main(String[] args) throws Exception {
Channel channel = getChannel();
//1.在消费者启动之前,需要先声明 ——————交换机
channel.exchangeDeclare("我的fanout交换机", BuiltinExchangeType.FANOUT);
//2.在消费者启动之前,需要先声明 ——————队列
//如果要绑定交换机,则第三个exclusive参数为false
channel.queueDeclare("q1",true,false,false,null);
channel.queueDeclare("q2",true,false,false,null);
channel.queueDeclare("q3",true,false,false,null);
//3.fanout交换机中任何对于routingKey的指定都没有效果
channel.queueBind("q1","我的fanout交换机","随便写");
channel.queueBind("q2","我的fanout交换机","11111");
channel.queueBind("q3","我的fanout交换机","22222");
/*
* 其实exchange和queue的声明随便放在生产者or消费者
* 但是一定要在消费者consumer之前声明,不然就会报错
**/
//4.开始发消息,producer发给指定的exchange,因为指定了fanout模式,
//所以绑定该exchange的所有queue都会收到消息,且无关routingKey
for(int i = 1 ; i < =10 ; i++){
channel.basicPublish("我的fanout交换机"
,"你看我随便指定routingKey"
, MessageProperties.PERSISTENT_TEXT_PLAIN
, ("第"+i+"条消息").getBytes(StandardCharsets.UTF_8));
System.out.println("Producer发布消息:"+i);
}
producer发布了10次给exchange,对应的3个队列,一共30条消息
一共用3个消费者分别消费这三条队列的消息
代码示例:
public static void main(String[] args) throws Exception {
Channel channel = getChannel();
DeliverCallback deliverCallback = (consumerTag,message)->{
System.out.println("Consumer1收到消息:"+new String(message.getBody(),"UTF-8"));
};
channel.basicConsume("q1",true,
deliverCallback,
cancleCallBack -> {}//取消时什么都不做
);
}
当生产者没有指定channle.exchangeDeclare(…)的模式时,默认使用的是直连交换机,routingKey就是queue名字
代码示例:
与默认的direct模式不同,路由模式需要显式
的声明exchange,并绑定routingKey
public static void main(String[] args) throws Exception {
Channel channel = getChannel();
//1.声明为direct直连交换机
channel.exchangeDeclare("logger", BuiltinExchangeType.DIRECT);
channel.queueDeclare("ERROR",false,false,true,null);
//INFO和WARNING级别的日志写入磁盘7天,ERROR级别的写入磁盘30天
channel.queueDeclare("INFO_AND_WARNING",false,false,true,null);
//2.绑定队列 交换机
channel.queueBind("ERROR","logger","error_key");
channel.queueBind("INFO_AND_WARNING","logger","info_warning_key");
//3.模拟日志信息
HashMap map = new HashMap<>();
map.put("INFO","INFO日志xxxxxxx");
map.put("WARNING","WARNING警告yyyyyy");
map.put("ERROR","ERROR错误zzzzzzz");
map.forEach((key,value)->{
try {
if("ERROR".equals(key)){
channel.basicPublish("logger","error_key",null,value.getBytes(StandardCharsets.UTF_8));
}
if("WARNING".equals(key) || "INFO".equals(key)){
channel.basicPublish("logger","info_warning_key",null,value.getBytes(StandardCharsets.UTF_8));
}
} catch (IOException e) {
e.printStackTrace();
}
});
}
一个处理ERROR日志的消费者:
public static void main(String[] args) throws Exception{
Channel channel = getChannel();
channel.basicConsume("ERROR",true,(e1,e2)->{
//把message写入磁盘30天
System.out.println("ERROR日志写入磁盘:"+ new String(e2.getBody()));
}, (e1,e2)->{});
}
一个处理INFO和WARNING日志的消费者:
public static void main(String[] args) throws Exception{
Channel channel = getChannel();
channel.basicConsume("INFO_AND_WARNING",true,
(e1,e2)->{
System.out.println(new String(e2.getBody()));
},
(e1,e2)->{});
}
核心代码:
//队列绑定交换机
channel.queueBind(TOPIC_QUEUE_1,TOPIC_EXCHAGE,"item.#");
channel.queueBind(TOPIC_QUEUE_2,TOPIC_EXCHAGE,"*.delete");
一般只有画框的这三个用的多
略
在声明了交换机、队列之后,需要将队列与交换机绑定,但是我用的是channle.exchangeBind(destination,sourse,routingKey)
这玩意其实是交换机之间互相绑定的,前两个参数都是exchange的名字
所以报错 channel error; protocol method: #methodno exchange 'q1' in vhost '/',
class-id=40, method-id=30)
改用chanle.queueBind即可