常用的Exchange类型有4种
可能大家不是很理解,下面来看代码就知道了!
引入依赖
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.6.0</version>
</dependency>
下面这个类用于创建一个与RabbitMQ的Connection(连接),该Connection用于创建Channel(信道),Channel是消息读写的通道,也就是我们的操作都会在Channel的基础之上进行
package com.dfyang.rabbitmq;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class RabbitmqConnectionFactory {
private static ConnectionFactory factory = new ConnectionFactory();
private static String HOST = "192.168.195.123";
private static int PORT = 5672;
private static String USERNAME = "root";
private static String PASSWORD = "151310";
static {
factory.setHost(HOST);
factory.setPort(PORT);
factory.setUsername(USERNAME);
factory.setPassword(PASSWORD);
}
public static Connection newConnection() {
try {
return factory.newConnection();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
package com.dfyang.rabbitmq.pc0;
import com.dfyang.rabbitmq.RabbitmqConnectionFactory;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
public class Producer {
private static String EXCHANGE_NAME = "exchange0";
private static String QUEUE_NAME = "queue0";
private static String BINDING_KEY = "key0";
private static String ROUTING_KEY = "key0";
private static String MESSAGE = "pc0发送消息";
public static void main(String[] args) throws Exception {
//创建一个Connection连接
Connection connection = RabbitmqConnectionFactory.newConnection();
//开启Channel
Channel channel = connection.createChannel();
//创建一个Exchange,设置名称和类型为direct
channel.exchangeDeclare(EXCHANGE_NAME, "direct");
//创建一个Queue,设置名称,后面先不管
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
//建立Queue与Exchange之间的BindingKey
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, BINDING_KEY);
//使用生产者发布一条消息和RoutingKey
channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, null, MESSAGE.getBytes());
//关闭Channel与Connection
channel.close();
connection.close();
}
}
上面代码我们干了什么?
后面将不会对一些基础的进行详细的描述,请读懂上面这个再往下看
执行上述代码,进入可视化管理界面,发现RabbitMQ已经帮我们创建好了Exchange和Queue,并建立了绑定关系,而且我们可以看到queue0是有一个消息正在准备被消费的状态不会的点这
——我们将ROUTING_KEY改为其他,会发现Queue0的Ready还是为1,因为我们的Exchange为direct类型,因此RoutingKey必须与BindingKey相等才能路由消息到Queue
下面我们来将这个消息消费掉
package com.dfyang.rabbitmq.pc0;
import com.dfyang.rabbitmq.RabbitmqConnectionFactory;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class Consumer {
private static String QUEUE_NAME = "queue0";
public static void main(String[] args) throws Exception {
Connection connection = RabbitmqConnectionFactory.newConnection();
Channel channel = connection.createChannel();
//创建消费者,传入信道,因为消费者需要在信道的基础上消费数据
//并重写获取消息的处理逻辑
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
System.out.println("consumerTag(消费者标签,区分消费者):"
+ consumerTag);
System.out.println("envelope(封装了一些本次路由相关的信息):"
+ envelope.toString());
System.out.println("msg(消息体):" + new String(body));
}
};
//Consumer消费消息,传入Queue
//第二个参数为是否自动响应,设为true表示消费者接受消息表示这条消息已经消费了
//否则即使获取到消息,该消息还会存在Queue中
channel.basicConsume(QUEUE_NAME, true, consumer);
//这里停留1s,防止执行慢了资源关闭
TimeUnit.SECONDS.sleep(1);
channel.close();
connection.close();
}
}
结果
这里对envelope进行一些解释
介绍Topic所使用的匹配符
eg.BindingKey:user . * (可以匹配user.delete,user.find,user.update)
eg.BindingKey:* . * . user (可以匹配delete.find.test)
eg.BindingKey:#. user (可以匹配delete.user,delete.find.user)
eg.BindingKey:user.# (可以匹配user.find.delete,user.find.find.find.find)
很好理解,希望大家能看懂
Producer
package com.dfyang.rabbitmq.pc1;
import com.dfyang.rabbitmq.RabbitmqConnectionFactory;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
public class Producer {
private static String EXCHANGE_NAME = "exchange1";
private static String QUEUE_NAME = "queue1";
private static String BINDING_KEY = "user.*";
private static String ROUTING_KEY0 = "user.delete";
private static String ROUTING_KEY1 = "user.update";
private static String ROUTING_KEY2 = "user.delete.find";
private static String MESSAGE0 = "user.delete";
private static String MESSAGE1 = "user.update";
private static String MESSAGE2 = "user.delete.find";
public static void main(String[] args) throws Exception {
Connection connection = RabbitmqConnectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "topic");
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, BINDING_KEY);
//发送RoutingKey:user.delete
channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY0, null, MESSAGE0.getBytes());
//发送RoutingKey:user.update
channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY1, null, MESSAGE1.getBytes());
//发送RoutingKey:user.delete.find
channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY2, null, MESSAGE2.getBytes());
channel.close();
connection.close();
}
}
这里创建了BindingKey为user.*,并发送了三个RoutingKey分别为user.delete、user.update、user.delete.find的消息,如果弄懂了上面.和#,那么这里很明显user.delete、user.update的消息将被路由到queue1,而user.delete.find的消息将被pass掉
Consumer
package com.dfyang.rabbitmq.pc1;
import com.dfyang.rabbitmq.RabbitmqConnectionFactory;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
public class Consumer {
private static String QUEUE_NAME = "queue1";
public static void main(String[] args) throws Exception {
Connection connection = RabbitmqConnectionFactory.newConnection();
Channel channel = connection.createChannel();
DefaultConsumer consumer = new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag,
Envelope envelope,
AMQP.BasicProperties properties,
byte[] body) throws IOException {
System.out.println(new String(body));
}
};
channel.basicConsume(QUEUE_NAME, true, consumer);
TimeUnit.SECONDS.sleep(1);
channel.close();
connection.close();
}
}
Producer
这里先声明一下,由于fanout模式Exchange会自动将发送到该Exchange的消息路由到所有与该Exchange所绑定的Queue,所以路由键以及绑定键就没有必要存在了,但还是得要,因为不要会报错,所以这里名字可以随便写,反正没什么用处。注意理解,绑定键是进行路由的规则,路由键是匹配这个规则,而我们此时不需要规则。
package com.dfyang.rabbitmq.pc2;
import com.dfyang.rabbitmq.RabbitmqConnectionFactory;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
public class Producer {
private static String EXCHANGE_NAME = "exchange2";
private static String QUEUE_NAME0 = "queue2.0";
private static String QUEUE_NAME1 = "queue2.1";
private static String MESSAGE = "发送fanout";
public static void main(String[] args) throws Exception {
Connection connection = RabbitmqConnectionFactory.newConnection();
Channel channel = connection.createChannel();
//生命一个Exchange,名称为exchange2
channel.exchangeDeclare(EXCHANGE_NAME, "fanout");
//声明两个Queue,queue2.0和queue2.1
channel.queueDeclare(QUEUE_NAME0, true, false, false, null);
channel.queueDeclare(QUEUE_NAME1, true, false, false, null);
//将exchange2分别与两个queue进行绑定
channel.queueBind(QUEUE_NAME0, EXCHANGE_NAME, "BindingKey");
channel.queueBind(QUEUE_NAME1, EXCHANGE_NAME, "BindingKey");
channel.basicPublish(EXCHANGE_NAME, "RoutingKey", null, MESSAGE.getBytes());
channel.close();
connection.close();
}
}
很明显,消息将发送到queue2.0和queue2.1,执行上面的程序,查询可视化界面
下面这段代码是创建一个类型为headers得Exchange,和一个Queue,并将他们通过一个headers进行绑定,也就是必须匹配里面得参数才能成功路由
package com.dfyang.rabbitmq.pc3;
import com.dfyang.rabbitmq.RabbitmqConnectionFactory;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import java.util.HashMap;
import java.util.Map;
public class Producer {
private static String EXCHANGE_NAME = "exchange3";
private static String QUEUE_NAME = "queue3";
public static void main(String[] args) throws Exception {
Connection connection = RabbitmqConnectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EXCHANGE_NAME, "headers");
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
Map<String, Object> headers = new HashMap<>();
headers.put("username", "root");
headers.put("password", "151310");
channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "headers", headers);
AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties().builder().headers(headers);
channel.close();
connection.close();
}
}
执行程序
可以看到RabbitMQ已经为我们创建了exchange3,并且类型为headers,接下来我们使用可是可视化页面进行发布消息
先发送错误的消息
点击exchange3 -> 点击Publish message
提示我们消息发布了,但没有路由到的Queue,也就是没有匹配的
接下来发送正确的消息,很明显发送成功,此时我们的queue中也多了一个消息,可以进入queue3查看消息的具体内容
这里再解释一下BindingKey,我们可以看到再对Exchange和Queue进行绑定时,参数提示为routingKey而不是bindingKey,因为除了Exchange为topic类型外,其他类型我们可以认为BindingKey与RoutingKey是相等的,所有没必要太过于区分