IBM Websphere MQ - EJB and MDB migration for Tomca

2019-07-15 15:07发布

问题:

I have been struggling with this for a long time now. I have an IBM Websphere MQ, which uses EJB and MDB

The following is where the ejb mdb is configured.

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar-bnd xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://websphere.ibm.com/xml/ns/javaee"
    xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-ejb-jar-bnd_1_0.xsd" version="1.0">
  <message-driven name="Queue1MDB">
    <jca-adapter activation-spec-binding-name="jms/Queue1MQActivationSpec" destination-binding-name="jms/Queue1RequestQueue"/>
    <resource-ref binding-name="jms/QueueConnectionFactory" name="jms/QueueConnectionFactory"/>
    <message-destination-ref binding-name="jms/SuccessfulResponseQueue" name="jms/SuccessfulResponseQueue"/>
    <message-destination-ref binding-name="jms/FailedResponseQueue" name="jms/FailedResponseQueue"/>
  </message-driven>

  <message-driven name="Queue2MDB">
    <jca-adapter activation-spec-binding-name="jms/Queue2MQActivationSpec" destination-binding-name="jms/Queue2RequestQueue"/>
    <resource-ref binding-name="jms/QueueConnectionFactory" name="jms/QueueConnectionFactory"/>
    <message-destination-ref binding-name="jms/SuccessfulResponseQueue" name="jms/SuccessfulResponseQueue"/>
    <message-destination-ref binding-name="jms/FailedResponseQueue" name="jms/FailedResponseQueue"/>
  </message-driven>

  <message-driven name="Queue3MDB">
    <jca-adapter activation-spec-binding-name="jms/Queue3MQActivationSpec" destination-binding-name="jms/Queue3RequestQueue"/>
    <resource-ref binding-name="jms/QueueConnectionFactory" name="jms/QueueConnectionFactory"/>
    <message-destination-ref binding-name="jms/SuccessfulResponseQueue" name="jms/SuccessfulResponseQueue"/>
    <message-destination-ref binding-name="jms/FailedResponseQueue" name="jms/FailedResponseQueue"/>
  </message-driven>

  <message-driven name="Queue4MDB">
    <jca-adapter activation-spec-binding-name="jms/Queue4MQActivationSpec" destination-binding-name="jms/Queue4RequestQueue"/>
    <resource-ref binding-name="jms/QueueConnectionFactory" name="jms/QueueConnectionFactory"/>
    <message-destination-ref binding-name="jms/SuccessfulResponseQueue" name="jms/SuccessfulResponseQueue"/>
    <message-destination-ref binding-name="jms/FailedResponseQueue" name="jms/FailedResponseQueue"/>
  </message-driven>
</ejb-jar-bnd>

This is configured in ear, which is deployed in IBM WAS. The destination-binding-name will pick the corresponding queue details from the IBM WAS.

And later, my configuring the MDB in my java class like below, the listening is achieved on all the queues simultaneously and the messages are picked up:

@Resource(name = "jms/QueueContractConnectionFactory")
private ConnectionFactory connectionFactory;

@Resource(name = "jms/FailedResponseQueue")
private Queue errorQueue;

@Resource(name = "jms/SuccessfulResponseQueue")
private Queue responseQueue;

I now have to remove the ejb and modify the mdb configurations to make it deploy-able in tomcat.

The xml is something, which I literally have no idea on how to map it without the ejb parameters.

Can someone help or share a document on how to achieve this? I would like to have a example of IBM MQ to Spring JMS with Activation Spec.

Thanks in advance.

回答1:

As has been commented, it's not simply a matter of replacing WAS with Tomcat, as they are not the same kind of container. So you can not directly deploy your WAS artifacts (the MDBs, notably) directly in to Tomcat. In order to get these in to Tomcat, they will have to be rewritten.

By being an MDB, the container manages for you: connecting to the JMS server, routing of messages from the queue/topic to your logic, multi-threaded message processing (handling more than one queued message at once) and, most notably, transaction management.

Now, message processing against JMS is pretty straightforward. You can make a connection to JMS readily. You can copy an example off the net and get that working. Running processing in the background is straightforward, there are examples of that as well. JMS 2.0 is easier to use than JMS 1.x. No reason not to port to that (unless MQ doesn't support JMS 2.0).

Running multiple instances of the logic, transactionally, is not so straightforward, but maybe that's not a keen aspect of your processing.

However, even if you were able to get all of that working, there's no guarantee at this juncture that your logic will work directly. We don't know if you logic calls other EJBs or leverages any of the other Java EE infrastructure. Were it to do so, them you have to port that aspect of your logic as well, not just the MDB connectivity.

So, this is a deeper problem. It's easy to say "just deploy it in Tomcat", but there could be details that derail that and need to be accounted for.

Another take is to convert the logic to Spring, as that can deploy in Tomcat readily. But that's not necessarily simpler than anything else -- all of the caveats remain.

Finally, "deploying in Tomcat" is almost a non-sequitur in this case because MDBs are not Web Apps, and Tomcat deploys Web Apps. You can create a shell of a Web App that does nothing but house your message driven logic. It's easy to do, I and many others have abused the Web App life cycles to our own nefarious ends for things like this.

So, in the end, I think you need more clarity as to what "deploy in Tomcat" really means, what the expectations are in the end, and whether your message logic relies on other Java EE infrastructure etc. Is the goal to run in Tomcat or to not run in WAS (in that case, as noted in the comments, there are other app servers you could possibly use that would be much easier to transition to).



回答2:

Mike my other post that you linked to this question outlines the steps assuming you are good with setting up the springframework, MQ and server administration. But if you are struggling to get a start, here's some pointers.

Before you begin, you need to understand that this can be technically challenging. Sometimes, instead of changing what exists, breaking down what exists into multiple modules and implementing them from scratch makes more sense. Should you choose to change what exists, here's how to approach it:

Get the spring framework working in your application that you built in RAD. Did you do this successfully? Just inject any bean from the application context and see if you can get this to work on WAS. If you can do this successfully, it means you got a head start, the rest of it can be done. Let me know when you get to this - paste your application context or configuration here. I can tell you what to do next. Remember, you don't have to switch to tomcat right away - your aim should be to replace an MDB with a spring bean that can listen to messages - and this can run on WAS.



回答3:

There is one thing you should be aware of with respect of Websphere MQ. The connection pooling with MQ classes for JMS is supported only through Websphere application server. When you migrate to Tomcat you may experience performance penalty and you may have to implement your self some amount of pooling. I think spring can help in this regards. I will quote it from IBM documentation

public void setUseConnectionPooling(boolean usePooling)

Deprecated. JMS does not use connection pooling anymore. Any connection pooling should be done using the facilities provided by the App Server. Set the use of ConnectionPooling in earlier versions of the IBM MQ classes for JMS. This method is retained for compatibility with older MQJMS applications, but, because this Connection Pooling functionality has been removed from version 7, setting this property will have no effect.

https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.0.0/com.ibm.mq.javadoc.doc/WMQJMSClasses/com/ibm/mq/jms/MQConnectionFactory.html#setUseConnectionPooling-boolean-

I think your best shot is to spring-ify(move to spring) your WAS application and then switch to Tomcat. Once you move to spring it should be a piece of cake to switch. It is supposed to be container independent. There are plenty of recipies online on how to migrate Java EE to spring applications. This excersise has been done for years(since spring exists:).

In the process you can also apply divide and conquere and end up with more then one app instead of monolith.