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
首先,我们需要一个新项目。使用以下命令创建一个新项目:
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 指南。
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 扩展的新项目:
<dependency>
<groupId>org.amqphub.quarkus</groupId>
<artifactId>quarkus-qpid-jms</artifactId>
</dependency>
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 服务器。接下来,您只需使用以下命令运行应用程序:
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
在浏览器中打开 http://localhost:8080/prices.html
。
Running Native
您可以通过以下命令构建原生可执行文件:
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.native.enabled=true
或者,如果您没有安装 GraalVM,则可以使用 Docker 来构建原生可执行文件:
quarkus build --native --no-tests -Dquarkus.native.container-build=true
# The --no-tests flag is required only on Windows and macOS.
./mvnw install -Dnative -DskipTests -Dquarkus.native.container-build=true
./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
使用以下命令创建一个新项目:
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 指南。
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 扩展的新项目:
<dependency>
<groupId>io.quarkiverse.artemis</groupId>
<artifactId>quarkus-artemis-jms</artifactId>
</dependency>
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。