📄 jms6.html
字号:
<a name="wp92822"> </a><div class="pSmartList1"><li>Click Finish.</li></div></ol></div><a name="wp87024"> </a><p class="pBody">Use the following command to run the program. The destination is <code class="cCode">jms/Topic</code>:</p><div class="pPreformattedRelative"><pre class="pPreformattedRelative">appclient -client DurableSubscriberExample.jar<a name="wp83722"> </a></pre></div><a name="wp83724"> </a><p class="pBody">The output looks something like this:</p><div class="pPreformattedRelative"><pre class="pPreformattedRelative">Connection factory without client ID is jms/TopicConnectionFactoryConnection factory with client ID is jms/DurableTopicConnectionFactoryTopic name is jms/TopicStarting subscriberPUBLISHER: Publishing message: Here is a message 1SUBSCRIBER: Reading message: Here is a message 1PUBLISHER: Publishing message: Here is a message 2SUBSCRIBER: Reading message: Here is a message 2PUBLISHER: Publishing message: Here is a message 3SUBSCRIBER: Reading message: Here is a message 3Closing subscriberPUBLISHER: Publishing message: Here is a message 4PUBLISHER: Publishing message: Here is a message 5PUBLISHER: Publishing message: Here is a message 6Starting subscriberSUBSCRIBER: Reading message: Here is a message 4SUBSCRIBER: Reading message: Here is a message 5SUBSCRIBER: Reading message: Here is a message 6Closing subscriberUnsubscribing from durable subscription<a name="wp92844"> </a></pre></div><a name="wp92878"> </a><h4 class="pHeading3">Using JMS API Local Transactions</h4><a name="wp82015"> </a><p class="pBody">You can group a series of operations together into an atomic unit of work called a transaction. If any one of the operations fails, the transaction can be rolled back, and the operations can be attempted again from the beginning. If all the operations succeed, the transaction can be committed. </p><a name="wp82016"> </a><p class="pBody">In a JMS client, you can use local transactions to group message sends and receives. The JMS API <code class="cCode">Session</code> interface provides <code class="cCode">commit</code> and <code class="cCode">rollback</code> methods that you can use in a JMS client. A transaction commit means that all produced messages are sent and all consumed messages are acknowledged. A transaction rollback means that all produced messages are destroyed and all consumed messages are recovered and redelivered unless they have expired (see <a href="JMS6.html#wp81871">Allowing Messages to Expire</a>).</p><a name="wp82023"> </a><p class="pBody">A transacted session is always involved in a transaction. As soon as the <code class="cCode">commit</code> or the <code class="cCode">rollback</code> method is called, one transaction ends and another transaction begins. Closing a transacted session rolls back its transaction in progress, including any pending sends and receives.</p><a name="wp82024"> </a><p class="pBody">In an Enterprise JavaBeans component, you cannot use the <code class="cCode">Session.commit</code> and <code class="cCode">Session.rollback</code> methods. Instead, you use distributed transactions, which are described in <a href="JMS7.html#wp82114">Using the JMS API in a J2EE Application</a>. </p><a name="wp82028"> </a><p class="pBody">You can combine several sends and receives in a single JMS API local transaction. If you do so, you need to be careful about the order of the operations. You will have no problems if the transaction consists of all sends or all receives or if the receives come before the sends. But if you try to use a request-reply mechanism, whereby you send a message and then try to receive a reply to the sent message in the same transaction, the program will hang, because the send cannot take place until the transaction is committed. The following code fragment illustrates the problem:</p><div class="pPreformattedRelative"><pre class="pPreformattedRelative">// Don't do this!outMsg.setJMSReplyTo(replyQueue);producer.send(outQueue, outMsg);consumer = session.createConsumer(replyQueue);inMsg = consumer.receive();session.commit();<a name="wp82029"> </a></pre></div><a name="wp82035"> </a><p class="pBody">Because a message sent during a transaction is not actually sent until the transaction is committed, the transaction cannot contain any receives that depend on that message's having been sent. </p><a name="wp82036"> </a><p class="pBody">In addition, the production and the consumption of a message cannot both be part of the same transaction. The reason is that the transactions take place between the clients and the JMS provider, which intervenes between the production and the consumption of the message. <a href="JMS6.html#wp82045">Figure 29-8</a> illustrates this interaction.</p><a name="wp89965"> </a><p class="pBody"></p><div align="left"><img src="images/JMS088.gif" height="87" width="361" alt="Using JMS API Local Transactions" border="0" hspace="0" vspace="0"/></div><p class="pBody"></p><p> <a name="82045"> </a><strong><font >Figure 29-8 Using JMS API Local Transactions</font></strong></p><a name="wp82046"> </a><p class="pBody">The sending of one or more messages to one or more destinations by Client 1 can form a single transaction, because it forms a single set of interactions with the JMS provider using a single session. Similarly, the receiving of one or more messages from one or more destinations by Client 2 also forms a single transaction using a single session. But because the two clients have no direct interaction and are using two different sessions, no transactions can take place between them. </p><a name="wp82047"> </a><p class="pBody">Another way of putting this is that the act of producing and/or consuming messages in a session can be transactional, but the act of producing and consuming a specific message across different sessions cannot be transactional. </p><a name="wp82048"> </a><p class="pBody">This is the fundamental difference between messaging and synchronized processing. Instead of tightly coupling the sending and receiving of data, message producers and consumers use an alternative approach to reliability, one that is built on a JMS provider's ability to supply a once-and-only-once message delivery guarantee.</p><a name="wp82049"> </a><p class="pBody">When you create a session, you specify whether it is transacted. The first argument to the <code class="cCode">createSession</code> method is a <code class="cCode">boolean</code> value. A value of <code class="cCode">true</code> means that the session is transacted; a value of <code class="cCode">false</code> means that it is not transacted. The second argument to this method is the acknowledgment mode, which is relevant only to nontransacted sessions (see <a href="JMS6.html#wp81785">Controlling Message Acknowledgment</a>). If the session is transacted, the second argument is ignored, so it is a good idea to specify <code class="cCode">0</code> to make the meaning of your code clear. For example:</p><div class="pPreformattedRelative"><pre class="pPreformattedRelative">session = connection.createSession(true, 0);<a name="wp82056"> </a></pre></div><a name="wp82057"> </a><p class="pBody">The <code class="cCode">commit</code> and the <code class="cCode">rollback</code> methods for local transactions are associated with the session. You can combine queue and topic operations in a single transaction if you use the same session to perform the operations. For instance, you can use the same session to receive a message from a queue and send a message to a topic in the same transaction.</p><a name="wp82058"> </a><p class="pBody">You can pass a client program's session to a message listener's constructor function and use it to create a message producer, so that you can use the same session for receives and sends in asynchronous message consumers. </p><a name="wp82059"> </a><p class="pBody">The next section provides an example of the use of JMS API local transactions.</p><a name="wp83801"> </a><h5 class="pHeading4">A Local Transaction Example</h5><a name="wp83804"> </a><p class="pBody">The <code class="cCode"><a href="../examples/jms/advanced/src/TransactedExample.java" target="_blank">TransactedExample.java </a></code>program in the directory <code class="cCode"><</code><code class="cVariable">INSTALL</code><code class="cCode">>/j2eetutorial14/examples/jms/advanced/src/</code> demonstrates the use of transactions in a JMS client application. This example shows how to use a queue and a topic in a single transaction as well as how to pass a session to a message listener's constructor function. The program represents a highly simplified e-Commerce application, in which the following things happen.</p><div class="pSmartList1"><ol type="1" class="pSmartList1"><a name="wp87228"> </a><div class="pSmartList1"><li>A retailer sends a <code class="cCode">MapMessage</code> to the vendor order queue, ordering a quantity of computers, and waits for the vendor's reply:</li></div><a name="wp87883"> </a><p class="pBodyRelative"><code class="cCode">producer = <br /> session.createProducer(vendorOrderQueue);<br />outMessage = session.createMapMessage();<br />outMessage.setString("Item", "Computer(s)");<br />outMessage.setInt("Quantity", quantity);<br />outMessage.setJMSReplyTo(retailerConfirmQueue);<br />producer.send(outMessage);<br />System.out.println("Retailer: ordered " + <br /> quantity + " computer(s)");<br /><br />orderConfirmReceiver =<br /> session.createConsumer(retailerConfirmQueue);<br />connection.start();</code></p><a name="wp87884"> </a><div class="pSmartList1"><li>The vendor receives the retailer's order message and sends an order message to the supplier order topic in one transaction. This JMS transaction uses a single session, so we can combine a receive from a queue with a send to a topic. Here is the code that uses the same session to create a consumer for a queue and a producer for a topic:</li></div><a name="wp87635"> </a><p class="pBodyRelative"><code class="cCode">vendorOrderReceiver = <br /> session.createConsumer(vendorOrderQueue);<br />supplierOrderProducer = <br /> session.createProducer(supplierOrderTopic);</code></p><a name="wp87671"> </a><p class="pBodyRelative">The following code receives the incoming message, sends an outgoing message, and commits the session. The message processing has been removed to keep the sequence simple:</p><a name="wp87646"> </a><p class="pBodyRelative"><code class="cCode">inMessage = vendorOrderReceiver.receive();<br />// Process the incoming message and format the outgoing message<br />...<br />supplierOrderProducer.send(orderMessage);<br />...<br />session.commit();</code></p><a name="wp87544"> </a><div class="pSmartList1"><li>Each supplier receives the order from the order topic, checks its inventory, then sends the items ordered to the queue named in the order message's <code class="cCode">JMSReplyTo</code> field. If it does not have enough in stock, the supplier sends what it has. The synchronous receive from the topic and the send to the queue take place in one JMS transaction.</li></div><a name="wp87745"> </a><p class="pBodyRelative"><code class="cCode">receiver = session.createConsumer(orderTopic);<br />...<br />inMessage = receiver.receive();<br />if (inMessage instanceof MapMessage) {<br /> orderMessage = (MapMessage) inMessage;<br /> // Process message<br />MessageProducer producer =<br /> session.createProducer((Queue) <br /> orderMessage.getJMSReplyTo());<br />outMessage = session.createMapMessage();<br />// Add content to message<br />producer.send(outMessage);<br />// Display message contents<br />session.commit();</code></p><a name="wp87853"> </a><div class="pSmartList1"><li>The vendor receives the replies from the suppliers from its confirmation queue and updates the state of the order. Messages are processed by an asynchronous message listener; this step shows the use of JMS transactions with a message listener.</li></div><a name="wp87915"> </a><p class="pBodyRelative"><code class="cCode">MapMessage component = (MapMessage) message;<br />...<br />orderNumber = <br /> component.getInt("VendorOrderNumber");<br />Order order = <br /> Order.getOrder(orderNumber).processSubOrder(component);<br />session.commit();</code></p><a name="wp83809"> </a><div class="pSmartList1"><li>When all outstanding replies are processed for a given order, the vendor message listener sends a message notifying the retailer whether it can fulfill the order.</li></div><a name="wp87997"> </a><p class="pBodyRelative"><code class="cCode">Queue replyQueue = <br /> (Queue) order.order.getJMSReplyTo();<br />MessageProducer producer = <br /> session.createProducer(replyQueue);<br />MapMessage retailerConfirmMessage = <br /> session.createMapMessage();<br />// Format the message<br />producer.send(retailerConfirmMessage);<br />session.commit();</code></p><a name="wp83810"> </a><div class="pSmartList1"><li>The retailer receives the message from the vendor: </li></div><a name="wp87894"> </a><p class="pBodyRelative"><code class="cCode">inMessage = <br /> (MapMessage) orderConfirmReceiver.receive();</code></p></ol></div><a name="wp83820"> </a><p class="pBody"><a href="JMS6.html#wp83822">Figure 29-9</a> illustrates these steps.</p><a name="wp89971"> </a><p class="pBody"></p><div align="left"><img src="images/TransactedExample9.gif" height="295" width="447" alt="Transactions: JMS Client Example" border="0" hspace="0" vspace="0"/></div><p class="pBody"></p><p> <a name="83822"> </a><strong><font >Figure 29-9 Transactions: JMS Client Example</font></strong>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -