Using JMS

本指南演示了 Quarkus 应用程序如何通过 Apache Qpid JMS AMQP 客户端或 Apache ActiveMQ Artemis JMS 客户端来使用 JMS 消息传递。 :iokays-category: quarkus :iokays-path: modules/ROOT/pages/_includes/extension-status.adoc :keywords: Quarkus, 中文文档, 编程技术

该技术被认为是 {extension-status}。 有关可能状态的完整列表,请查看我们的 FAQ entry.

Prerequisites

include::./_includes/prerequisites.adoc[]* 正在运行的 Artemis 服务器或用于启动一个 Artemis 服务器的 Docker

Architecture

在此指南中,我们将在一个组件中生成(随机)价格。这些价格使用 JMS 客户端写入队列 (prices)。另一个组件从 `prices`队列中读取内容并存储最新价格。可以从浏览器中使用 Jakarta REST 资源中的获取按钮获取数据。

可以在下面按照详细说明操作,使用 Apache Qpid JMS AMQP 客户端来使用指南,或者在一些不同的配置中 (detailed later) 指定 Apache ActiveMQ Artemis JMS 客户端。

Qpid JMS - AMQP

在以下详细步骤中,我们将通过 Quarkus Qpid JMS extension使用 Apache Qpid JMS客户端。Qpid JMS 将 AMQP 1.0 ISO 标准用作其传输协议,使其可以与各种 AMQP 1.0 服务器和服务(如 ActiveMQ Artemis、ActiveMQ 5、Qpid Broker-J、Qpid Dispatch 路由器、Azure 服务总线等)一起使用。

Solution

我们建议您遵循接下来的部分中的说明,按部就班地创建应用程序。然而,您可以直接跳到完成的示例。

克隆 Git 存储库: git clone [role="bare"]https://github.com/amqphub/quarkus-qpid-jms-quickstart.git,或下载 archive.

Creating the Maven Project

首先,我们需要一个新项目。使用以下命令创建一个新项目:

CLI
quarkus create app {create-app-group-id}:{create-app-artifact-id} \
    --no-code
cd {create-app-artifact-id}

要创建一个 Gradle 项目,添加 --gradle--gradle-kotlin-dsl 选项。 有关如何安装和使用 Quarkus CLI 的详细信息,请参见 Quarkus CLI 指南。

Maven
mvn {quarkus-platform-groupid}:quarkus-maven-plugin:{quarkus-version}:create \
    -DprojectGroupId={create-app-group-id} \
    -DprojectArtifactId={create-app-artifact-id} \
    -DnoCode
cd {create-app-artifact-id}

要创建一个 Gradle 项目,添加 -DbuildTool=gradle-DbuildTool=gradle-kotlin-dsl 选项。

适用于 Windows 用户:

  • 如果使用 cmd,(不要使用反斜杠 \ ,并将所有内容放在同一行上)

  • 如果使用 Powershell,将 -D 参数用双引号引起来,例如 "-DprojectArtifactId={create-app-artifact-id}"

此命令生成导入 quarkus-qpid-jms 扩展的新项目:

pom.xml
<dependency>
    <groupId>org.amqphub.quarkus</groupId>
    <artifactId>quarkus-qpid-jms</artifactId>
</dependency>
build.gradle
implementation("org.amqphub.quarkus:quarkus-qpid-jms")

Starting the broker

接下来,我们需要一个 AMQP 代理。在此情况下,我们将使用 Apache ActiveMQ Artemis 服务器。您可以按照 Apache Artemis website中的说明操作,或使用 ArtemisCloud容器映像通过 docker 启动代理:

docker run -it --rm -p 8161:8161 -p 61616:61616 -p 5672:5672 -e AMQ_USER=quarkus -e AMQ_PASSWORD=quarkus quay.io/artemiscloud/activemq-artemis-broker:1.0.25

The price producer

创建 `src/main/java/org/acme/jms/PriceProducer.java`文件,其内容如下:

package org.acme.jms;

import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.jms.ConnectionFactory;
import jakarta.jms.JMSContext;

import io.quarkus.runtime.ShutdownEvent;
import io.quarkus.runtime.StartupEvent;

