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
Quarkus version | Quarkus JMS version | End of Life |
---|---|---|
|
latest |
2024-04-30 |
|
latest |
TBD |
|
|
TBD |
|
|
TBD |
|
|
TBD |
Quarkus LTS version | Quarkus JMS version | End of Life |
---|---|---|
|
|
TBD |
|
|
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.4</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.
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. |
ServerLocator
when using quarkus-artemis-core
public class MyClass {
...
private final ServerLocator serverLocator;
...
public MyClass (
...
ServerLocator serverLocator,
...
) {
...
this.serverLocator = serverLocator;
...
}
}
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
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;
...
}
}
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":
quarkus.artemis."named-1".url=...
quarkus.artemis."named-1".username=...
quarkus.artemis."named-1".password=...
we can inject it with:
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;
...
}
}
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:
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.
Description | Example | Visible? |
---|---|---|
configuration property belonging to a specific profile |
|
❌ |
configuration property bound to constant value |
|
✔️ |
configuration property bound to environment variable |
|
❌ |
configuration property bound to environment variable with default value |
|
✔️ |
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.:
ServerLocator
-bean that is picked up automatically by health checkspublic 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;
}
}
ConnectionFactory
-bean that is picked up automatically by health checkspublic 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.:
ConnectionFactory
s in a camel route by their bean namefrom(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")
:
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:
ConnectionFactory
-bean by its namefrom(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:
ConnectionFactory
-bean defined in the applicationfrom(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
:
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
Type |
Default |
|
---|---|---|
Whether to enable this configuration. Is enabled by default. Environment variable: |
boolean |
|
Enable or disable Dev Services explicitly. Dev Services are automatically enabled unless Environment variable: |
boolean |
|
Optional fixed port the dev service will listen to. If not defined, the port will be chosen randomly. Environment variable: |
int |
|
The ActiveMQ Artemis container image to use.
Defaults to Environment variable: |
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 Environment variable: |
boolean |
|
The value of the Environment variable: |
string |
|
User to start artemis broker. Defaults to Environment variable: |
string |
|
Password to start artemis broker. Defaults to Environment variable: |
string |
|
The value of the Environment variable: |
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: |
boolean |
|
Support to expose Environment variable: |
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: |
boolean |
|
Whether camel context enhancement should be enabled.
If enabled, all Environment variable: |
boolean |
|
Artemis connection url Environment variable: |
string |
|
Username for authentication, only used with JMS Environment variable: |
string |
|
Password for authentication, only used with JMS Environment variable: |
string |
|
Whether configurations ( Environment variable: |
boolean |
|
Type |
Default |
|
Whether to enable this configuration. Is enabled by default. Environment variable: |
boolean |
|
Enable or disable Dev Services explicitly. Dev Services are automatically enabled unless Environment variable: |
boolean |
|
Optional fixed port the dev service will listen to. If not defined, the port will be chosen randomly. Environment variable: |
int |
|
The ActiveMQ Artemis container image to use.
Defaults to Environment variable: |
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 Environment variable: |
boolean |
|
The value of the Environment variable: |
string |
|
User to start artemis broker. Defaults to Environment variable: |
string |
|
Password to start artemis broker. Defaults to Environment variable: |
string |
|
The value of the Environment variable: |
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: |
boolean |
|
Support to expose Environment variable: |
boolean |
|
Type |
Default |
|
Artemis connection url Environment variable: |
string |
|
Username for authentication, only used with JMS Environment variable: |
string |
|
Password for authentication, only used with JMS Environment variable: |
string |