"What's New in JMS 2.0"Part 1 and Part 2 provide comprehensive introduction to new messaging features introduced in JMS 2.0. The biggest improvement in JMS 2.0 is introduction of the "new simplified API". This was explained in theJava EE 7 Launch Technical Keynote. You can watch a complete replay here.
Sending and Receiving a JMS message using JMS 1.1 requires lot of boilerplate code, primarily because the API was designed 10+ years ago. Here is a code that shows how to send a message using JMS 1.1 API:
@Stateless
public class ClassicMessageSender {
@Resource(lookup = "java:comp/DefaultJMSConnectionFactory")
ConnectionFactory connectionFactory;
@Resource(mappedName = "java:global/jms/myQueue")
Queue demoQueue;
public void sendMessage(String payload) {
Connection connection = null;
try {
connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = session.createProducer(demoQueue);
TextMessage textMessage = session.createTextMessage(payload);
messageProducer.send(textMessage);
} catch (JMSException ex) {
ex.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (JMSException ex) {
ex.printStackTrace();
}
}
}
}
}
There are several issues with this code:
- A JMS ConnectionFactory needs to be created in a application server-specific way before this application can run.
- Application-specific destination needs to be created in an application server-specific way before this application can run.
- Several intermediate objects need to be created to honor the JMS 1.1 API, e.g. ConnectionFactory -> Connection -> Session -> MessageProducer -> TextMessage.
- Everything is a checked exception and so try/catch block must be specified.
- Connection need to be explicitly started and closed, and that
bloats even the finally block.
@Stateless
public class SimplifiedMessageSender {
@Inject
JMSContext context;
@Resource(mappedName="java:global/jms/myQueue")
Queue myQueue;
public void sendMessage(String message) {
context.createProducer().send(myQueue, message);
}
}
The code is significantly improved from the previous version in the following ways:
- The
JMSContext
interface combines in a single object the functionality of both theConnection
and theSession
in the earlier JMS APIs. You can obtain aJMSContext
object by simply injecting it with the@Inject
annotation. - No need to explicitly specify a ConnectionFactory. A default
ConnectionFactory under the JNDI name of
java:comp/DefaultJMSConnectionFactory
is used if no explicit ConnectionFactory is specified. - The destination can be easily created using newly introduced
@JMSDestinationDefinition as:
@JMSDestinationDefinition(name = "java:global/jms/myQueue",
It can be specified on any Java EE component and the destination is created during deployment.
interfaceName = "javax.jms.Queue") JMSContext
,Session
,Connection
,JMSProducer
andJMSConsumer
objects are nowAutoCloseable
. This means that these resources are automatically closed when they go out of scope. This also obviates the need to explicitly start the connection- JMSException is now a runtime exception.
- Method chaining on JMSProducers allows to use builder patterns.
- No need to create separate Message object, you can specify the message body as an argument to the send() method instead.
Want to try this code ? Download source code!
Download Java EE 7 SDK and install.
Start GlassFish: bin/asadmin start-domain
Build the WAR (in the unzipped source code directory): mvn package
Deploy the WAR: bin/asadmin deploy<source-code>/jms/target/jms-1.0-SNAPSHOT.war
And access the application at http://localhost:8080/jms-1.0-SNAPSHOT/index.jsp to send and receive a message using classic and simplified API.
A replay of JMS 2.0 session from Java EE 7 Launch Webinar provides complete details on what's new in this specification:
Enjoy!