/**
 * A bean producing random prices every 5 seconds and sending them to the prices JMS queue.
 */
@ApplicationScoped
public class PriceProducer implements Runnable {

    @Inject
    ConnectionFactory connectionFactory;

    private final Random random = new Random();
    private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();

    void onStart(@Observes StartupEvent ev) {
        scheduler.scheduleWithFixedDelay(this, 0L, 5L, TimeUnit.SECONDS);
    }

    void onStop(@Observes ShutdownEvent ev) {
        scheduler.shutdown();
    }

    @Override
    public void run() {
        try (JMSContext context = connectionFactory.createContext(JMSContext.AUTO_ACKNOWLEDGE)) {
            context.createProducer().send(context.createQueue("prices"), Integer.toString(random.nextInt(100)));
        }
    }
}

The price consumer

价格使用者从 JMS 中读取价格并存储最后一个价格。使用以下内容创建 `src/main/java/org/acme/jms/PriceConsumer.java`文件:

package org.acme.jms;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;
import jakarta.inject.Inject;
import jakarta.jms.ConnectionFactory;
import jakarta.jms.JMSConsumer;
import jakarta.jms.JMSContext;
import jakarta.jms.JMSException;
import jakarta.jms.Message;

import io.quarkus.runtime.ShutdownEvent;
import io.quarkus.runtime.StartupEvent;

/**
 * A bean consuming prices from the JMS queue.
 */
@ApplicationScoped
public class PriceConsumer implements Runnable {

    @Inject
    ConnectionFactory connectionFactory;

    private final ExecutorService scheduler = Executors.newSingleThreadExecutor();

    private volatile String lastPrice;

    public String getLastPrice() {
        return lastPrice;
    }

    void onStart(@Observes StartupEvent ev) {
        scheduler.submit(this);
    }

    void onStop(@Observes ShutdownEvent ev) {
        scheduler.shutdown();
    }

    @Override
    public void run() {
        try (JMSContext context = connectionFactory.createContext(JMSContext.AUTO_ACKNOWLEDGE)) {
            JMSConsumer consumer = context.createConsumer(context.createQueue("prices"));
            while (true) {
                Message message = consumer.receive();
                if (message == null) return;
                lastPrice = message.getBody(String.class);
            }
        } catch (JMSException e) {
            throw new RuntimeException(e);
        }
    }
}

The price resource

最后,让我们创建一个简单的 Jakarta REST 资源来显示最后一个价格。使用以下内容创建 `src/main/java/org/acme/jms/PriceResource.java`文件:

package org.acme.jms;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

/**
 * A simple resource showing the last price.
 */
@Path("/prices")
public class PriceResource {

    @Inject
    PriceConsumer consumer;

    @GET
    @Path("last")
    @Produces(MediaType.TEXT_PLAIN)
    public String last() {
        return consumer.getLastPrice();
    }
}

The HTML page

最后一步,使用 SSE 读取已转换价格的 HTML 页面。

创建 `src/main/resources/META-INF/resources/prices.html`文件,其内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Prices</title>

    <link rel="stylesheet" type="text/css"
          href="https://cdnjs.cloudflare.com/ajax/libs/patternfly/3.24.0/css/patternfly.min.css">
    <link rel="stylesheet" type="text/css"
          href="https://cdnjs.cloudflare.com/ajax/libs/patternfly/3.24.0/css/patternfly-additions.min.css">
</head>
<body>
<div class="container">

    <h2>Last price</h2>
    <div class="row">
    <p class="col-md-12"><button id="fetch">Fetch</button>The last price is <strong><span id="content">N/A</span> €</strong>.</p>
    </div>
</div>
</body>
<script>
    document.getElementById("fetch").addEventListener("click", function() {
        fetch("/prices/last").then(function (response) {
            response.text().then(function (text) {
                document.getElementById("content").textContent = text;
            })
        })
    })
</script>
</html>

没有特别之处。在每次读取时,它都会更新页面。

Configure the Qpid JMS properties

我们需要在注入 ConnectionFactory 时配置扩展使用的 Qpid JMS 属性。

