RabbitMQ消息队列(一)——Hello World例子

本文主要阐述 6个基本的消息发送/接收模型,或者称为6种不同的使用场景!

在学习6种模型之前,我们首先需要安装RabbitMQ。RabbitMQ支持多种系统平台,各平台的安装方法可以点此查看。安装好之后,我们使用如下命令启用Web端的管理插件:rabbitmq-plugins enable rabbitmq_management,然后启动RabbitMQ ( rabbitmq-server start)。接着用浏览器访问http://localhost:15672/,若能看到RabbitMQ相关Web页面,说明启动成功。

1.Hello World

正所谓万事开头难,我们先从最简单的Hello World开始。首先当然是新建一个项目,导入RabiitMQ相关jar。我采用Maven来构建项目,因此只需要在pom文件中添加如下依赖:

<!-- rabbitmq相关 -->
<dependency>
	<groupId>com.rabbitmq</groupId>
	<artifactId>amqp-client</artifactId>
	<version>5.1.2</version>
</dependency>

接下来学习最简单的消息队列模型,如下图:


在图中,P代表producer,它是消息的生产者C代表consumer,它是消息的消费者;而红色的矩形正是我们所谓的消息队列,它位于RabbitMQ中(RabbitMQ中可以有很多这样的队列,并且每个队列都有一个唯一的名字)。生产者(们)可以将消息发送到消息队列中,消费者(们)可以从消息队列中取出消息。

这种模型是不是很简单呢?下面我们使用Java,借助于RabbitMQ来实现这种模型的消息通信。

首先我们介绍如何send消息到消息队列。send之前,当然是和RabbitMQ服务器建立连接:

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

接下来我们创建一个channel,大多数API都是通过这个对象来调用的:

Channel channel = connection.createChannel();

之后,我们便可以调用channel的如下方法去声明一个队列:

channel.queueDeclare("hello", false, false, false, null);

该方法的第一个参数是队列的名称,其余的参数先不管,之后会介绍。我们可以尝试着去执行以上的5行代码,然后打开Web端,可以看到新建了一个叫作hello的队列:


有了队列,我们便可以向其中发送消息了,同样还是调用channel对象的API:

channel.basicPublish("", "hello", null, "Hello World".getBytes());

以上代码所做的事情就是发送了一条字符串消息“Hello World”(第4个参数)到消息队列。你可能注意到我们调用了String对象的getBytes方法,没错,我们发送的实际上二进制数据。因此,理论上你能够发送任何数据到消息队列中,而不仅仅是文本信息。

第2个参数叫做路由键(routingKey),在该模型下必须与队列名相同,至于为什么,和其他参数一样,之后会了解到。

我们可以修改发送的文本,再次执行上述代码,然后打开Web端查看,便可以查看到我们发送的消息:

点击上图的name字段下的hello,可以查看hello队列中的具体信息:


接下来,我们去尝试着去获取生产者发送的消息,和send方法一样,我们同样需要连接服务器,创建channel,声明队列:

ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("hello", false, false, false, null);

之后我们可以调用channel的相关方法去监听队列,接收消息:

channel.basicConsume("hello", true, new DefaultConsumer(channel) {
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            System.out.println(new String(body, "UTF-8"));
        }
});

以上basicConsume方法中,第一个参数是队列的名字;第二个参数表示是否自动确认消息的接收情况,我们使用true,自动确认;第三个参数需要传入一个实现了Consumer接口的对象,我们简单的new一个默认的Consumer的实现类DefaultConsumer,然后在handleDelivery方法中去处理接收到的消息(handleDelivery方法会在接收到消息时被回调)。

运行以上代码,我们可以打印出之前向队列中send的数据:

Hello World
Hello World2

下面是Hello World的完整代码:

Producer:生产者
	public static void main(String[] args) throws Exception {
		// 创建链接工厂
		ConnectionFactory factory = new ConnectionFactory();
		// 默认链接的主机名,RabbitMQ-Server安装在本机,所以可以直接用127.0.0.1
		factory.setHost("127.0.0.1");
		// 创建链接
		Connection connection = factory.newConnection();
		// 创建信息管道
		Channel channel = connection.createChannel();
		// 创建一个名为queue01的队列,防止队列不存在
		String queueName = "queue01";
		// 进行信息声明 1.队列名2.是否持久化,3是否局限与链接,4不再使用是否删除,5其他的属性
		channel.queueDeclare(queueName, false, false, false, null);
		String msg = "Hello World!";

		// 发送消息
		// 在RabbitMQ中,消息是不能直接发送到队列,它需要发送到交换器(exchange)中。
		// 第一参数空表示使用默认exchange,第二参数表示路由键(routingKey)在该模型下必须与队列名相同,第四参数是发送的消息是(字节数组)
		channel.basicPublish("", queueName, null, msg.getBytes());

		System.out.println("发送  message[" + msg + "] to " + queueName + " success!");

		// 关闭管道
		channel.close();
		// 关闭连接
		connection.close();
	}

Customer:消费者
public static void main(String[] args) throws Exception {
		// 创建链接工厂
		ConnectionFactory factory = new ConnectionFactory();
		// 默认链接的主机名,RabbitMQ-Server安装在本机,所以可以直接用127.0.0.1
		factory.setHost("127.0.0.1");
		// 创建链接
		Connection connection = factory.newConnection();
		// 创建信息管道
		Channel channel = connection.createChannel();
		// 创建一个名为queue01的队列,防止队列不存在
		String queueName = "queue01";
		// 进行信息声明 1.队列名2.是否持久化,3是否局限与链接,4不再使用是否删除,5其他的属性
		channel.queueDeclare(queueName, false, false, false, null);

		// ---------------------上面代码和Producer 是一样-------------------------
		// 声明一个消费者,配置好获取消息的方式
		/**
		 * queue:队列名
		 * autoAck:是否自动ack,如果不自动ack,需要使用channel.ack、channel.nack、channel
		 * .basicReject 进行消息应答
		 */
		channel.basicConsume(queueName, false, new DefaultConsumer(channel) {
			@Override
			public void handleDelivery(String consumerTag, Envelope envelope, BasicProperties properties, byte[] body)
					throws IOException {
				String routingKey = envelope.getRoutingKey();
				long deliveryTag = envelope.getDeliveryTag();
				System.out.println("routingKey:" + routingKey + ",deliveryTag:" + deliveryTag);
				System.out.println("----msg------" + new String(body, "UTF-8"));
				try {
					Thread.sleep(10000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				// 消息确认
				/**
				 * deliveryTag:该消息的index
				 * multiple:是否批量.true:将一次性ack所有小于deliveryTag的消息
				 */
				channel.basicAck(deliveryTag, false);
			}

		});
	}

 

猜你喜欢

转载自blog.csdn.net/qq994406030/article/details/79926632
今日推荐