RabbitMQ指南(二) 基本概念和开发

2.1 基本概念

  下图是RabbitMQ的基本模型,模型中包括以下部分:生产者、交换机、队列和消费者。
  生产者产生消息,并将消息发送至交换机,交换机根据一定的路由规则将消息发送至一个或多个消息队列中,消息的消费者从相应的消息队列中取数据,进行处理。
  其中,交换机和队列位于RabbitMQ服务端,生产者和消费者属于RabbitMQ的客户端。
RabbitMQ基本模型
  RabbitMQ的客户端建立与服务端的Socket长连接(Connection),并在其上建立轻量级的连接——信道(Channel),大部分的业务操作是在信道中进行的。有文章有形象的比喻:若连接是一根光缆,则信道就是光缆中的光纤。
  RabbitMQ安装部署完毕,会已经创建好一些交换机,进入Web管理界面->Exchanges页签,可看到下图这些默认创建的交换机:
默认创建的交换机
  其中,默认交换机“(AMQP default)”最为特殊,它的名字是一个空字符串(””),不能被删除。所有创建的队列都会与之连接(称为“绑定”),且不能解绑。绑定使用的路由键(Routing Key)即为队列的名称。
  本节的基本内容,即创建一个消息的发送方(生产者)、接收方(消费者)和与默认交换机绑定的队列,发送方通过默认交换机向该队列中发送一条消息,接收方从该队列中取出消息。
  RabbitMQ支持多种编程语言的客户端,本文主要使用Java、C#和Python。在开发之前,需要做一定的准备工作。

2.2 Java开发

2.2.1 准备工作

  新建一个Maven项目,对于Java程序,需引入RabbitMQ客户端所需的jar包。包括RabbitMQ客户端的jar包(本文版本5.4.3),以及日志所需的jar包(缺少该包会报错):

	<dependencies>
		<dependency>
			<groupId>com.rabbitmq</groupId>
			<artifactId>amqp-client</artifactId>
			<version>5.4.3</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-nop</artifactId>
			<version>1.7.25</version>
		</dependency>
	</dependencies>

2.2.2 发送方

  消息发送方的代码如下。发送方创建一个名为“Queue_Java”的队列,并向其中发送消息“This is Java’s message”:

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;


public class Sender {

	// RabbitMQ服务端地址
	private static final String ADDRESS = "10.176.65.172";
	// RabbitMQ默认监听端口为5672
	private static final int PORT = 5672;
	// 使用第一章创建的用户mqtester进行登录
	private static final String USERNAME = "mqtester";
	private static final String PASSWORD = "mqtester";
	// 默认交换机的名字为空字符串
	private static final String DEFAULT_EXCHANGE = "";
	// 所要创建的队列名称
	private static final String QUEUE_NAME = "Queue_Java";


	public static void main(String[] args) throws Exception {
		// 1.创建工厂类,设置服务端的地址、端口、用户名和密码
		ConnectionFactory factory = new ConnectionFactory();
		factory.setHost(ADDRESS);
		factory.setPort(PORT);
		factory.setUsername(USERNAME);
		factory.setPassword(PASSWORD);
		// 2.建立连接
		Connection connection = factory.newConnection();
		// 3.建立信道
		Channel channel = connection.createChannel();
		// 4.声明队列,该操作是幂等的,如果队列不存在则创建队列
		channel.queueDeclare(QUEUE_NAME, false, false, false, null);
		// 5.发送消息
		byte[] message = "This is Java's message".getBytes();
		channel.basicPublish(DEFAULT_EXCHANGE, QUEUE_NAME, null, message);
		// 6.关闭连接
		channel.close();
		connection.close();
	}
}

  为简洁起见,程序直接在主方法上抛出异常,实际使用时应当以try…catch…块处理异常。
  从代码中可以看到,发送消息最后调用的是Channel类的basicPublish方法,该方法第一个参数为交换机的名称,第二个参数为路由键,第四个参数为所要发送的消息(以字节数组形式)。前文提到,默认交换机与队列绑定的路由键即为队列名称,故程序中以队列名称作为路由键入参,即可将消息发送至声明的队列中。
  运行该段代码后,进入RabbitMQ的Web管理页面->Queues页签,可看到出现了创建的队列“Queue_Java”,并且该队列中有1条消息:
