编辑此页面

使用 JMS

本指南演示了您的Quarkus应用程序如何通过Apache Qpid JMS AMQP客户端或Apache ActiveMQ Artemis JMS客户端使用JMS消息传递。

此技术被认为是预览版。

预览版中,不保证向后兼容性和在生态系统中的存在。特定改进可能需要更改配置或API,并且正计划成为稳定版。欢迎在我们的邮件列表或我们的GitHub问题跟踪器上提出问题并提供反馈。

有关可能的完整状态列表,请查看我们的常见问题解答条目

先决条件

要完成本指南,您需要

  • 大约 15 分钟

  • 一个 IDE

  • 已安装 JDK 17+ 并正确配置了 JAVA_HOME

  • Apache Maven 3.9.9

  • 如果您想使用它,可以选择 Quarkus CLI

  • 如果您想构建本机可执行文件(或者如果您使用本机容器构建,则为 Docker),可以选择安装 Mandrel 或 GraalVM 并进行适当的配置

  • 一个正在运行的Artemis服务器,或用于启动一个的Docker

架构

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

本指南可以通过Apache Qpid JMS AMQP客户端(如下文详述)或替代地通过Apache ActiveMQ Artemis JMS客户端(具有一些不同的配置,稍后详述)来使用。

Qpid JMS - AMQP

在下面的详细步骤中,我们将通过Quarkus Qpid JMS扩展使用Apache Qpid JMS客户端。Qpid JMS使用AMQP 1.0 ISO标准作为其线协议,允许它与各种AMQP 1.0服务器和服务一起使用,例如ActiveMQ Artemis、ActiveMQ 5、Qpid Broker-J、Qpid Dispatch路由器、Azure Service Bus等。

解决方案

我们建议您按照以下章节中的说明,逐步创建应用程序。但是,您可以直接转到完整的示例。

克隆Git存储库:git clone https://github.com/amqphub/quarkus-qpid-jms-quickstart.git,或下载一个存档

创建 Maven 项目

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

CLI
quarkus create app org.acme:jms-quickstart \
    --extension='rest,qpid-jms' \
    --no-code
cd jms-quickstart

要创建 Gradle 项目,请添加 --gradle--gradle-kotlin-dsl 选项。

有关如何安装和使用 Quarkus CLI 的更多信息,请参阅 Quarkus CLI 指南。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.24.4:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=jms-quickstart \
    -Dextensions='rest,qpid-jms' \
    -DnoCode
cd jms-quickstart

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

对于 Windows 用户

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

  • 如果使用Powershell,请将-D参数用双引号括起来,例如"-DprojectArtifactId=jms-quickstart"

此命令生成一个导入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")

启动代理

然后,我们需要一个AMQP代理。在这种情况下,我们将使用Apache ActiveMQ Artemis服务器。您可以按照Apache Artemis网站上的说明进行操作,或使用Docker启动一个代理,使用ArtemisCloud容器镜像

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

价格生产者

创建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)));
        }
    }
}

价格消费者

价格消费者从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);
        }
    }
}

价格资源

最后,我们创建一个简单的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();
    }
}

HTML 页面

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

创建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>&nbsp;&euro;</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>

这里没什么特别的。每次获取时,它都会更新页面。

配置Qpid JMS属性

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

这在src/main/resources/application.properties文件中完成。

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

更多配置细节可在Quarkus Qpid JMS文档中找到。

开始运行

如果您按照说明进行操作,应该已经启动了Artemis服务器。然后,您只需使用以下命令运行应用程序

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

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

原生运行

您可以使用以下命令构建原生可执行文件

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

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


Artemis JMS

上述步骤详细介绍了使用Qpid JMS AMQP客户端,然而本指南也可以与Artemis JMS客户端一起使用。许多单独的步骤与上面为Qpid JMS详述的完全相同。各个组件的代码也相同。唯一的区别在于初始项目创建的依赖项以及使用的配置属性。这些更改将在下面详细说明,并应替换为上述顺序中的相应步骤。

解决方案

您可以直接查看已完成的示例。

克隆Git存储库:git clone https://github.com/quarkusio/quarkus-quickstarts.git,或下载一个存档

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

创建Maven项目

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

CLI
quarkus create app org.acme:jms-quickstart \
    --extension='rest,artemis-jms' \
    --no-code
cd jms-quickstart

要创建 Gradle 项目,请添加 --gradle--gradle-kotlin-dsl 选项。

有关如何安装和使用 Quarkus CLI 的更多信息,请参阅 Quarkus CLI 指南。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.24.4:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=jms-quickstart \
    -Dextensions='rest,artemis-jms' \
    -DnoCode
cd jms-quickstart

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

对于 Windows 用户

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

  • 如果使用Powershell,请将-D参数用双引号括起来,例如"-DprojectArtifactId=jms-quickstart"

这会创建一个导入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")

项目创建后,您可以从上面的详细步骤中的启动代理继续,直到配置application.properties文件,届时您应该使用下面的Artemis配置。

配置Artemis属性

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

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

配置完Artemis属性后,您可以从运行的步骤继续。

配置参考

要了解更多关于如何配置Artemis JMS客户端的信息,请查看扩展文档

相关内容