发布订阅模式:
- 每个消费者监听自己的队列。
- 生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收
- 此种模式在交换机和队列进行绑定时,我们不设置routingKey,即""空字符串。
Publish/Subscribe发布与订阅模式下,我们自己需要定义一个交换机,让信道与交换机之间进行绑定
交换机的模式有:Fanout:广播,Direct:定向,Topic:通配符,HEADERS(“headers”);参数匹配。我们这里使用Fanout:广播模式,即发送到交换机的消息,每个绑定在该交换机上的队列都将收到消息
生产者
public class Producer {
//0. Publish/Subscribe发布与订阅模式
public static void main(String[] args) throws Exception{
//1. 创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//2. 设置参数
connectionFactory.setHost("localhost");//ip 默认值 localhost
connectionFactory.setPort(5672);//端口 默认值 5672
connectionFactory.setUsername("guest");//用户名 默认 guest
connectionFactory.setPassword("guest");//密码 默认值 guest
connectionFactory.setVirtualHost("/");//虚拟机 默认值
//3. 创建连接 Connection
Connection connection = connectionFactory.newConnection();
//4. 创建Channel
Channel channel = connection.createChannel();
//5. 创建交换机,设置交换机模式为广播模式
String exchangeName = "test_fanout";
channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT, true, false, false, null);
//6. 创建队列Queue,因为可以多个队列绑定到一个交换机上
String queue1Name = "test_fanout_queue1";
String queue2Name = "test_fanout_queue2";
channel.queueDeclare(queue1Name, true, false, false, null);
channel.queueDeclare(queue2Name, true, false, false, null);
//7. 绑定队列和交换机,不设置路由规则
channel.queueBind(queue1Name, exchangeName, "");
channel.queueBind(queue2Name, exchangeName, "");
//8. 发布消息,不设置路由规则
String body = "你好;小兔子!";
channel.basicPublish(exchangeName, "", null, body.getBytes());
//9. 释放资源
channel.close();
connection.close();
}
}
/**
exchangeDeclare(String exchange, BuiltinExchangeType type, boolean durable, boolean autoDelete, boolean internal, Map<String, Object> arguments)
参数:
1. exchange:交换机名称
2. type:交换机类型
DIRECT("direct"),:定向
FANOUT("fanout"),:扇形(广播),发送消息到每一个与之绑定队列。
TOPIC("topic"),通配符的方式
HEADERS("headers");参数匹配
3. durable:是否持久化
4. autoDelete:自动删除
5. internal:内部使用。 一般false
6. arguments:参数
/
/**
queueBind(String queue, String exchange, String routingKey)
参数:
1. queue:队列名称
2. exchange:交换机名称
3. routingKey:路由键,绑定规则
如果交换机的类型为fanout ,routingKey设置为""
*/
注意:多个消费者,每个消费者可能绑定的队列都不同,我们要注意,此处我们只举例出一个消费者。
消费者
public class Consumer1 {
public static void main(String[] args) throws IOException, TimeoutException {
//1.创建连接工厂
ConnectionFactory connectionFactory = new ConnectionFactory();
//2. 设置参数
connectionFactory.setHost("localhost");//ip 默认值 localhost
connectionFactory.setPort(5672);//端口 默认值 5672
connectionFactory.setUsername("guest");//用户名 默认 guest
connectionFactory.setPassword("guest");//密码 默认值 guest
connectionFactory.setVirtualHost("/");//虚拟机 默认值
//3. 创建连接 Connection
Connection connection = connectionFactory.newConnection();
//4. 创建Channel
Channel channel = connection.createChannel();
//创建Consumer即可的消费者实现类DefaultConsumer,并写回调函数,打印队列中的信息
DefaultConsumer consumer = new DefaultConsumer(channel){
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("body:"+new String(body));
}
};
/**
basicConsume(String queue, boolean autoAck, Consumer callback)
参数:
1. queue:队列名称
2. autoAck:是否自动确认
3. callback:回调对象
*/
//5. 接收队列消息
String queue1Name = "test_fanout_queue1";//此队列名称必须在生产者对应交换机绑定的队列中能找得到。
channel.basicConsume(queue1Name, true, consumer);
}
}
发布订阅模式与工作队列模式的区别
1、工作队列模式不用定义交换机,而发布/订阅模式需要定义交换机。
2、发布/订阅模式的生产方是面向交换机发送消息,工作队列模式的生产方是面向队列发送消息(底层使用默认交换机)。
3、发布/订阅模式需要设置队列和交换机的绑定,工作队列模式不需要设置,实际上工作队列模式会将队列绑 定到默认的交换机 。