Java队列创建
  点击该队列名称,进入该队列的管理界面,在“Get Messages”下拉框中,点击获取消息“Get Message(s)”按键,可以看到这条消息就是程序发送的消息“This is Java’s message”:
Java消息发送

2.2.3 接收方

  接收方建立连接、信道、声明队列的过程与发送方相同。RabbitMQ服务端的队列收到消息后,异步将消息推送给消费者,故消费者通过回调方法处理接收到的消息。接收方代码如下:

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.Consumer;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.Envelope;


public class Reciver {

	private static final String ADDRESS = "10.176.65.172";
	private static final int PORT = 5672;
	private static final String QUEUE_NAME = "Queue_Java";
	private static final String USERNAME = "mqtester";
	private static final String PASSWORD = "mqtester";


	public static void main(String[] args) throws Exception {
		// 1.创建工厂类,设置服务端地址、端口、用户名和密码
		ConnectionFactory factory = new ConnectionFactory();
		factory.setHost(ADDRESS);
		factory.setPort(PORT);
		factory.setUsername(USERNAME);
		factory.setPassword(PASSWORD);
		// 2.建立连接
		Connection connection = factory.newConnection();
		// 3.建立信道
		Channel channel = connection.createChannel();
		// 4.声明队列
		channel.queueDeclare(QUEUE_NAME, true, false, false, null);
		// 5.创建消费者,从队列中消费消息
		Consumer consumer = new DefaultConsumer(channel) {

			@Override
			public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
				String message = new String(body);
				System.out.println("Received: " + message);
			}
		};
		channel.basicConsume(QUEUE_NAME, true, consumer);
	}
}

  在运行basicConsume()方法后,消费者开始监听队列,队列中有消息时,将回调消费者重写的handleDelivery()方法。运行该程序,可以看到控制台打印出生产者发送的“This is Java’s message”消息。再次查看Web管理端的队列,可看到队列Queue_Java中的消息数变为0了,之前发送的消息已经被消费:
Java消息消费

2.3 C#开发

2.3.1 准备工作

  下载RabbitMQ客户端C#版本,下载地址:
  http://www.rabbitmq.com/releases/rabbitmq-dotnet-client
  版本:rabbitmq-dotnet-client-3.6.14-dotnet-4.5.zip
  压缩包中bin/RabbitMQ.Client.dll是C#开发需要的动态链接库文件。在Visual Studio中新建C#控制台程序,在项目的引用中添加RabbitMQ.Client.dll。
C#添加引用

2.3.2 发送方

  C#版本的发送方代码与Java流程相同,由于C#有using关键字,省去了关闭连接的代码。如下:

using RabbitMQ.Client;
using System;
using System.Text;

namespace RabbitMQDemoCSharp
{
    public class Sender
    {
        // RabbitMQ服务端地址
        private const string ADDRESS = "10.176.65.227";
        // RabbitMQ默认监听端口为5672
        private const int PORT = 5672;
        // 使用第一章创建的用户mqtester进行登录
        private const string USERNAME = "mqtester";
        private const string PASSWORD = "mqtester";
        // 默认交换机的名字为空字符串
        private const string DEFAULT_EXCHANGE = "";
        // 所要创建的队列名称
        private const string QUEUE_NAME = "Queue_C#";

        public static void Main(string[] args)
        {
            // 1.创建工厂类,设置服务端地址、端口、用户名和密码
            var factory = new ConnectionFactory()
            {
                HostName = ADDRESS,
                Port = PORT,
                UserName = USERNAME,
                Password = PASSWORD
            };
            // 2.建立连接
            using (var connection = factory.CreateConnection())
            {
                // 3.建立信道
                using (var channel = connection.CreateModel())
                {
                    // 4.声明队列
                    channel.QueueDeclare(queue: QUEUE_NAME,
                                 durable: false,
                                 exclusive: false,
                                 autoDelete: false,
                                 arguments: null);
                    // 5.发送消息
                    byte[] message = Encoding.UTF8.GetBytes("This is C#'s message");
                    channel.BasicPublish(exchange: DEFAULT_EXCHANGE,
                                 routingKey: QUEUE_NAME,
                                 basicProperties: null,
                                 body: message);
                }
                Console.ReadLine();
            }
        }
    }
}

