Quarkus Artemis JMS

This extension enables the use of the Apache ActiveMQ Artemis JMS client in Quarkus.

It provides configuration properties to configure the JMS client and native executable support.

For general considerations about the JMS support in Quarkus, it is recommended to read the JMS guide.

Compatibility

Table 1. Compatibility Table
Quarkus version Quarkus JMS version End of Life

2.x

latest 2.x

2024-04-30

3.0.x
3.1.x
3.2.x

latest 3.0.x

TBD

3.3.x
3.4.x
3.5.x
3.6.x
3.7.x

3.1.x

TBD

3.8.x

3.2.x

TBD

3.9.x

3.3.x

TBD

Table 2. LTS Support
Quarkus LTS version Quarkus JMS version End of Life

3.2.x

3.0.x

TBD

3.8.x

3.2.x

TBD

Installation

To benefit from a consistent definition of the Artemis dependencies (including artemis-server often used in the tests), it is recommended to add the following BOM to your project, below the Quarkus BOM:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.quarkus.platform</groupId>
            <artifactId>quarkus-bom</artifactId>
            <version>${quarkus.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>io.quarkiverse.artemis</groupId>
            <artifactId>quarkus-artemis-bom</artifactId>
            <version>2.1.3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Once the BOM is added, simply add the io.quarkiverse.artemis:quarkus-artemis-jms extension:

<dependency>
    <groupId>io.quarkiverse.artemis</groupId>
    <artifactId>quarkus-artemis-jms</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkiverse.artemis</groupId>
    <artifactId>quarkus-test-artemis</artifactId>
    <scope>test</scope>
</dependency>

We recommend to set properties quarkus.version and artemis.version to the versions you are using/need to use. We also recommend to align artemis.version with the artemis server version used.

If you are using camel-quarkus, we also recommend setting camel-quarkus.platform.version to the version of camel used.

Named configurations

As with quarkus.datasource, we can configure multiple, named configuration. If a configuration is configured under the root quarkus.artemis, then this is the default or unnamed configuration.

Default configuration
quarkus.artemis.url=...
quarkus.artemis.username=...
quarkus.artemis.password=...

This corresponding bean is registered as the @Default bean and can be injected without additional qualifiers.

There must be some build-time configuration, otherwise the bean will not be available. Having only run-time configuration (e.g. environment variables) is not enough. Please see section Configuration detection at build-time for details.
Injection of default ServerLocator when using quarkus-artemis-core
public class MyClass {
    ...
    private final ServerLocator serverLocator;
    ...

    public MyClass (
            ...
            ServerLocator serverLocator,
            ...
    ) {
        ...
        this.serverLocator = serverLocator;
        ...
    }
}
Injection of default ConnectionFactory when using quarkus-artemis-jms
public class MyClass {
    ...
    private final ConnectionFactory connectionFactory;
    ...

    public MyClass (
            ...
            ConnectionFactory connectionFactory,
            ...
    ) {
        ...
        this.connectionFactory = connectionFactory;
        ...
    }
}

It is also registered with @Identifier("<default>"), so we can inject it with

Injection of default ServerLocator by its explicit name when using quarkus-artemis-core
public class MyClass {
    ...
    private final ServerLocator serverLocator;
    ...

    public MyClass (
            ...
            @Identifier("<default>") ServerLocator serverLocator,
            ...
    ) {
        ...
        this.serverLocator = serverLocator;
        ...
    }
}
Injection of default ConnectionFactory by its explicit name when using quarkus-artemis-jms
public class MyClass {
    ...
    private final ConnectionFactory connectionFactory;
    ...

    public MyClass (
            ...
            @Identifier("<default>") ConnectionFactory connectionFactory,
            ...
    ) {
        ...
        this.connectionFactory = connectionFactory;
        ...
    }
}

Named configurations, on the other hand, are not configured as @Default beans and must therefore be injected by name. The name of the bean is the name of the configuration, and @Identifier(…​) is used to qualify the name. So for example, if we define a configuration "named-1":

Named configuration "named-1"
quarkus.artemis."named-1".url=...
quarkus.artemis."named-1".username=...
quarkus.artemis."named-1".password=...

we can inject it with:

Injection of named ServerLocator "named-1" when using extension quarkus-artemis-core
public class MyClass {
    ...
    private final ServerLocator serverLocator;
    ...

    public MyClass (
            ...
            @Identifier("named-1") ServerLocator serverLocator,
            ...
    ) {
        ...
        this.serverLocator = serverLocator;
        ...
    }
}
Injection of named ConnectionFactory "named-1" when using extension quarkus-artemis-jms
public class MyClass {
    ...
    private final ConnectionFactory connectionFactory;
    ...

    public MyClass (
            ...
            @Identifier("named-1") ConnectionFactory connectionFactory,
            ...
    ) {
        ...
        this.connectionFactory = connectionFactory;
        ...
    }
}
We strongly recommend the usage of @Identifier annotation instead of the @Named annotation. Some other feature rely on the usage of @Identifier. Please see section Health checks for details.

@Default Bean

When an unnamed configuration is provided, this configuration will be registered as @Default bean. Otherwise, if only a single configuration is provided, this configuration will be registered as @Default bean. This mechanism allows us to inject this bean without any qualifier.

Setting properties at runtime results in a warning

When we override the properties url, username or password of a configuration at runtime - either through the implicit environment variable (QUARKUS_ARTEMIS_URL, QUARKUS_ARTEMIS__CONNECTION_NAME__URL), a custom environment variable (quarkus.artemis.url=${ARTEMIS_URL:tcp://dummy:12345}) or a runtime-provided .properties-/.yaml files, we will see a warning at startup similar to this one:

Warning at startup
2022-11-03 00:53:17,060 WARN  [io.qua.run.con.ConfigRecorder] (main) Build time property cannot be changed at runtime:
 - quarkus.artemis.url is set to 'tcp://localhost:61616' but it is build time fixed to 'tcp://dummy:12345'. Did you change the property quarkus.artemis.url after building the application?

This is expected. We bind some properties twice: once as build-time property, once as run time property. We do so to analyze the (run time-)configuration at build time to get a list of named connections. The overwritten configuration will take effect. The correct behaviour is enforced by two different tests. The above example is taken from the logs of those tests.

Configuration detection at build-time

We took special care so the configurations behave "as intuitively as possible". This means that if no connection-related configuration (enabled, url, username, password, devservices…​, health-exclude, xa-enabled) is present at build-time, it is assumed that the configuration is not used and disabled. Therefore, if we want to use any configuration, but not configure it, we should set quarkus.artemis.enabled / quarkus.artemis."named-configuration".enabled to true to explicitly enable the configuration. Due to the fact how the configuration system works in quarkus, we are only able to analyze properties defined in the default profile, i.e. properties without a prefix (%dev, %text, …​). If in doubt, we recommend setting quarkus.artemis.enabled/quarkus.artemis."named-configuration".enabled to true.

This is also the case if we bind properties in the default profile to environment variables, without a default value. For example, quarkus.artemis.url=${ARTEMIS_URL} has no value at build-time, thus this property is "invisible" at build time.
Binding a property to an environment variable, like quarkus.artemis.url=${ARTEMIS_URL} is sufficient, so the extension can pick up the configuration at build-time.
If we want to configure a connection solely through the implicit environment variables QUARKUS_ARTEMIS_…​, we should enable the configuration by setting quarkus.artemis.enabled / quarkus.artemis."named-configuration".enabled to true. For example, if we want to configure connection quarkus.artemis."named-1" through the implicit environment variables, we would set quarkus.artemis."named-1".enabled=true and then configure the connection through environment variables QUARKUS_ARTEMIS__NAMED_1__…​.

Table Visibility of configuration values gives an overview when a property is visible at build time, and when it is not.

Table 3. Visibility of configuration values
Description Example Visible?

configuration property belonging to a specific profile

  • %dev.quarkus.artemis.url=tcp://localhost:61616

  • %test.quarkus.artemis.password=${ARTEMIS_PASSWORD:artemis}

configuration property bound to constant value

  • quarkus.artemis.url=tcp://localhost:61616

  • quarkus.artemis.username=artems

✔️

configuration property bound to environment variable

  • quarkus.artemis."named".url=${ARTEMIS_NAMED_URL}

  • quarkus.artemis.password=${ARTEMIS_PASSWORD}

configuration property bound to environment variable with default value

  • quarkus.artemis."named".url=${ARTEMIS_NAMED_URL:tcp://localhost:61616}

  • quarkus.artemis.password=${ARTEMIS_PASSWORD:artemis}

✔️

Please do not try to configure a configuration purely through environment variables, without having any indication of its present in the application’s configuration file. We specifically rely on the presence of some configuration fragment at build-time to detect configurations.

XA-capable Connection Factories

To get XA-capable connection factories, we can set quarkus.artemis.xa-enabled / quarkus.artemis."named-configuration".xa-enabled to true. We can then inject the corresponding bean as XAConnectionFactory.

To use XA transactions and integrate with a transaction manager, we recommend using the quarkus-pooled-jms quarkiverse extension.

URL as optional configuration

The url configuration property is optional. But in general, without a url property, we cannot create a connection. In case of tests with embedded resources or devservices, the corresponding annotation/service injects a url. But if the application starts up and no url property is found, the creation of the bean will throw a RuntimeException with a corresponding error message. Notice that this will happen when the bean is created. If the bean is never used (and thus never created), the exception will not occur.

Health checks

By default, all configurations are added to the health check endpoint when extension quarkus-smallrye-health is loaded.

We can disable health checks for all ServerLocator s (extension quarkus-artemis-core) or ConnectionFactory s (extension quarkus-artemis-jms) by setting quarkus.artemis.health.enabled to false.

We can disable health checks for individual configurations by setting quarkus.artemis.health-exclude / quarkus.artemis."named-configuration".health-exclude to true

Note that we can only enable health checks through the above configuration if quarkus.artemis.health.enabled is true. Otherwise, setting quarkus.artemis.health-exclude / quarkus.artemis."named-connection".health-exclude has no effect.

If we create ServerLocator- (extension quarkus-artemis-core) or ConnectionFactory- (extension quarkus-artemis-jms) beans within our application (i.e. outside of this extension), we can include them in the health check by using the @Identifier annotation, e.g.:

Defining a ServerLocator-bean that is picked up automatically by health checks
public class MyBeanProvider {
    @ApplicationScoped
    @Identified("my-server-locator") // this annotation makes it so the bean is picked up by the health endpoint
    public ServerLocator mySeverLocator(...) {
        ServerLocator myServerLocator = ...;
        ...
        return myServerLocator;
    }
}
Defining a ConnectionFactory-bean that is picked up automatically by health checks
public class MyBeanProvider {
    @ApplicationScoped
    @Identified("my-connection-factory") // this annotation makes it so the bean is picked up by the health endpoint
    public ConnectionFactory myConnectionFactory(...) {
        ConnectionFactory myConnectionFactory = ...;
        ...
        return myConnectionFactory;
    }
}

If we do not want that beans created within our application is picked up by the health endpoint, we can set quarkus.artemis.health.external.enabled to false.

Note that ServerLocator s / ConnectionFactory s are only picked up when quarkus.artemis.health.enabled is true.

Camel support

All connection factories that are configured through quarkus-artemis-jms are automatically registered in the camel context, if the program uses camel. This allows us to reference the connection factories by name, e.g.:

Referencing ConnectionFactory s in a camel route by their bean name
from(jms("queue:in").connectionFactory("<default>"))
    .to(jms("queue:out").connectionFactory("named"));

In camel-quarkus, an externally defined ConnectionFactory can only be referenced by its name in a route configuration if it has a @Named(…​) annotation (documentation). This conflicts somewhat with the philosophy of the quarkus-artemis extensions, since it uses @Identifier instead. We bridge this gap by allowing to register all ConnectionFactory s annotated with @Identifier with the camel context. To enable this feature, we can set configuration property quarkus.artemis.camel-quarkus-enhance-enabled to true. This property is set to false by default.

With this in place, we can define a ConnectionFactory, e.g. through a method annotated with @Produces and, for example, @Identifier("externally-defined"):

Defining an externally defined ConnectionFactory-bean through a @Produces method
@Produces
@Typed({ ConnectionFactory.class })
@ApplicationScoped
@Identifier("externally-defined")
ActiveMQConnectionFactory externallyDefinedConnectionFactory(
        @ConfigProperty(name = "artemis.externally-defined.url") String externallyDefinedUrl) {
    return new ActiveMQConnectionFactory(externallyDefinedUrl);
}

We can then use this ConnectionFactory as follows:

Referencing an externally defined ConnectionFactory-bean by its name
from(jms("queue:in").connectionFactory("externally-defined"))
    .to(jms("queue:out").connectionFactory("externally-defined"));

Finally, if only a single ConnectionFactory is defined through quarkus-artemis-jms, this ConnectionFactory is always registered as @Default bean (see Section @Default Bean). This allows us to use this ConnectionFactory implicitly in a camel route, without setting it explicitly:

Implicitly use the only ConnectionFactory-bean defined in the application
from(jms("queue:in"))
    .to(jms("queue:out"));

This also works for an externally defined ConnectionFactory, as long as it is defined as @Default (remember that all beans that do not have any qualifier annotation are automatically @Default beans). For an externally defined ConnectionFactory, this does not require to set quarkus.artemis.camel-context-enhance-enable to be true.

This mechanism stops working as soon as more than one ConnectionFactory bean is defined in the application.

Artemis DevServices

Artemis DevServices are automatically enabled unless quarkus.artemis.url / quarkus.artemis."named-configuration".url is set or quarkus.artemis.devservices.enabled / quarkus.artemis."named-configuration".enabled is false explicitly. And if you still want to use ArtemisTestResource in the test, you need to disable artemis devservices.

Test framework

To facilitate testing, we provide a dedicated testing framework that can start an in-memory artemis instance For the default configuration, we can start an in-memory instance of artemis by annotating our tests with @QuarkusTestResource(ArtemisTestResource.class). The embedded artemis can be configured through a broker.xml, located under src/test/resources.

To start an in-memory artemis for a named configuration, we can define our own test annotation by extending ArtemisTestResource.class:

Annotation to start an in-memory artemis instance for the named configuration "named-1"
public class NamedOneArtemisTestResource extends ArtemisTestResource {
    public NamedOneArtemisTestResource() {
        super("named-1");
    }
}

We can then annotate our test with @QuarkusTestResource(NamedOneArtemisTestResource.class).

This instance can be configured by placing a broker-named-1.xml in src/test/resources. In general, for a configuration with name <name>, we can configure the corresponding in-memory artemis through file src/test/resources/broker-<name>.xml.

For an in-depth explanation of what can be configured in a broker.xml, please see the official Artemis documentation.

Examples

Examples can be found in the integration-tests module, e.g. The Apache ActiveMQ Artemis Core integration with default configuration tests module

Configuration Reference

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

Whether to enable this configuration. Is enabled by default.

Environment variable: QUARKUS_ARTEMIS_ENABLED

boolean

Enable or disable Dev Services explicitly. Dev Services are automatically enabled unless quarkus.artemis.url is set.

Environment variable: QUARKUS_ARTEMIS_DEVSERVICES_ENABLED

boolean

Optional fixed port the dev service will listen to. If not defined, the port will be chosen randomly.

Environment variable: QUARKUS_ARTEMIS_DEVSERVICES_PORT

int

The ActiveMQ Artemis container image to use. Defaults to quay.io/artemiscloud/activemq-artemis-broker:artemis.2.33.0

Environment variable: QUARKUS_ARTEMIS_DEVSERVICES_IMAGE_NAME

string

Indicates if the ActiveMQ Artemis broker managed by Quarkus Dev Services is shared. When shared, Quarkus looks for running containers using label-based service discovery. If a matching container is found, it is used, and so a second one is not started. Otherwise, Dev Services for ActiveMQ Artemis starts a new container. Is activated by default when not set. The discovery uses the quarkus-dev-service-artemis label. The value is configured using the service-name property. Container sharing is only used in dev mode.

Environment variable: QUARKUS_ARTEMIS_DEVSERVICES_SHARED

boolean

The value of the quarkus-dev-service-artemis label attached to the started container. This property is used when shared is set to true. It defaults to artemis when not set. In this case, before starting a container, Dev Services for ActiveMQ Artemis looks for a container with the quarkus-dev-service-artemis label set to the configured value. If found, it will use this container instead of starting a new one. Otherwise it starts a new container with the quarkus-dev-service-artemis label set to the specified value. This property is used when you need multiple shared ActiveMQ Artemis brokers.

Environment variable: QUARKUS_ARTEMIS_DEVSERVICES_SERVICE_NAME

string

User to start artemis broker. Defaults to admin if not set.

Environment variable: QUARKUS_ARTEMIS_DEVSERVICES_USER

string

Password to start artemis broker. Defaults to admin whne not set.

Environment variable: QUARKUS_ARTEMIS_DEVSERVICES_PASSWORD

string

The value of the AMQ_EXTRA_ARGS environment variable to pass to the container. Defaults to --no-autotune --mapped --no-fsync when not set.

Environment variable: QUARKUS_ARTEMIS_DEVSERVICES_EXTRA_ARGS

string

Whether this particular data source should be excluded from the health check if the general health check for data sources is enabled. By default, the health check includes all configured data sources (if it is enabled).

Environment variable: QUARKUS_ARTEMIS_HEALTH_EXCLUDE

boolean

Support to expose javax.jms.XAConnectionFactory. Is not activated by default.

Environment variable: QUARKUS_ARTEMIS_XA_ENABLED

boolean

Whether a health check is published in case the smallrye-health extension is present. This is a global setting and is not specific to a datasource.

Environment variable: QUARKUS_ARTEMIS_HEALTH_ENABLED

boolean

true

Whether camel context enhancement should be enabled. If enabled, all javax.jms.ConnectionFactory s annotated with io.smallrye.common.annotation.Identifier are registered as named beans in the camel context.

Environment variable: QUARKUS_ARTEMIS_CAMEL_QUARKUS_ENHANCE_ENABLED

boolean

false

Artemis connection url

Environment variable: QUARKUS_ARTEMIS_URL

string

Username for authentication, only used with JMS

Environment variable: QUARKUS_ARTEMIS_USERNAME

string

Password for authentication, only used with JMS

Environment variable: QUARKUS_ARTEMIS_PASSWORD

string

Whether configurations (org.apache.activemq.artemis.api.core.client.ServerLocator`s in case of the `artemis-core extension, javax.jms.ConnectionFactory`s in case of the `artemis-jms extension) should be included in the health check. Defaults to true if not set.

Environment variable: QUARKUS_ARTEMIS_HEALTH_EXTERNAL_ENABLED

boolean

Additional named configs

Type

Default

Whether to enable this configuration. Is enabled by default.

Environment variable: QUARKUS_ARTEMIS__CONFIGURATION_NAME__ENABLED

boolean

Enable or disable Dev Services explicitly. Dev Services are automatically enabled unless quarkus.artemis.url is set.

Environment variable: QUARKUS_ARTEMIS__CONFIGURATION_NAME__DEVSERVICES_ENABLED

boolean

Optional fixed port the dev service will listen to. If not defined, the port will be chosen randomly.

Environment variable: QUARKUS_ARTEMIS__CONFIGURATION_NAME__DEVSERVICES_PORT

int

The ActiveMQ Artemis container image to use. Defaults to quay.io/artemiscloud/activemq-artemis-broker:artemis.2.33.0

Environment variable: QUARKUS_ARTEMIS__CONFIGURATION_NAME__DEVSERVICES_IMAGE_NAME

string

Indicates if the ActiveMQ Artemis broker managed by Quarkus Dev Services is shared. When shared, Quarkus looks for running containers using label-based service discovery. If a matching container is found, it is used, and so a second one is not started. Otherwise, Dev Services for ActiveMQ Artemis starts a new container. Is activated by default when not set. The discovery uses the quarkus-dev-service-artemis label. The value is configured using the service-name property. Container sharing is only used in dev mode.

Environment variable: QUARKUS_ARTEMIS__CONFIGURATION_NAME__DEVSERVICES_SHARED

boolean

The value of the quarkus-dev-service-artemis label attached to the started container. This property is used when shared is set to true. It defaults to artemis when not set. In this case, before starting a container, Dev Services for ActiveMQ Artemis looks for a container with the quarkus-dev-service-artemis label set to the configured value. If found, it will use this container instead of starting a new one. Otherwise it starts a new container with the quarkus-dev-service-artemis label set to the specified value. This property is used when you need multiple shared ActiveMQ Artemis brokers.

Environment variable: QUARKUS_ARTEMIS__CONFIGURATION_NAME__DEVSERVICES_SERVICE_NAME

string

User to start artemis broker. Defaults to admin if not set.

Environment variable: QUARKUS_ARTEMIS__CONFIGURATION_NAME__DEVSERVICES_USER

string

Password to start artemis broker. Defaults to admin whne not set.

Environment variable: QUARKUS_ARTEMIS__CONFIGURATION_NAME__DEVSERVICES_PASSWORD

string

The value of the AMQ_EXTRA_ARGS environment variable to pass to the container. Defaults to --no-autotune --mapped --no-fsync when not set.

Environment variable: QUARKUS_ARTEMIS__CONFIGURATION_NAME__DEVSERVICES_EXTRA_ARGS

string

Whether this particular data source should be excluded from the health check if the general health check for data sources is enabled. By default, the health check includes all configured data sources (if it is enabled).

Environment variable: QUARKUS_ARTEMIS__CONFIGURATION_NAME__HEALTH_EXCLUDE

boolean

Support to expose javax.jms.XAConnectionFactory. Is not activated by default.

Environment variable: QUARKUS_ARTEMIS__CONFIGURATION_NAME__XA_ENABLED

boolean

Additional named configuration

Type

Default

Artemis connection url

Environment variable: QUARKUS_ARTEMIS__CONFIGURATION_NAME__URL

string

Username for authentication, only used with JMS

Environment variable: QUARKUS_ARTEMIS__CONFIGURATION_NAME__USERNAME

string

Password for authentication, only used with JMS

Environment variable: QUARKUS_ARTEMIS__CONFIGURATION_NAME__PASSWORD

string