In the first article in this series on transactions, we looked at what transactions are, how they are defined in JMS and in IBM MQ and shared a few samples for simple usage in stand-alone Java SE applications.
In this article we look at what you need to know to write applications for enterprise application servers.
Application servers provide abstractions that remove some of the complexity away from your app so you can concentrate on the business logic alone. The trade-off is that you have to know how to use the common services they provide, to achieve your goal.
Enterprise applications are not usually stand alone, there are lots of them, doing different things and connecting to resources through different protocols to exchange data and keep the state of all the participating resources consistent. It makes sense for them to have a common environment to run in and once they're there, it might make sense that some of the repeated, common functionality is centralised on the platform so that new apps don't have to implement the same behaviours over and over again.
For Java, we start with Jakarta Enterprise Edition (JEE), a specification used to define a JEE platform which is referred to as a JEE container, a server environment in which our application can run that also provides common services and APIs.
Examples of such JEE compliant platforms are IBM's WebSphere Application Server or it's lighter, open source version Liberty, RedHat's JBoss, Oracle's GlassFish etc.
The aim of the JEE specification is to standardise how distributed computing and web services work in enterprise servers.
For a good overview of the Java EE Architecture see this page from the book by Arun Gupta, Java EE 7 Essentials and this Stack Overflow answer that summarises the Java EE specifications.
We used JMS in several tutorials to create stand-alone Java SE apps and have seen how transactions work with just JMS and MQ but what do transactional JMS enterprise applications look like when they are created to run on app servers?
Let's look at a more specific set of resources that make up an app server, based on the JEE specification.
In this diagram we have the Liberty app server working with a resource adapter to allow a message to be sent to a queue on an IBM MQ queue manager. Both Liberty and MQ support JMS messaging. A web application sends a message to a queue on which a message driven bean is listening. The message driven bean is also running in the app server but is not consuming any resources until a message arrives. The resource adapter enables the communication between the Liberty app server and IBM MQ to happen so that a message is sent to the queue and the listener gets the message when it arrives on the queue.
Figure 1 Applications using Liberty app server resources and MQ Resource adapter to connect to a queue manager and send/receive messages
In the previous article we saw that a in a Java SE scenario, the transaction was coordinated between MQ as the messaging provider and the JMS API.
We added a transacted property to a JMS context (or session) before starting a method or a group of methods and ended the transaction with a commit. Depending on how critical the messages we were sending inside the transaction were, we made sure when rolling them back that they ended up on a queue they started from or if a message was just created before being a part of the transaction, it might have been thrown away. If the message was important and it didn't come from a queue which it could go back to, we made use of the JMS API call to put it to a backout queue we named for this purpose. If we didn't name the backout queue, we relied on the queue manager to put the message on the dead letter queue.
In the app server environment, service components take over the role of managing transactions. Rather than just knowing which JMS classes to use, you need to know that at a certain point the JEE platform will take over, do things under the covers and provide transactionality for your app. Your application needs to behave in the right way.
This is where we get to the concept of transaction demarcation. This means setting the boundaries of where the transaction begins and ends.
In Java EE, there are two ways to manage transactions. They help you understand what and how much you're responsible for when including a transaction in your app.
In container managed transaction demarcation the EJB container sets the transaction boundaries. In basic terms, the transaction starts before the bean method starts and commits just before the method exits. Read more about container managed transactions and how to use the attributes to set the scope for this kind of transaction.
Bean managed transaction demarcation allows developers to explicitly mark the transaction boundaries. It allows for a more fine-grain control over transactions. Read this tutorial for more on bean managed transactions.
But we jumped in there a bit quick. Before you use transactions, you should know a little about these app server concepts first.
Enterprise java beans are server side components that provide some business logic to application clients. Clients invoke the EJB methods to use a service provided by the bean. EJBs run in EJB containers which provide services like transactionality and security.
Message driven beans are a type of EJBs. They allow enterprise applications to process messages asynchronously. They are usually message listeners listening for messages from applications or other components. When a message arrives, the EJB container calls the message listener's onMessage method to process the message.
Contexts provide lifecycle management for stateful components like beans and dependency injection allows for injection of components into applications to be used at deployment time.
Deployment descriptors are xml files that describe how applications should be deployed and what dependencies should be injected. Annotations are used in applications to add the injection in classes and methods, removing the need for XML configuration files. Annotations are more recent but both are still in use and can be used in combination.
This is just the tip of the iceberg of what a developer should be familiar with in order to write good JEE applications that run in app servers.
Spring promises a more developer friendly approach to using the resources that a JEE compliant framework provides.
Figure 2 Overview of the Spring framework modules
Spring provides its own abstraction on top of the JEE specification. Spring works with plain old java objects (POJOs) and does not require you to understand how JEE works. The Spring framework hides the app server layer and gives you a different way of achieving your goals.
With the EJB container, you can give it an annotation or a descriptor and the app server orchestrates things for you, with the bean you do it programmatically. In Spring it is the same, you can rely on the container and they'll manage it for you or you can do it yourself. You just have to learn a little about Spring annotations and classes, the framework will do the rest for you.
Your application built for Spring is still portable. Spring gives you an app server agnostic way of doing things.
Spring has its own model for managing transactions that is JEE compliant. This model provides abstractions for enabling transactions declaratively or programatically.
Declarative transaction management is Spring's preferred way of working with transactions because it has less impact on the application code. Spring warns developers that it is useful to understand that the functionality of transactions goes beyond the @Transactional
annotation and the @EnableTransactionManagement
configuration. The support for transactions is provided through Spring's AOP proxies and transactional metadata. Read more about it in this section of the Spring doc.
We're mentioning Spring's declarative transaction management because this is what we're using in our samples.
In practical terms we can demonstrate simple usage through these samples. Let’s see how transactions work in practice in Spring.
We provide two sets of simple transacted samples.
Sample 2 - simple application shows a transaction with a commit and a rollback.
Sample 3 requester is a request sample that puts a message on the queue using the Spring send and receive method, provides a temporary queue where it waits for a reply.
Sample 3 responder is a message driven response/listener sample that receives a message, gets the reply queue from the requester and sends a message back.
They are designed to work with the IBM MQ container with the default developer configuration.
We give you a couple of options for exploring the samples.
- The samples are included in this GitHub repository that has the code for integrating MQ JMS with Spring (the
mq-spring-boot-starter
). Follow the instructions in the mainmq-jms-spring
Readme to clone, build and run the samples locally with Gradle. - If you need step by step instructions, you can also clone the
mq-dev-patterns
repository and follow the instructions in theSpring directory Readme
to use the samples sets 2 and 3 frommq-jms-spring
repository and run them with Maven. Full instructions are in theSpring directory Readme
.
For a quick note on some of the annotations we're using in our samples, read a bit more below or jump straight into the samples.
We use Spring Boot in our applications. Spring Boot is an extension to Spring that allows for building and running of stand-alone Spring applications without much configuration.
Along with the mq-spring-boot-starter
that provides the helper classes for integrating with IBM MQ, you can get started very quickly.
We tell Spring that we're using Spring Boot by adding the
@SpringBootApplication annotation. It lives along our main
class.
We use Spring's externalised configuration
properties in the form of an application.properties file which Spring Boot finds and loads when the application starts. This is how we provide some of the MQ connection variables and user details for our app to access the queue manager.
ibm.mq.queueManager=QM1
ibm.mq.channel=DEV.APP.SVRCONN
ibm.mq.connName=localhost(1414)
ibm.mq.tempModel=DEV.APP.MODEL.QUEUE
ibm.mq.user=app
ibm.mq.password=passw0rd
As mentioned in the Messaging with JMS
Spring guide we use the @EnableJms annotation to "trigger the discovery of methods annotated with @JmsListener and create the message listener container under the covers".
We use the @EnableTransactionManagement annotation to make use of the declarative transaction management.
We use the JMSTemplate to create the JMS Template object to control connections and sessions.
We use the JmsTransactionManager because we want to retrieve the JMS Session and use the same transaction to send a reply after we get a request message.
TransactionStatus represents the status of a transaction and can be retrieved to find out the status information and programatically request a rollback.
In this article we looked at how JMS messaging applications work in applications servers, both JEE and Spring. We looked at what it takes for transactions to work in such environments. While JEE compliant application servers offer a sophisticated environment for applications to make use of the platform's services such as transactionality, its complexity, packaging and deployment strategies might create barriers for developers to get started with easily. The Spring framework seeks to simplify access to its resources by cutting out the middle layer by hiding it behind the abstractions that POJOs can use through straight forward annotations while the framework wires everything together as needed for applications to work. Transactions are an essential part of enterprise application programming. Regardless of whether your applications need to work with JEE servers or Spring, if the messaging payload is of value, IBM MQ is flexible and can support either.
Deploying a Message Driven Bean in Open Liberty with IBM MQ
Installing the resource adapter in Liberty
Verifying the resource adapter installation (with an Installation Verification Test (IVT) sample)
WAS: Java EE architecture: Containers, Components, Annotations
Transactions in Java EE Applications
Spring Boot Messaging with JMS
Books
Java EE The big picture - Dr Danny Coward
Expert One-on-One™ J2EE™ Development without EJB™ - Rod Johnson, Juergen Hoeller