rabbitmq入门-发布与订阅

发布/订阅:分发一个消息给多个消费者(consumers)接收一个生产者生产的消息

交换器(Exchanges)

rabbitmq完整的消息模型

  • 发布者(producer)是发布消息的应用程序。
  • 队列(queue)用于消息存储的缓冲。
  • 消费者(consumer)是接收消息的应用程序。

  RabbitMQ消息模型的核心理念是:发布者(producer)不会直接发送任何消息给队列。事实上,发布者(producer)甚至不知道消息是否已经被投递到队列。

发布者(producer)只需要把消息发送给一个交换器(exchange)。交换器非常简单,它一边从发布者方接收消息,一边把消息推入队列。交换器必须知道如何处理它接收到的消息,是应该推送到指定的队列还是是多个队列,或者是直接忽略消息。这些规则是通过exchange type来定义的。

有几个可供选择的交换器类型:directtopicheaders和 fanout

 

创建一个fanout类型的交换器,命名为logs

channel.exchangeDeclare(EXCHANGE_NAME, "fanout");

 fanout交换器很简单,从名字上就能猜测出来,它把消息发送给它所知道的所有队列。

交换器列表

rabbitmqctl能够列出服务器上所有的交换器:

rabbitmqctl list_exchanges

Listing exchanges ...
        direct
amq.direct      direct
amq.fanout      fanout
amq.headers     headers
amq.match       headers
amq.rabbitmq.log        topic
amq.rabbitmq.trace      topic
amq.topic       topic
...done.

 这个列表中有一些叫做amq.*的交换器。这些都是默认创建的,不过这时候你还不需要使用他们。

匿名的交换器

 

我们对交换器一无所知,但仍然能够发送消息到队列中。因为使用了命名为空字符串("")默认的交换器。

 

之前是如何发布一则消息:

 

channel.basicPublish("", "hello", null, message.getBytes());

exchange参数就是交换器的名称。空字符串代表默认或者匿名交换器:消息将会根据指定的routing_key分发到指定的队列。

发送消息到一个具名交换器了:

channel.basicPublish( "logs", "", null, message.getBytes());

临时队列

一个消息同时分发给多个消费者,需要指定exchange名称,另外,当我们连接上RabbitMQ的时候,我们需要一个全新的、空的队列。我们可以手动创建一个随机的队列名,或者让服务器为我们选择一个随机的队列名(推荐)。我们只要在调用queue_declare方法的时候,不提供queue参数就可以了:

String queueName = channel.queueDeclare().getQueue();

绑定

已经创建了一个fanout类型的交换器和一个队列。现在我们需要告诉交换器如何发送消息给我们的队列。交换器和队列之间的关系我们称之为绑定(binding)

channel.queueBind(queueName, "logs", "");

 logs交换器将会把消息添加到我们的队列中logs交换器将会把消息添加到我们的队列中

使用rabbitmqctl list_bindings队列出所有存在的绑定

生产者代码

public class EmitLog {
	private static final String EXCHANGE_NAME = "logs";

	public static void main(String[] argv) throws java.io.IOException {

		ConnectionFactory factory = new ConnectionFactory();
		factory.setHost("localhost");
		Connection connection = factory.newConnection();
		Channel channel = connection.createChannel();

		channel.exchangeDeclare(EXCHANGE_NAME, "fanout");

		String message = getMessage(argv);

		channel.basicPublish(EXCHANGE_NAME, "", null, message.getBytes());
		System.out.println(" [x] Sent '" + message + "'");

		channel.close();
		connection.close();
	}

	private static String getMessage(String[] strings){
        if (strings.length < 1)
            return "Hello World!";
        return joinStrings(strings, " ");
    }
    
    private static String joinStrings(String[] strings, String delimiter) {
        int length = strings.length;
        if (length == 0) return "";
        StringBuilder words = new StringBuilder(strings[0]);
        for (int i = 1; i < length; i++) {
            words.append(delimiter).append(strings[i]);
        }
        return words.toString();
    }
}

 消费者代码

public class ReceiveLogs {
	private final static String EXCHANGE_NAME = "logs";
	
	public static void main(String[] args) throws IOException, ShutdownSignalException, ConsumerCancelledException, InterruptedException {
		ConnectionFactory factory = new ConnectionFactory();
		factory.setHost("localhost");
		Connection connection = factory.newConnection();
		Channel channel = connection.createChannel();
		channel.exchangeDeclare(EXCHANGE_NAME,"fanout");
		String queueName = channel.queueDeclare().getQueue();
		channel.queueBind(queueName, EXCHANGE_NAME, "");
		System.out.println(" [*] Waiting for messages. To exit press CTRL+C");

        QueueingConsumer consumer = new QueueingConsumer(channel);
        channel.basicConsume(queueName, true, consumer);

        while (true) {
            QueueingConsumer.Delivery delivery = consumer.nextDelivery();
            String message = new String(delivery.getBody());

            System.out.println(" [x] Received '" + message + "'");
        }
	}
}

 查看banding的exchange

Listing bindings ...
        exchange        amq.gen-zKK_8tEJV79W5r1twM87lg  queue   amq.gen-zKK_8
V79W5r1twM87lg  []
        exchange        hello   queue   hello   []
logs    exchange        amq.gen-zKK_8tEJV79W5r1twM87lg  queue           []
...done.

 

猜你喜欢

转载自yugouai.iteye.com/blog/1969216