JMS Providers
Quarkus JMS works with any JMS provider that exposes a ConnectionFactory CDI bean.
The extension is agnostic to the JMS providers: the application needs to include the JMS provider library of the broker,
and either a Quarkus extension or the application produces the ConnectionFactory bean.
The following providers are tested:
| Provider | Client | ConnectionFactory |
JMS API | XA |
|---|---|---|---|---|
Apache ActiveMQ Artemis |
|
Provided by the extension, with Dev Services |
2.0 |
Yes |
AMQP 1.0 brokers (Qpid JMS) |
|
Provided by the extension |
2.0 |
No |
Apache ActiveMQ Classic |
|
Produced by the application |
2.0 |
Yes |
IBM MQ |
|
Produced by the application |
2.0 |
Yes |
RabbitMQ |
|
Produced by the application |
2.0 |
No |
Amazon SQS |
|
Produced by the application |
1.1 |
No |
Oracle AQ |
|
Produced by the application |
1.1 |
No |
Dev Services
Quarkus JMS does not start a broker itself.
Dev Services come from the provider extension: currently, only quarkus-artemis-jms starts a broker in dev and test mode and configures its ConnectionFactory.
For other providers, start the broker yourself, for example with Testcontainers in tests.
Native executables
Quarkus JMS supports native executables.
The JMS client library must also work in native mode: use a Quarkus extension that provides native support for it, such as quarkus-artemis-jms or quarkus-qpid-jms.
When you produce the ConnectionFactory yourself with a plain JMS client library, native compilation depends on that library, and may require additional native-image configuration.
Producing a ConnectionFactory
When no Quarkus extension provides the ConnectionFactory, produce it as a CDI bean.
Quarkus JMS uses the @Default bean, or a bean qualified with @Identifier when a destination or listener sets connection-factory / connectionFactory.
In the examples below, the configuration keys (activemq.url, ibmmq.host, …) are defined by the application, not by Quarkus JMS.
TLS and credentials are configured on the ConnectionFactory: through the provider extension’s configuration, or in your producer method.
A producer method can inject the Quarkus TlsConfigurationRegistry or a CredentialsProvider like any other CDI bean.
XA connection factories
Listeners with acknowledge = XA, the Reactive Messaging connector with transaction-mode=xa, and receiveWith in a @Transactional method need an XAConnectionFactory.
Quarkus JMS looks for an XAConnectionFactory bean with the same qualifier as the ConnectionFactory.
If there is none, it checks whether the ConnectionFactory bean itself implements XAConnectionFactory.
For providers that use separate classes for XA, produce both beans, as shown for ActiveMQ Classic and IBM MQ.
XA also requires the quarkus-narayana-jta extension.
See XA Distributed Transactions.
Apache ActiveMQ Artemis
Add the Artemis JMS extension:
<dependency>
<groupId>io.quarkiverse.artemis</groupId>
<artifactId>quarkus-artemis-jms</artifactId>
</dependency>
The extension provides the ConnectionFactory from configuration, and starts a broker with Dev Services in dev and test mode:
quarkus.artemis.url=tcp://localhost:61616
quarkus.artemis.username=quarkus
quarkus.artemis.password=quarkus
To use XA transactions, enable XA-capable connection factories:
quarkus.artemis.xa-enabled=true
See the Quarkus Artemis documentation for named connection factories and other options.
AMQP 1.0 brokers with Qpid JMS
Add the Qpid JMS extension:
<dependency>
<groupId>org.amqphub.quarkus</groupId>
<artifactId>quarkus-qpid-jms</artifactId>
</dependency>
The extension provides the ConnectionFactory from configuration:
quarkus.qpid-jms.url=amqp://localhost:5672
quarkus.qpid-jms.username=quarkus
quarkus.qpid-jms.password=quarkus
Qpid JMS connects to AMQP 1.0 brokers such as ActiveMQ Artemis, ActiveMQ Classic, Qpid Broker-J and Azure Service Bus. See the Quarkus Qpid JMS documentation for the other options.
Apache ActiveMQ Classic
Add the ActiveMQ Classic client:
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-client-jakarta</artifactId>
<version>${activemq.version}</version>
</dependency>
Produce the connection factories:
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Singleton;
import jakarta.jms.ConnectionFactory;
import jakarta.jms.XAConnectionFactory;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.ActiveMQXAConnectionFactory;
import org.eclipse.microprofile.config.inject.ConfigProperty;
@ApplicationScoped
public class ActiveMqConnectionFactoryProducer {
@Produces
@Singleton
ConnectionFactory connectionFactory(@ConfigProperty(name = "activemq.url") String brokerUrl) {
return new ActiveMQConnectionFactory(brokerUrl);
}
// Only needed for XA transactions
@Produces
@Singleton
XAConnectionFactory xaConnectionFactory(@ConfigProperty(name = "activemq.url") String brokerUrl) {
return new ActiveMQXAConnectionFactory(brokerUrl);
}
}
activemq.url=tcp://localhost:61616
IBM MQ
Add the IBM MQ Jakarta client:
<dependency>
<groupId>com.ibm.mq</groupId>
<artifactId>com.ibm.mq.jakarta.client</artifactId>
<version>${ibmmq.version}</version>
</dependency>
Produce the connection factories with JmsFactoryFactory:
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Singleton;
import jakarta.jms.ConnectionFactory;
import jakarta.jms.JMSException;
import jakarta.jms.XAConnectionFactory;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import com.ibm.msg.client.jakarta.jms.JmsConnectionFactory;
import com.ibm.msg.client.jakarta.jms.JmsFactoryFactory;
import com.ibm.msg.client.jakarta.wmq.WMQConstants;
@ApplicationScoped
public class IbmMqConnectionFactoryProducer {
@ConfigProperty(name = "ibmmq.host")
String host;
@ConfigProperty(name = "ibmmq.port")
int port;
@ConfigProperty(name = "ibmmq.queue-manager")
String queueManager;
@ConfigProperty(name = "ibmmq.channel")
String channel;
@ConfigProperty(name = "ibmmq.user")
String user;
@ConfigProperty(name = "ibmmq.password")
String password;
@Produces
@Singleton
ConnectionFactory connectionFactory() throws JMSException {
JmsConnectionFactory cf = JmsFactoryFactory.getInstance(WMQConstants.JAKARTA_WMQ_PROVIDER)
.createConnectionFactory();
configure(cf);
return cf;
}
// Only needed for XA transactions
@Produces
@Singleton
XAConnectionFactory xaConnectionFactory() throws JMSException {
var cf = JmsFactoryFactory.getInstance(WMQConstants.JAKARTA_WMQ_PROVIDER)
.createXAConnectionFactory();
configure(cf);
return cf;
}
private void configure(JmsConnectionFactory cf) throws JMSException {
cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, host);
cf.setIntProperty(WMQConstants.WMQ_PORT, port);
cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, queueManager);
cf.setStringProperty(WMQConstants.WMQ_CHANNEL, channel);
cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
cf.setStringProperty(WMQConstants.USERID, user);
cf.setStringProperty(WMQConstants.PASSWORD, password);
}
}
ibmmq.host=localhost
ibmmq.port=1414
ibmmq.queue-manager=QM1
ibmmq.channel=DEV.APP.SVRCONN
ibmmq.user=app
ibmmq.password=passw0rd
IBM MQ queue names often differ from the names used in the application.
Use the destination property to map them:
quarkus.jms.destinations.orders.destination=DEV.QUEUE.1
RabbitMQ
Add the RabbitMQ JMS client:
<dependency>
<groupId>com.rabbitmq.jms</groupId>
<artifactId>rabbitmq-jms</artifactId>
<version>${rabbitmq-jms.version}</version>
</dependency>
Produce the connection factory:
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Singleton;
import jakarta.jms.ConnectionFactory;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import com.rabbitmq.jms.admin.RMQConnectionFactory;
@ApplicationScoped
public class RabbitMqConnectionFactoryProducer {
@Produces
@Singleton
ConnectionFactory connectionFactory(
@ConfigProperty(name = "rabbitmq.host") String host,
@ConfigProperty(name = "rabbitmq.port") int port,
@ConfigProperty(name = "rabbitmq.username") String username,
@ConfigProperty(name = "rabbitmq.password") String password) {
RMQConnectionFactory cf = new RMQConnectionFactory();
cf.setHost(host);
cf.setPort(port);
cf.setUsername(username);
cf.setPassword(password);
return cf;
}
}
RabbitMQ does not prefetch messages for JMS consumers by default, so consumer caching (quarkus.jms.pool.cache-consumers=true) can be enabled safely.
Amazon SQS
The SQS JMS client only implements JMS 1.1. Enable the JMS 1.1 compatibility mode:
quarkus.jms.jms11=true
Add the SQS JMS client:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>amazon-sqs-java-messaging-lib</artifactId>
<version>${amazon-sqs-java-messaging-lib.version}</version>
</dependency>
Produce the connection factory from an SqsClient:
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Singleton;
import jakarta.jms.ConnectionFactory;
import com.amazon.sqs.javamessaging.ProviderConfiguration;
import com.amazon.sqs.javamessaging.SQSConnectionFactory;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sqs.SqsClient;
@ApplicationScoped
public class SqsConnectionFactoryProducer {
@Produces
@Singleton
ConnectionFactory connectionFactory() {
SqsClient sqsClient = SqsClient.builder()
.region(Region.EU_WEST_1)
.build();
return new SQSConnectionFactory(new ProviderConfiguration(), sqsClient);
}
}
XA transactions are not available in JMS 1.1 compatibility mode.
Oracle AQ
The Oracle AQ JMS client only implements JMS 1.1. Enable the JMS 1.1 compatibility mode:
quarkus.jms.jms11=true
Add the AQ JMS client and the Oracle JDBC driver:
<dependency>
<groupId>com.oracle.database.messaging</groupId>
<artifactId>aqapi-jakarta</artifactId>
<version>${oracle.aqapi.version}</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc11</artifactId>
<version>${oracle.jdbc.version}</version>
</dependency>
Produce the connection factory from an Oracle data source:
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
import jakarta.inject.Singleton;
import jakarta.jms.ConnectionFactory;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import oracle.jakarta.jms.AQjmsFactory;
import oracle.jdbc.pool.OracleDataSource;
@ApplicationScoped
public class OracleAqConnectionFactoryProducer {
@Produces
@Singleton
ConnectionFactory connectionFactory(
@ConfigProperty(name = "oracle.jdbc.url") String jdbcUrl,
@ConfigProperty(name = "oracle.jdbc.user") String user,
@ConfigProperty(name = "oracle.jdbc.password") String password) throws Exception {
OracleDataSource dataSource = new OracleDataSource();
dataSource.setURL(jdbcUrl);
dataSource.setUser(user);
dataSource.setPassword(password);
return AQjmsFactory.getConnectionFactory(dataSource);
}
}
XA transactions are not available in JMS 1.1 compatibility mode.