2.3.3 接收方

using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System;
using System.Text;

namespace RabbitMQDemoCSharp
{
    public class Receiver
    {
        private const string ADDRESS = "10.176.65.182";
        private const int PORT = 5672;
        private const string USERNAME = "mqtester";
        private const string PASSWORD = "mqtester";
        private const string QUEUE_NAME = "Queue_C#";

        public static void Main(string[] args)
        {
            // 1.创建工厂类,设置服务端地址、端口、用户名和密码
            var factory = new ConnectionFactory()
            {
                HostName = ADDRESS,
                Port = PORT,
                UserName = USERNAME,
                Password = PASSWORD
            };
            // 2.建立连接
            using (var connection = factory.CreateConnection())
            {
                // 3.建立信道
                using (var channel = connection.CreateModel())
                {
                    // 4.声明队列
                    channel.QueueDeclare(queue: QUEUE_NAME,
                                 durable: false,
                                 exclusive: false,
                                 autoDelete: false,
                                 arguments: null);
                    // 5.创建消费者,接收消息
                    var consumer = new EventingBasicConsumer(channel);
                    consumer.Received += (model, ea) =>
                    {
                        var message = Encoding.UTF8.GetString(ea.Body);
                        Console.WriteLine("Received: " + message);
                    };
                    channel.BasicConsume(queue: QUEUE_NAME,
                                         noAck: true,
                                         consumer: consumer);
                    Console.ReadLine();
                }
            }
        }
    }
}

2.4 Python开发

2.4.1 准备工作

  使用pip命令安装pika包:

pip install pika

2.4.2 发送方

import pika

# RabbitMQ服务端地址
ADDRESS = '10.176.65.172'
# RabbitMQ默认监听端口为5672
PORT = 5672
# 使用第一章创建的用户mqtester进行登录
USERNAME = 'mqtester'
PASSWORD = 'mqtester'
# 默认交换机的名字为空字符串
DEFAULT_EXCHANGE = ''
# 所要创建的队列名称
QUEUE_NAME = 'Queue_Python'

# 1.设置服务端地址、端口、用户名和密码
credentials = pika.PlainCredentials(username=USERNAME, password=PASSWORD)
# 2.建立连接
connection = pika.BlockingConnection(parameters=pika.ConnectionParameters(host=ADDRESS, port=PORT, credentials=credentials))
# 3.建立信道
channel = connection.channel()
# 4.声明队列
channel.queue_declare(queue=QUEUE_NAME, durable=False, exclusive=False, auto_delete=False, arguments=None)
# 5.发送消息
channel.basic_publish(exchange=DEFAULT_EXCHANGE, routing_key=QUEUE_NAME, body="This is Python's message")
# 6.关闭连接
channel.close()
connection.close()

2.4.3 接收方

import pika

# RabbitMQ服务端地址
ADDRESS = '10.176.65.172'
# RabbitMQ默认监听端口为5672
PORT = 5672
# 使用第一章创建的用户mqtester进行登录
USERNAME = 'mqtester'
PASSWORD = 'mqtester'
# 默认交换机的名字为空字符串
DEFAULT_EXCHANGE = ''
# 所要创建的队列名称
QUEUE_NAME = 'Queue_Python'

# 1.设置服务端地址、端口、用户名和密码
credentials = pika.PlainCredentials(username=USERNAME, password=PASSWORD)
# 2.建立连接
connection = pika.BlockingConnection(parameters=pika.ConnectionParameters(host=ADDRESS, port=PORT, credentials=credentials))
# 3.建立信道
channel = connection.channel()
# 4.声明队列
channel.queue_declare(queue=QUEUE_NAME, durable=False, exclusive=False, auto_delete=False, arguments=None)


# 5.定义回调方法,消费消息
def callback(ch, method, properties, body):
    print('Received: ' + body.decode('utf8'))


channel.basic_consume(consumer_callback=callback, queue=QUEUE_NAME, no_ack=True)
channel.start_consuming()

猜你喜欢

转载自blog.csdn.net/weixin_43533358/article/details/83511861