它是在 `src/main/resources/application.properties`文件中完成的。

# Configures the Qpid JMS properties.
quarkus.qpid-jms.url=amqp://localhost:5672
quarkus.qpid-jms.username=quarkus
quarkus.qpid-jms.password=quarkus

有关配置的更多详细信息,请参阅 Quarkus Qpid JMS 文档中。

Get it running

如果您按照了说明,那么应该已经启动了 Artemis 服务器。接下来,您只需使用以下命令运行应用程序:

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

在浏览器中打开 http://localhost:8080/prices.html

Running Native

您可以通过以下命令构建原生可执行文件:

CLI
quarkus build --native
Maven
./mvnw install -Dnative
Gradle
./gradlew build -Dquarkus.native.enabled=true

或者,如果您没有安装 GraalVM,则可以使用 Docker 来构建原生可执行文件:

CLI
quarkus build --native --no-tests -Dquarkus.native.container-build=true
# The --no-tests flag is required only on Windows and macOS.
Maven
./mvnw install -Dnative -DskipTests -Dquarkus.native.container-build=true
Gradle
./gradlew build -Dquarkus.native.enabled=true -Dquarkus.native.container-build=true

然后通过以下命令运行:

./target/jms-quickstart-1.0.0-SNAPSHOT-runner

在浏览器中打开 http://localhost:8080/prices.html

Artemis JMS

上述步骤使用 Qpid JMS AMQP 客户端进行了详细说明,但是指南也可以与 Artemis JMS 客户端一起使用。许多单个步骤与之前 detailed above for Qpid JMS 中的步骤完全相同。各个组件代码也是相同的。唯一的区别在于初始项目创建的依赖项,以及所使用的配置属性。这些更改将在下面进行详细说明,应当替换上述序列中的等效步骤。

Solution

您可以直接转到完成的示例。

克隆 Git 存储库: git clone $${quickstarts-base-url}.git,或下载 $${quickstarts-base-url}/archive/main.zip[存档]。

Artemis JMS 解决方案位于 jms-quickstart directory 中。

Creating the Maven Project

使用以下命令创建一个新项目:

CLI
quarkus create app {create-app-group-id}:{create-app-artifact-id} \
    --no-code
cd {create-app-artifact-id}

要创建一个 Gradle 项目,添加 --gradle--gradle-kotlin-dsl 选项。 有关如何安装和使用 Quarkus CLI 的详细信息,请参见 Quarkus CLI 指南。

Maven
mvn {quarkus-platform-groupid}:quarkus-maven-plugin:{quarkus-version}:create \
    -DprojectGroupId={create-app-group-id} \
    -DprojectArtifactId={create-app-artifact-id} \
    -DnoCode
cd {create-app-artifact-id}

要创建一个 Gradle 项目,添加 -DbuildTool=gradle-DbuildTool=gradle-kotlin-dsl 选项。

适用于 Windows 用户:

  • 如果使用 cmd,(不要使用反斜杠 \ ,并将所有内容放在同一行上)

  • 如果使用 Powershell,将 -D 参数用双引号引起来,例如 "-DprojectArtifactId={create-app-artifact-id}"

这将创建一个导入 quarkus-artemis-jms 扩展的新项目:

pom.xml
<dependency>
    <groupId>io.quarkiverse.artemis</groupId>
    <artifactId>quarkus-artemis-jms</artifactId>
</dependency>
build.gradle
implementation("io.quarkiverse.artemis:quarkus-artemis-jms")

创建完项目后,您可以从上面详细步骤中的 Starting the broker 处继续开始,一直进行到配置 application.properties 文件,此时您应使用以下 Artemis 配置作为替代。

Configure the Artemis properties

我们需要配置 Artemis 连接属性。这将在 src/main/resources/application.properties 文件中完成。

# Configures the Artemis properties.
quarkus.artemis.url=tcp://localhost:61616
quarkus.artemis.username=quarkus
quarkus.artemis.password=quarkus

配置完 Artemis 属性后,您可以在 Get it running 处继续上述步骤。

Configuration Reference

要详细了解如何配置 Artemis JMS 客户端,请参阅 the documentation of the extension