Usando JMS
This guide demonstrates how your Quarkus application can use JMS messaging via the Apache Qpid JMS AMQP client, or alternatively the Apache ActiveMQ Artemis JMS client.
Essa tecnologia é considerada preview. In preview, backward compatibility and presence in the ecosystem is not guaranteed. Specific improvements might require changing configuration or APIs, and plans to become stable are under way. Feedback is welcome on our mailing list or as issues in our GitHub issue tracker. Para obter uma lista completa de possíveis status, consulte nosso FAQ. |
Pré-requisitos
Para concluir este guia, você precisa:
-
Cerca de 15 minutos
-
Um IDE
-
JDK 17+ installed with
JAVA_HOME
configured appropriately -
Apache Maven 3.9.9
-
Opcionalmente, o Quarkus CLI se você quiser usá-lo
-
Opcionalmente, Mandrel ou GraalVM instalado e configurado apropriadamente se você quiser criar um executável nativo (ou Docker se você usar uma compilação de contêiner nativo)
-
A running Artemis server, or Docker to start one
Arquitetura
In this guide, we are going to generate (random) prices in one component.
These prices are written to a queue (prices
) using a JMS client.
Another component reads from the prices
queue and stores the latest price.
The data can be fetched from a browser using a fetch button from a Jakarta REST resource.
The guide can be used either via the Apache Qpid JMS AMQP client as detailed immediately below, or alternatively with the Apache ActiveMQ Artemis JMS client given some different configuration as detailed later.
Qpid JMS - AMQP
In the detailed steps below we will use the Apache Qpid JMS client via the Quarkus Qpid JMS extension. Qpid JMS uses the AMQP 1.0 ISO standard as its wire protocol, allowing it to be used with a variety of AMQP 1.0 servers and services such as ActiveMQ Artemis, ActiveMQ 5, Qpid Broker-J, Qpid Dispatch router, Azure Service Bus, and more.
Solução
Recomendamos que siga as instruções nas seções seguintes e crie a aplicação passo a passo. No entanto, você pode ir diretamente para o exemplo completo.
Clone the Git repository: git clone https://github.com/amqphub/quarkus-qpid-jms-quickstart.git
,
or download an archive.
Criando o projeto Maven
Primeiro, precisamos de um novo projeto. Crie um novo projeto com o seguinte comando:
Para usuários do Windows:
-
Se estiver usando cmd, (não use barra invertida '\' e coloque tudo na mesma linha)
-
Se estiver usando o Powershell, envolva os parâmetros '-D' entre aspas duplas, por exemplo, '"-DprojectArtifactId=jms-quickstart"'
This command generates a new project importing the quarkus-qpid-jms extension:
<dependency>
<groupId>org.amqphub.quarkus</groupId>
<artifactId>quarkus-qpid-jms</artifactId>
</dependency>
implementation("org.amqphub.quarkus:quarkus-qpid-jms")
Starting the broker
Then, we need an AMQP broker. In this case we will use an Apache ActiveMQ Artemis server. You can follow the instructions from the Apache Artemis website or start a broker via docker using the ArtemisCloud container image:
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
Create the src/main/java/org/acme/jms/PriceProducer.java
file, with the following content:
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
The price consumer reads the prices from JMS, and stores the last one.
Create the src/main/java/org/acme/jms/PriceConsumer.java
file with the following content:
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
Finally, let’s create a simple Jakarta REST resource to show the last price.
Create the src/main/java/org/acme/jms/PriceResource.java
file with the following content:
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();
}
}
A página HTML
Toque final, a página HTML que lê os preços convertidos utilizando SSE.
Create the src/main/resources/META-INF/resources/prices.html
file, with the following content:
<!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>
Nothing spectacular here. On each fetch, it updates the page.
Configure the Qpid JMS properties
We need to configure the Qpid JMS properties used by the extension when injecting the ConnectionFactory.
This is done in the src/main/resources/application.properties
file.
# Configures the Qpid JMS properties.
quarkus.qpid-jms.url=amqp://localhost:5672
quarkus.qpid-jms.username=quarkus
quarkus.qpid-jms.password=quarkus
More detail about the configuration are available in the Quarkus Qpid JMS documentation.
Executando a aplicação
If you followed the instructions, you should have the Artemis server running. Then, you just need to run the application using:
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
Open http://localhost:8080/prices.html
in your browser.
Executando em modo nativo
You can build the native executable with:
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.native.enabled=true
Or, if you don’t have GraalVM installed, you can instead use Docker to build the native executable using:
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
and then run with:
./target/jms-quickstart-1.0.0-SNAPSHOT-runner
Open http://localhost:8080/prices.html
in your browser.
Artemis JMS
The above steps detailed using the Qpid JMS AMQP client, however the guide can also be used with the Artemis JMS client. Many of the individual steps are exactly as previously detailed above for Qpid JMS. The individual component code is the same. The only differences are in the dependency for the initial project creation, and the configuration properties used. These changes are detailed below and should be substituted for the equivalent step during the sequence above.
Solução
You can go right to the completed example.
Clone o repositório Git: git clone https://github.com/quarkusio/quarkus-quickstarts.git
, ou baixe um arquivo.
The Artemis JMS solution is located in the jms-quickstart
directory.
Criando o projeto Maven
Create a new project with the following command:
Para usuários do Windows:
-
Se estiver usando cmd, (não use barra invertida '\' e coloque tudo na mesma linha)
-
Se estiver usando o Powershell, envolva os parâmetros '-D' entre aspas duplas, por exemplo, '"-DprojectArtifactId=jms-quickstart"'
This creates a new project importing the quarkus-artemis-jms extension:
<dependency>
<groupId>io.quarkiverse.artemis</groupId>
<artifactId>quarkus-artemis-jms</artifactId>
</dependency>
implementation("io.quarkiverse.artemis:quarkus-artemis-jms")
With the project created, you can resume from Starting the broker in the detailed steps above
and proceed until configuring the application.properties
file, when you should use the Artemis
configuration below instead.
Configure the Artemis properties
We need to configure the Artemis connection properties.
This is done in the src/main/resources/application.properties
file.
# Configures the Artemis properties.
quarkus.artemis.url=tcp://localhost:61616
quarkus.artemis.username=quarkus
quarkus.artemis.password=quarkus
With the Artemis properties configured, you can resume the steps above from Executando a aplicação.
Referência de configuração
To know more about how to configure the Artemis JMS client, have a look at the documentation of the extension.