使用 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 项目
首先,我们需要一个新项目。使用以下命令创建一个新项目
对于 Windows 用户
-
如果使用 cmd,(不要使用反斜杠
\
并将所有内容放在同一行上) -
如果使用Powershell,请将
-D
参数用双引号括起来,例如"-DprojectArtifactId=jms-quickstart"
此命令生成一个导入quarkus-qpid-jms扩展的新项目
<dependency>
<groupId>org.amqphub.quarkus</groupId>
<artifactId>quarkus-qpid-jms</artifactId>
</dependency>
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> €</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服务器。然后,您只需使用以下命令运行应用程序
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
在浏览器中打开https://:8080/prices.html
。
原生运行
您可以使用以下命令构建原生可执行文件
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
在浏览器中打开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项目
使用以下命令创建一个新项目
对于 Windows 用户
-
如果使用 cmd,(不要使用反斜杠
\
并将所有内容放在同一行上) -
如果使用Powershell,请将
-D
参数用双引号括起来,例如"-DprojectArtifactId=jms-quickstart"
这会创建一个导入quarkus-artemis-jms扩展的新项目
<dependency>
<groupId>io.quarkiverse.artemis</groupId>
<artifactId>quarkus-artemis-jms</artifactId>
</dependency>
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客户端的信息,请查看扩展文档。