📄 ch08s32.html
字号:
<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>JMS as a managed resource</title><link rel="stylesheet" href="styles.css" tppabs="http://www.huihoo.org/jboss/online_manual/3.0/styles.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets Vimages/callouts/"><link rel="home" href="index.html" tppabs="http://www.huihoo.org/jboss/online_manual/3.0/index.html" title="JBoss 3.0 Documentation"><link rel="up" href="ch08.html" tppabs="http://www.huihoo.org/jboss/online_manual/3.0/ch08.html" title="Chapter 8. JBoss and JMS"><link rel="previous" href="ch08s20.html" tppabs="http://www.huihoo.org/jboss/online_manual/3.0/ch08s20.html" title="Message Driven Beans and JBoss"><link rel="next" href="ch09.html" tppabs="http://www.huihoo.org/jboss/online_manual/3.0/ch09.html" title="Chapter 9. JBossSX Security Extension Framework"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><table border="0" cellpadding="0" cellspacing="0" height="65"><tr height="65"><td rowspan="2"><img src="jboss.gif" tppabs="http://www.huihoo.org/jboss/online_manual/3.0/jboss.gif" border="0"></td><td rowspan="2" background="gbar.gif" tppabs="http://www.huihoo.org/jboss/online_manual/3.0/gbar.gif" width="100%" align="right" valign="top"><a href="index.html" tppabs="http://www.huihoo.org/jboss/online_manual/3.0/index.html"><img src="doc.gif" tppabs="http://www.huihoo.org/jboss/online_manual/3.0/doc.gif" border="0"></a><a href="ch08.html" tppabs="http://www.huihoo.org/jboss/online_manual/3.0/ch08.html"><img src="toc.gif" tppabs="http://www.huihoo.org/jboss/online_manual/3.0/toc.gif" border="0"></a><a href="ch08s20.html" tppabs="http://www.huihoo.org/jboss/online_manual/3.0/ch08s20.html"><img src="prev.gif" tppabs="http://www.huihoo.org/jboss/online_manual/3.0/prev.gif" border="0"></a><a href="ch09.html" tppabs="http://www.huihoo.org/jboss/online_manual/3.0/ch09.html"><img src="next.gif" tppabs="http://www.huihoo.org/jboss/online_manual/3.0/next.gif" border="0"></a></td></tr><tr></tr></table><div class="section"><a name="jms-resource"></a><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="jms-resource"></a>JMS as a managed resource</h2></div></div><p>It has always been possible in JBoss to send JMS messages from EJB session and entity beans, either through JBossMQ or another JMS provider. This is done through normal JMS programming. But programming JMS like this is in some ways outside the EJB contract, since the JMS stuff never gets handled as a container-managed resource. This means, for example, that your JMS code is never enlisted in any transaction management and that you cannot pool your JMS sessions and therefore might run out of them.</p><p>Starting with EJB v2.0 and J2EE v1.3, there is, however, the requirement that the access to JMS connections and sessions be done as true J2EE resources, much like a DataSource. This means that a J2EE server that is compliant with the 1.3 specification must be able to handle JMS as a managed resource. JBoss version <span class="bold"><b>2.4.0</b></span> is compliant in this respect, but <span class="emphasis"><i>not</i></span> previous versions of JBoss.</p><p>[<span class="bold"><b>2.4.0</b></span>. What does this mean to you? It means that from JBoss version <span class="bold"><b>2.4.0</b></span> on, you have to define your JMS resources in the deployment descriptor, look them up as you do with other resources and use them as resources too. The container will then pool your JMS resources for you and it will enlist them with any ongoing or to be started transactions, much like using a DataSource.</p><p>The new resource management of JMS is based on a JMS resource adapter compatible with the J2EE Connector architecture (the first of its kind ;-)). The resource adapter is included in the distribution, in file <tt>deploy/lib/jms-ra.rar</tt>, but generally you don't have to worry about it because it is automatically deployed and configured in <tt>jboss.jcml</tt> for distributed transactions.</p><p>The management of JMS as a resource is available to all EJB types, session, entity and message-driven, but not (as far as I know) from the web container. The reason behind this is that the web container does not know how to handle transactions.</p><p>To use JMS as a resource, two things need to be done. One has two write resource-compatible JMS code and the resource must be added to the deployment descriptors. Let's work through all this with a simple example.]</p><div class="section"><a name="jms-resource-example"></a><div class="titlepage"><div><h3 class="title"><a name="jms-resource-example"></a>[<span class="bold"><b>2.4.0</b></span>] JMS resource example</h3></div></div><p>The example is based on a simple pattern. A session bean receives invocations containing messages. We might think that processing these messages requires too much time. Therefore, we want to handle them asynchronously: instead of letting the session bean process them, it simply passes them on to a JMS destination and it may therefore return immediately. Another reason could be that we want multiple systems to be able to act on the messages, so they get sent to a topic open up for many subscribers.</p><p>As in every case when handling resources, we need a name to look the resource up; after creation, the container will bind the resource to that name. For JMS (as opposed to a DataSource) we need access to two resources, a connection factory and a destination, so we will need two names:</p><div class="figure"><p><a name="d0e5571"></a><b>Figure 8.77. [<span class="bold">2.4.0</span>] Name giving for looking up JMS resources</b></p><pre class="programlisting">
/**
* Name used to lookup TopicConnectionFactory
*/
private static final String CONNECTION_JNDI =
"java:comp/env/jms/MyTopicConnection";
/**
* Name used to lookup topic destination
*/
private static final String TOPIC_JNDI = "java:comp/env/jms/TopicName";
</pre></div><p>The lookup of these resources will be done during the creation of the bean, much like what happens with a DataSource. What's different in JMS from the handling of a DataSource is that the JMS connection (not the factory) is what is similar to the DataSource and the JMS session is like a JDBC connection. Therefore, we create the JMS connection also when the bean is created and we hold on to it as long as the bean is alive:</p><div class="figure"><p><a name="d0e5581"></a><b>Figure 8.78. [<span class="bold">2.4.0</span>] Looking up JMS resources (connection factory and destination)</b></p><pre class="programlisting">
public void ejbCreate() {
try {
Context context = new InitialContext();
// Lookup the topic
topic = (Topic)context.lookup(TOPIC_JNDI);
// Lookup the connection factory
TopicConnectionFactory factory =
(TopicConnectionFactory)context.lookup(CONNECTION_JNDI);
topicConnection = factory.createTopicConnection();
// Keep both around
} catch (Exception ex) {
// JMSException or NamingException could be thrown
ex.printStackTrace();
throw new EJBException(ex.toString());
}
}
</pre></div><p>In our example bean we have a method, <tt>hello()</tt>, that takes a text message in the form of a <tt>String</tt> object. This is the method the remote clients invoke. Every time the bean receives a message, it packs it into a JMS message and sends it along on its way to the destination. This looks very much like normal JMS code indeed:</p><div class="figure"><p><a name="d0e5597"></a><b>Figure 8.79. [<span class="bold">2.4.0</span>] Publishing messages using JMS resources</b></p><pre class="programlisting">
TopicPublisher topicPublisher = null;
TextMessage message = null;
// Create a session
topicSession = topicConnection.createTopicSession(true,
Session.AUTO_ACKNOWLEDGE);
// Create a publisher
topicPublisher = topicSession.createPublisher(topic);
// Create a message
message = topicSession.createTextMessage();
message.setText(msg);
// Publish it
System.out.println("Publishing message " + msg);
topicPublisher.publish(message);
</pre></div><p>Since we are now working in a transacted and pooled environment, we have to write the code carefully. We handle errors in our code by rolling back the transaction.</p><div class="figure"><p><a name="d0e5607"></a><b>Figure 8.80. [<span class="bold">2.4.0</span>] Marking for rollback if there are exceptions</b></p><pre class="programlisting">
try {
//... application code
} catch (JMSException ex) {
ex.printStackTrace();
ctx.setRollbackOnly();
throw new EJBException(ex.toString());
}
</pre></div><p>We also have to be careful to close the session, in case an exception occurs, in a <tt>finally</tt> block.</p><div class="figure"><p><a name="d0e5620"></a><b>Figure 8.81. [<span class="bold">2.4.0</span>] Closing JMS resources properly</b></p><pre class="programlisting">
} finally {
// ALWAYS close the session. It's pooled, so do not worry.
if (topicSession != null) {
try {
topicSession.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
</pre></div><p>Here it is the complete example bean:</p><div class="figure"><p><a name="d0e5630"></a><b>Figure 8.82. [<span class="bold">2.4.0</span>] Bean example of using JMS as a resource, from <tt>TopicHelloBean.java</tt> in directory <tt>org/jboss/docs/jms/ra/bean</tt></b></p><pre class="programlisting">
package org.jboss.docs.jms.ra.bean;
import java.rmi.RemoteException;
import javax.ejb.SessionBean;
import javax.ejb.SessionContext;
import javax.ejb.EJBException;
import javax.naming.InitialContext;
import javax.naming.Context;
import javax.jms.TopicConnectionFactory;
import javax.jms.TopicConnection;
import javax.jms.TopicSession;
import javax.jms.TopicPublisher;
import javax.jms.Topic;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.JMSException;
import org.jboss.docs.jms.ra.interfaces.*;
/**
* Hello bean, send a message to the configured topic.
* The JMS stuff is configured via the deployment descriptor.
*
* The TopicConnection is comparable to the JDBC DataSource,
* and the TopicSession to the JDBC Connection.
*
* @author Peter Antman
* @version $Revision: 3.1 $
*/
public class TopicHelloBean implements SessionBean {
/**
* Name used to lookup TopicConnectionFactory
*/
private static final String CONNECTION_JNDI =
"java:comp/env/jms/MyTopicConnection";
/**
* Name used to lookup topic destination
*/
private static final String TOPIC_JNDI = "java:comp/env/jms/TopicName";
private SessionContext ctx = null;
private Topic topic = null;
private TopicConnection topicConnection = null;
public TopicHelloBean() {
}
public void setSessionContext(SessionContext ctx) {
this.ctx = ctx;
}
public void ejbCreate() {
try {
Context context = new InitialContext();
// Lookup the topic
topic = (Topic)context.lookup(TOPIC_JNDI);
// Lookup the connection factory
TopicConnectionFactory factory =
(TopicConnectionFactory)context.lookup(CONNECTION_JNDI);
topicConnection = factory.createTopicConnection();
// Keep both around
} catch (Exception ex) {
// JMSException or NamingException could be thrown
ex.printStackTrace();
throw new EJBException(ex.toString());
}
}
/**
* Send a message with a message nr in property MESSAGE_NR
*/
public void hello(String msg) {
sendMessage(msg);
}
public void ejbRemove() throws RemoteException {
if (topicConnection != null) {
try {
// Remember to close the connection when the bean is destroyed
topicConnection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void ejbActivate() {}
public void ejbPassivate() {}
/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -