发布订阅模式用到了交换机,消息不再直接发送给队列了,其实消息本来也没直接发送给队列,在工作队列和简单的HelloWorld代码里,我们其实发送至的是一个默认交换机。而发布订阅模式需要自己定义一个交换机。
将消息发送给交换机,再由交换机的类型分发给队列。发布订阅模式中交换机的类型是BuiltinExchangeType.FANOUT
,即“fanout”。
话不多说,代码,上!
public class SendMessage {
private static final ConnectionFactory factory = new ConnectionFactory();
private static Connection connectionStatic = null;
static {
factory.setHost("49.232.202.201");
factory.setUsername("gosuncn");
factory.setPassword("123456");
factory.setVirtualHost("/gosuncn");
try {
connectionStatic = factory.newConnection();
} catch (IOException | TimeoutException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
try (Connection connection = connectionStatic; Channel channel = connection.createChannel()) {
channel.exchangeDeclare(Constant.EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
channel.basicPublish(Constant.EXCHANGE_NAME, "", null, ("FANOUT").getBytes());
System.out.println("消息已发送至交换机");
} catch (Exception exception) {
exception.printStackTrace();
}
}
}
这是发送消息的程序代码,可以看出channel.exchangeDeclare(Constant.EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
声明了一个FANOUT
类型交换机。还给交换机起了个名字,叫Constant.EXCHANGE_NAME
常量对应的值。
之前,我们发送消息,是这样发:channel.basicPublish("", QUEUE_NAME, null, MESSAGE.getBytes());
将消息发送给" "
默认交换机(类型是直连交换机DIRECT("direct")
),再由默认交换机发送给QUEUE_NAME
队列,其实第二个参数是路由键,并不是队列的名字。由于直连交换机的特点就是根据路由键去寻找和路由键相同名称的队列,所以我们也可以理解为队列名。
而发布订阅模式,channel.basicPublish(Constant.EXCHANGE_NAME, "", null, ("FANOUT").getBytes());
指:我们不再发送给默认交换机了,而是发给名为Constant.EXCHANGE_NAME
常量值的交换机,路由键为空,由于该交换机是FANOUT
类型交换机,凡是收到消息就会把消息分发给所有绑定的队列,所以起到了一个发布订阅的功能。
来看下消费者的代码:
public static void main(String[] args) throws IOException {
Channel channel = connection.createChannel();
channel.exchangeDeclare(Constant.EXCHANGE_NAME, BuiltinExchangeType.FANOUT);
String queueName = channel.queueDeclare().getQueue();
channel.queueBind(queueName, Constant.EXCHANGE_NAME, "");
channel.basicConsume(queueName, true, (consumerTag, message) -> {
System.out.println("DeliverCallback's consumerTag is {" + consumerTag + "}");
System.out.println("消费消息的内容 = " + new String(message.getBody()));
}, consumerTag -> System.out.println("CancelCallback's consumerTag is {" + consumerTag + "}"));
}
String queueName = channel.queueDeclare().getQueue();
声明了一个默认的队列。
通过channel.queueBind(queueName, Constant.EXCHANGE_NAME, "")
将队列绑定到交换机。这样,交换机收到消息就会分发给绑定的queueName
队列。任何与交换机EXCHANGE_NAME绑定的(FANOUT
类型)队列都会收到消息放入队列。