Spring JMS API Compatibility
The quarkus-spring-jms module lets you use the Spring JMS API (@JmsListener, @SendTo, @Header, JmsClient, JmsResponse) in a Quarkus application.
It re-exports the actual Spring types and maps them to the Quarkus JMS extension at build time, so existing Spring JMS code compiles with minimal changes.
Getting Started
<dependency>
<groupId>io.quarkiverse.jms</groupId>
<artifactId>quarkus-spring-jms</artifactId>
</dependency>
This brings in the Spring JMS API types and the Quarkus JMS runtime. You still need a JMS provider (e.g., quarkus-artemis-jms).
Supported Spring Annotations
| Spring annotation | Package | Mapping |
|---|---|---|
|
|
Mapped to |
|
|
Repeatable container — each listener is mapped individually |
|
|
Mapped to |
|
|
Mapped to |
|
|
Mapped to the first non-annotated parameter (implicit in Quarkus) |
Supported Spring Types
| Spring type | Quarkus equivalent |
|---|---|
|
Adapted via |
|
Supported as a return type from |
Example
A typical Spring JMS listener works as-is:
import org.springframework.jms.annotation.JmsListener;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.messaging.handler.annotation.SendTo;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class OrderProcessor {
@JmsListener(destination = "orders", concurrency = "3-5")
@SendTo("order-events")
public OrderEvent process(Order order, @Header("category") String category) {
return new OrderEvent(order.id(), category, "processed");
}
}
The deployment processor extracts the destination, concurrency range, selector, and container factory from the Spring annotations and produces the same build items as native @JmsListener.
Container Factories
Spring’s containerFactory attribute maps to named configuration groups.
Configure concurrency, pub/sub domain, and acknowledge mode per factory:
quarkus.spring.jms.container-factories.myFactory.concurrency=3-10
quarkus.spring.jms.container-factories.myFactory.pub-sub-domain=true
quarkus.spring.jms.container-factories.myFactory.acknowledge-mode=client
@JmsListener(destination = "events", containerFactory = "myFactory")
public void onEvent(Event event) { }
Pub/Sub Domain
By default, destinations are treated as queues.
Set pub-sub-domain to treat destinations as topics globally:
quarkus.spring.jms.pub-sub-domain=true
Or per container factory as shown above.
JmsClient
Inject org.springframework.jms.core.JmsClient to send and receive messages using the Spring API:
import org.springframework.jms.core.JmsClient;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@ApplicationScoped
public class NotificationService {
@Inject
JmsClient jmsClient;
public void sendNotification(Notification notification) {
jmsClient.destination("notifications").send(notification);
}
}
The SpringJmsClientAdapter delegates to the Quarkus JmsClient under the hood, with full session pooling and observability support.
What’s Different from Spring
-
CDI scope is required — annotate listener classes with
@ApplicationScoped(or another CDI scope). The extension adds it automatically if missing, but being explicit is recommended. -
@Headers(map injection of all headers) is supported. -
@Payloadis optional — the first non-annotated parameter is the payload by default. -
Container factory configuration uses
application.propertiesinstead of Java@Beandefinitions. -
All Quarkus JMS features (session pooling, health checks, tracing, metrics, XA transactions) apply transparently to Spring-annotated listeners.