如何在Scala中通过RabbitMQ进行通信

152 阅读4分钟

RabbitMQ 简介

在这篇文章中,我们将看到如何将 RabbitMQ 与 Scala 集成。首先,我们将简要讨论什么是 RabbitMQ,然后我们将快速进入我们在应用程序中使用 RabbitMQ 所需的步骤。

首先,什么是 RabbitMQ?

RabbitMQ 是一个消息代理,它有助于在微服务之间进行通信。随着微服务架构在应用程序开发中的使用越来越多,对 RabbitMQ 等消息代理的依赖程度也越来越高。

消息代理在两个微服务之间充当中间人。一个微服务向经纪人发送一个消息,然后经纪人将其发送给可能正在等待该消息的其他微服务。

这有助于我们开发具有异步性和弹性的应用程序。

将 RabbitMQ 与 Scala 集成

我们需要遵循几个步骤,在 Scala 中创建一个 RabbitMQ 生产者和消费者。

  1. 添加所需的依赖项
  2. 与 RabbitMQ 建立连接
  3. 使用获得的连接创建一个通道
  4. 声明队列,发布者将在该队列上发布消息,而消费者将消费消息。
  5. 在发布者的情况下发布消息,在消费者的情况下消费消息。
  6. 对于消费者来说,还需要一个额外的步骤,即在收到消息时创建一个回调。

添加依赖项

在你的文件中添加以下依赖关系 build.sbt 文件中添加以下依赖关系

libraryDependencies += "com.rabbitmq" % "amqp-client" % "5.14.2"

创建一个 RabbitMQ 连接

我们使用软件包中的ConnectionFactorycom.rabbitmq.client来创建一个连接。然后我们可以根据需要设置用户名和密码。

最后,我们调用*newConnection()*方法来建立一个连接。

  def getConnection: Try[Connection] = Try {

    val connectionFactory: ConnectionFactory = new ConnectionFactory()

    connectionFactory.setUsername("admin")

    connectionFactory.setPassword("password")

    connectionFactory.newConnection()

  }

创建通道

我们可以把通道看作是单个 TCP 连接上的轻量级连接。打开多个连接到代理是不明智的,因为它们是资源密集型的。

相反,我们在包内有一个Channel接口 com.rabbitmq.client包内有一个通道接口。通道不能独立于连接而存在,它是通过连接建立的。

当我们关闭连接时,所有相关的通道都会自动关闭。

def initializeConnection(): Try[Channel] = {

    // Get the Connection

    val rabbitMQConnection: Try[Connection] = RabbitMQConnection.getConnection  

    // Create Channel if connection is successfully established

    val connectionChannel: Try[Channel] = rabbitMQConnection match {

      case Failure(exception) =>

        logger.error("Could not establish connection with RabbitMQ")

        throw new Exception(exception.getMessage)

      case Success(connection) => Try(connection.createChannel())

    }

    connectionChannel
}

声明 RabbitMQ 队列

我们用下面的方法声明队列 queueDeclare方法声明队列。该方法将队列的名称作为一个参数。

channel.queueDeclare("greet", false, false, false, null)

第一个参数是队列的名称。

第二个参数是一个布尔值,表示该队列是否会在服务器重新启动后继续存在。

第三个参数表示该队列是否是一个排他性队列,即它被限制在该特定的连接中。

第四个参数表示如果不再使用该队列,服务器是否会删除它。

第五个参数是向队列传递额外的属性

发布/消耗消息

// To pusblish a message

channel.basicPublish("", "greet", null, message.getBytes(StandardCharsets.UTF_8)) 

// To consume a message

channel.basicConsume("greet", true, "", deliverCallback, cancelCallback)


basicPublishmethod需要以下参数:

  1. 交易所的名称。我们可以把交易所看成是一个邮差。它决定哪条消息将被送到哪个队列。为了简单起见,我们将使用一个交换系统将消息路由到我们作为参数传递的队列的名称。
  2. routingKey。它是帮助交换系统决定我们应该把消息发送到哪个队列的routingKey。
  3. 道具(props)。消息的其他属性,如路由头等。
  4. body。消息的主体

basicConsumemethod 需要以下参数:

  1. queue。队列的名称
  2. autoAck:如果为真,则服务器不需要明确的确认。
  3. consumerTag:客户端生成一个消费者标签以建立上下文。
  4. deliverCallback:消息到达消费者时的回调。
  5. cancelCallback。回调接口,在消费者被取消时被通知。

为消费者创建回调

// Callback in case the message is delivered

val deliverCallback: DeliverCallback = (consumerTag: String, message: 

Delivery) => 

{

    val messageBody = new String(message.getBody, "UTF-8")

    logger.info(s"[x] Received '$messageBody'")

  }

// Callback in case the consumer is cancelled

val cancelCallback: CancelCallback = (consumerTag: String) => 

logger.info("Cancelled")

结论

在遵循上述所有步骤后,我们将成功创建一个简单的生产者和消费者应用程序,该应用程序通过向 RabbitMQ 代理传递消息进行通信。