Skip to content

JmsClient vs JmsTemplate: When to Use Spring 7.0's New JMS API

Purpose

Spring 7.0 introduced JmsClient, a modern fluent API for sending JMS messages. If you’re like me, you’ve been using JmsTemplate for years and might wonder: should I switch? This post will help you understand the differences and make the right choice for your project.

What is JmsTemplate?

JmsTemplate has been the go-to API for JMS operations in Spring since the early days. It provides a template method pattern for all JMS operations: sending, receiving, and browsing messages.

JmsTemplateExample.java
@Service
public class OrderService {
@Autowired
private JmsTemplate jmsTemplate;
public void sendOrder(Order order) {
jmsTemplate.send("order.queue", session -> {
ObjectMessage message = session.createObjectMessage(order);
message.setJMSCorrelationID(order.getId());
return message;
});
}
public Order receiveOrder() {
return (Order) jmsTemplate.receiveAndConvert("order.queue");
}
}

The JmsTemplate approach works well, but it can feel verbose for simple send operations. The template method pattern requires you to provide a callback for message creation, which adds boilerplate code.

What is JmsClient?

JmsClient is Spring 7.0’s new fluent API designed specifically for sending messages. It offers a cleaner, chainable syntax that reduces boilerplate code.

JmsClientExample.java
@Service
public class OrderService {
@Autowired
private JmsClient jmsClient;
public void sendOrder(Order order) {
jmsClient.send(order)
.to("order.queue")
.withCorrelationId(order.getId())
.execute();
}
}

You can see the difference immediately. The fluent API reads naturally from left to right, making it clear what’s happening: send an order to the order queue with a correlation ID.

Feature Comparison

Let me show you a detailed comparison between the two APIs:

FeatureJmsClientJmsTemplate
Send messagesYes - Fluent APIYes - Template method
Receive messagesNoYes
Browse messagesNoYes
Batch operationsNoYes
Fluent chainingYesNo
Message conversionAutomaticAutomatic
Transaction supportYesYes

Code Comparison: Sending Messages

Let me show you more examples comparing how both APIs handle common scenarios.

Sending a Simple Text Message

With JmsTemplate:

TextMessageJmsTemplate.java
jmsTemplate.send("notifications.queue", session -> {
TextMessage message = session.createTextMessage("Order shipped!");
return message;
});

With JmsClient:

TextMessageJmsClient.java
jmsClient.send("Order shipped!")
.to("notifications.queue")
.execute();

Sending an Object with Custom Properties

With JmsTemplate:

ObjectMessageJmsTemplate.java
jmsTemplate.convertAndSend("order.queue", order, message -> {
message.setStringProperty("orderType", order.getType());
message.setIntProperty("priority", order.getPriority());
message.setJMSCorrelationID(order.getId());
return message;
});

With JmsClient:

ObjectMessageJmsClient.java
jmsClient.send(order)
.to("order.queue")
.withProperty("orderType", order.getType())
.withProperty("priority", order.getPriority())
.withCorrelationId(order.getId())
.execute();

The JmsClient version is more readable and requires less nesting.

Receiving Messages: JmsTemplate Only

Here’s where JmsTemplate still shines. JmsClient cannot receive messages, so if you need to consume messages from a queue, you must use JmsTemplate.

MessageReceiver.java
@Service
public class OrderProcessor {
@Autowired
private JmsTemplate jmsTemplate;
public Order receiveOrder() {
return (Order) jmsTemplate.receiveAndConvert("order.queue");
}
public Order receiveOrderWithTimeout(long timeout) {
return (Order) jmsTemplate.receiveSelectedAndConvert(
"order.queue",
"priority > 5",
timeout
);
}
public void browseOrders() {
jmsTemplate.browse("order.queue", (session, browser) -> {
Enumeration<Message> messages = browser.getEnumeration();
while (messages.hasMoreElements()) {
Message message = messages.nextElement();
// Process browsed message
}
return null;
});
}
}

Spring Boot Auto-Configuration

Spring Boot automatically configures both JmsClient and JmsTemplate beans when you have JMS on your classpath.

ApplicationConfig.java
@Configuration
public class JmsConfig {
@Bean
public MessageConverter orderMessageConverter() {
return new MappingJackson2MessageConverter();
}
}

The MessageConverter bean is automatically shared between both APIs, so you don’t need to configure it twice.

Common Mistakes to Avoid

Mistake 1: Assuming JmsClient Can Receive

WrongUsage.java
// WRONG: JmsClient doesn't have receive methods
Order order = jmsClient.receive("order.queue"); // This won't compile!

Use JmsTemplate instead:

CorrectUsage.java
// CORRECT: Use JmsTemplate for receiving
Order order = (Order) jmsTemplate.receiveAndConvert("order.queue");

Mistake 2: Migrating Receive Operations

If you’re migrating to JmsClient, don’t forget that your receive operations still need JmsTemplate:

HybridApproach.java
@Service
public class OrderService {
@Autowired
private JmsClient jmsClient; // For sending
@Autowired
private JmsTemplate jmsTemplate; // For receiving
public void sendOrder(Order order) {
jmsClient.send(order)
.to("order.queue")
.execute();
}
public Order receiveOrder() {
return (Order) jmsTemplate.receiveAndConvert("order.queue");
}
}

Mistake 3: Not Updating Tests

When you switch to JmsClient, make sure to update your tests:

OrderServiceTest.java
@SpringBootTest
class OrderServiceTest {
@Autowired
private JmsClient jmsClient;
@Test
void shouldSendOrder() {
Order order = new Order("123", "Laptop");
jmsClient.send(order)
.to("test.queue")
.execute();
// Verify the message was sent
}
}

Migration Strategy

If you decide to migrate from JmsTemplate to JmsClient for sending operations, here’s my recommended approach:

  1. Identify send-only code: Find all places where you only send messages (no receive operations)
  2. Add JmsClient dependency: Spring Boot 3.x+ with Spring Framework 7.0 includes JmsClient
  3. Migrate incrementally: Start with new code or simple send operations
  4. Keep JmsTemplate for receive: You’ll still need it for consuming messages
  5. Update tests: Ensure your tests cover the new API

Summary

In this post, I compared JmsClient and JmsTemplate for JMS messaging in Spring 7.0. The key takeaway is:

  • Use JmsClient for new projects that prioritize clean, chainable syntax and only need to send messages
  • Keep JmsTemplate for advanced features like receive operations, browse operations, or when working with legacy Spring applications

Both APIs can coexist in the same application, so you don’t have to choose one exclusively. Use each for what it does best.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments