JMS : Java Message Service (Java消息服务)之二

6 JORAM使用代码举例
6.1 创建消息载体Queue和Topic并绑定Jndi
--用root用户连接Joram Server
AdminModule.connect("root", "root", 60);
    --创建Queue和Topic
Queue queue = (Queue) Queue.create("queue");
    Topic topic = (Topic) Topic.create("topic");
    --创建匿名访问用户
    User user = User.create("anonymous", "anonymous");
--设置Queue和Topic为可读、可写
    queue.setFreeReading();
    topic.setFreeReading();
    queue.setFreeWriting();
    topic.setFreeWriting();
--创建连接工厂
    javax.jms.ConnectionFactory cf =
      TcpConnectionFactory.create("localhost", 16010);
    javax.jms.QueueConnectionFactory qcf =
      QueueTcpConnectionFactory.create("localhost", 16010);
    javax.jms.TopicConnectionFactory tcf =
      TopicTcpConnectionFactory.create("localhost", 16010);
--邦定Jndi
    javax.naming.Context jndiCtx = new javax.naming.InitialContext();
    jndiCtx.bind("cf", cf);
    jndiCtx.bind("qcf", qcf);
    jndiCtx.bind("tcf", tcf);
    jndiCtx.bind("queue", queue);
    jndiCtx.bind("topic", topic);
    jndiCtx.close();
--关闭连接
    AdminModule.disconnect();
另一种创建Queue和Topic的方法:
可以将Queue和Topic的具体信息写入一个joramAdmin.XML配置文件,然后在程序中读取这个XML配置文件即可创建。举例如下:
joramAdmin.XML:
==============================================
<?xml version="1.0"?>

<JoramAdmin>
 
  <AdminModule>
    <connect host="localhost"
             port="16010"
             name="root"
             password="root"/>
  </AdminModule>
 
  <InitialContext>
    <property name="java.naming.factory.initial"
              value="fr.dyade.aaa.jndi2.client.NamingContextFactory"/>
    <property name="java.naming.factory.host" value="localhost"/>
    <property name="java.naming.factory.port" value="16400"/>
  </InitialContext>

  <ConnectionFactory className="org.objectweb.joram.client.jms.tcp.TcpConnectionFactory">
    <tcp host="localhost"
         port="16010"/>
    <jndi name="cf"/>
  </ConnectionFactory>
 
  <ConnectionFactory className="org.objectweb.joram.client.jms.tcp.TopicTcpConnectionFactory">
    <tcp host="localhost"
         port="16010"/>
    <jndi name="tcf"/>
  </ConnectionFactory>
 
  <ConnectionFactory className="org.objectweb.joram.client.jms.tcp.QueueTcpConnectionFactory">
    <tcp host="localhost"
         port="16010"/>
    <jndi name="qcf"/>
  </ConnectionFactory>
 
  <User name="anonymous"
        password="anonymous"/>

  <Queue name="queue">
    <freeReader/>
    <freeWriter/>
    <jndi name="queue"/>
  </Queue>
 
  <Topic name="topic">
    <freeReader/>
    <freeWriter/>
    <jndi name="topic"/>
  </Topic>
 
</JoramAdmin>
==============================================
代码举例:***代表配置文件的具体路径
AdminModule.connect("root", "root", 60);
AdminModule.executeXMLAdmin("***","joramAdmin.xml");
AdminModule.disconnect();
6.2 发送消息
--初始化上下文空间
ictx = new InitialContext();
--实例化Queue对象
Queue queue = (Queue) ictx.lookup("queue");
--通过Jndi邦定创建好的Queue建立连接工厂
QueueConnectionFactory qcf = (QueueConnectionFactory) ictx
.lookup("qcf");
ictx.close();
--创建Queue连接
QueueConnection qc = qcf.createQueueConnection();
--创建Queue会话
QueueSession qs = qc.createQueueSession(true, 0);
注意:此处创建的Session使用了事务模式,因此在执行具体的发送消息代码即qsend.send()方法后必须要提交Session事务,即:qs.commit(),否则消息不会发送。其他举例代码类似,不再逐一复述。
--创建QueueSender
QueueSender qsend = qs.createSender(queue);
--创建文本消息
TextMessage msg = qs.createTextMessage();
int i;
    for (i = 0; i < 10; i++) {
      --设置消息具体内容
msg.setText("Test number " + i);
--发送的消息可以设置具体的业务种类,或其他的类型标志:
msg.setIntProperty("ywlx",i);
msg.setIntProperty("****",*)
      --发送消息
qsend.send(msg);
    }
--提交Queue会话
    qs.commit();
    System.out.println(i + " messages sent.");
--关闭Queue连接
    qc.close();
消息的主体也可以是Java对象:
--创建对象消息
ObjectMessage omsg = qs.createObjectMessage();
omsg.clearBody();
--实例化并传送的Java对象
TestObj to = new TestObj();
   omsg.setObject(to);
   qsend.send(omsg);
qs.commit();
qc.close();
6.3 接收消息
--初始化上下文空间
ictx = new InitialContext();
--实例化Queue对象
Queue queue = (Queue) ictx.lookup("queue");
--通过Jndi邦定创建好的Queue建立连接工厂
QueueConnectionFactory qcf = (QueueConnectionFactory) ictx
.lookup("qcf");
ictx.close();
--创建Queue连接
QueueConnection qc = qcf.createQueueConnection();
--创建Queue会话
QueueSession qs = qc.createQueueSession(true, 0);
--创建QueueReceiver实例
QueueReceiver qrec = qs.createReceiver(queue);
--创建消息接收体
Message msg;
TestObj to;
--起动Queue连接
qc.start();
int i;
for (i = 0; i < 10; i++) {
--接收消息
msg = qrec.receive();
--接收文本消息
if (msg instanceof TextMessage)
System.out.println("Msg received: "
+ ((TextMessage) msg).getText());
--接收Java对象消息
else if (msg instanceof ObjectMessage) {
to = (TestObj) ((ObjectMessage) msg).getObject();
to.TestFunc();
} else
System.out.println("Msg received: " + msg);
}
--提交Queue会话
qs.commit();
System.out.println();
System.out.println(i + " messages received.");
--关闭Queue连接
qc.close();
接收指定业务种类的消息:
--指定接收消息的具体类型
此处用到了Message Selector来创建QueueReceiver对象,详细介绍请参看前面的介绍。
String strMsgSelect = "ywlx=0";
QueueConnection qc = (QueueConnection) qcf.createQueueConnection();
QueueSession qs = (QueueSession) qc.createQueueSession(true, 0);
--用MesageSelecter创建QueueReceiver对象
QueueReceiver qrec = (QueueReceiver) qs.createReceiver(queue,
strMsgSelect);
--接收指定的消息;
msg = (Message) qrec.receive();
6.4 发布消息
--初始化上下文空间
ictx = new InitialContext();
--实例化Topic对象
Topic topic = (Topic) ictx.lookup("topic");
--通过Jndi邦定创建好的Topic建立连接工厂
TopicConnectionFactory tcf = (TopicConnectionFactory) ictx.lookup("tcf");
ictx.close();
--创建Topic连接
TopicConnection tc = tcf.createTopicConnection();
--创建Topic会话
TopicSession ts = tc.createTopicSession(true, 0);
--创建消息发布实例
TopicPublisher tpub = ts.createPublisher(topic);
--创建文本消息
TextMessage msg = ts.createTextMessage();
int i;
for (i = 0; i < 10; i++) {
msg.setText("Test number " + i);
    --发布消息
tpub.publish(msg);
}
--提交Topic会话
ts.commit();
System.out.println(i + " messages published.");
--关闭Topic连接
tc.close();
6.5 订阅消息
--初始化上下文空间
ictx = new InitialContext();
--实例化Topic对象
Topic topic = (Topic) ictx.lookup("topic");
--通过Jndi邦定创建好的Topic建立连接工厂
TopicConnectionFactory tcf = (TopicConnectionFactory) ictx.lookup("tcf");
ictx.close();
--创建Topic连接
TopicConnection tc = tcf.createTopicConnection();
--创建Topic会话
TopicSession ts = tc.createTopicSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
--创建消息订阅实例
TopicSubscriber tsub = ts.createSubscriber(topic);
--订阅消息
tsub.setMessageListener(new MsgListener());
--起动Topic连接
tc.start();
System.in.read();
--关闭Topoc连接
tc.close();
其中MsgListener类是一个实现了MessageListener接口的具体类,它实现了onMessage方法,具体处理监听到的消息。监听启动后,一旦队列中出现了被监听的消息,系统会自动调用MsgListener的onMessage方法去处理消息。
MsgListener类:
public class MsgListener implements MessageListener{
String ident = null;
public MsgListener(){}
public MsgListener(String ident){
this.ident = ident;
}
public void onMessage(Message msg){
try {--根据不同的消息类型接收消息
    if (msg instanceof TextMessage) {
       if (ident == null)
       System.out.println(((TextMessage) msg).getText());
   else
       System.out.println(ident + ": " + ((TextMessage) msg).getText());
    }
      else if (msg instanceof ObjectMessage) {
if (ident == null)
          System.out.println(((ObjectMessage) msg).getObject());
        else
          System.out.println(ident + ": " + ((ObjectMessage) msg).getObject());
      }
    }catch (JMSException jE) {
     System.err.println("Exception in listener: " + jE);
    }
  }
}

6.6 产生消息
--初始化上下文空间
ictx = new InitialContext();
--实例化Queue对象
Queue queue = (Queue) ictx.lookup("queue");
--实例化Topic对象
Topic topic = (Topic) ictx.lookup("topic");
--通过Jndi邦定建立连接工厂
ConnectionFactory cf = (ConnectionFactory) ictx.lookup("cf");
ictx.close();
--创建连接
Connection cnx = cf.createConnection();
--创建会话
Session sess = cnx.createSession(true, 0);
--创建产生消息实例
MessageProducer producer = sess.createProducer(null);
--创建文本消息
TextMessage msg = sess.createTextMessage();
int i;
for (i = 0; i < 10; i++) {
msg.setText("Test number " + i);
--在Queue上产生消息
producer.send(queue, msg);
--在Topic上产生消息
producer.send(topic, msg);
}
--提交会话
sess.commit();
System.out.println(i + " messages sent.");
--关闭连接
cnx.close();
6.7 消费消息
--初始化上下文空间
ictx = new InitialContext();
--实例化Queue对象
Queue queue = (Queue) ictx.lookup("queue");
--实例化Topic对象
Topic topic = (Topic) ictx.lookup("topic");
--通过Jndi邦定建立连接工厂
ConnectionFactory cf = (ConnectionFactory) ictx.lookup("cf");
ictx.close();
--创建连接
Connection cnx = cf.createConnection();
--创建会话
Session sess = cnx.createSession(false, Session.AUTO_ACKNOWLEDGE);
--创建消费消息实例
MessageConsumer recv = sess.createConsumer(queue);
MessageConsumer subs = sess.createConsumer(topic);
--订阅Queue和Topic上的消息
recv.setMessageListener(new MsgListener("Queue listener"));
subs.setMessageListener(new MsgListener("Topic listener"));
--起动连接
cnx.start();
System.in.read();
cnx.close();
System.out.println();
System.out.println("Consumer closed.");
6.8 对Queue的清理操作
--创建连接
AdminModule.connect("root", "root", 60);
--读取server.properties具体配置信息
ictx = new InitialContext(JMSConstant.getProp());
Queue queue = (Queue) ictx.lookup("queue");
--清理Queue
queue.clear();
6.9 Connectiion的注意事项:
在创建jms客户端的时候.有一个问题值得注意.在一个jms运用当中,至少需要两个客户端(消息发送端和消息接手端).每个客户端都需通过jndi去找连接工厂.并且创建一个连接。
消息发送端:
………………………………………………………………………………………….
ConnectionFactory cf = (ConnectionFactory) ictx.lookup("cf");
Connection cn = cf.createConnection();
……………………………………………………………………………………………...
消息接收端
…………………………………………………………………………………………...
ConnectionFactory cf = (ConnectionFactory) ictx.lookup("cf");
Connection cn = cf.createConnection();
…………………………………………………………………………………………..
两个客户端都享有一个连接工厂,而且很可能占有同一个连接,如果当接收端需要调用cn.close()关闭连接.cn.start ();打开连接,或者发送段cn.close()关闭连接.cn.start ();就会发生不可预料的情况.
要区别连接是很必要的.所以我们创建2个User.分别如下:
//User user= User.create(String username,PassWord password,Int serverID);
User user1=User.create(“user1”,”user1”,0);
User user2=User.create(“user2”,”user2”,0);
然后根据不同的用户,来创建一个不同的连接.
消息发送端
…………………………………………………………………………………….
ConnectionFactory cf = (ConnectionFactory) ictx.lookup("cf");
Connection cn = cf.createConnection(“user1”,”user1”);
………………………………………………………………...
消息接收端
………………………………………………………………….
ConnectionFactory cf= (ConnectionFactory) ictx.lookup(“cf”);
Connection cn = cf.createConnection(“user2”,”user2”);
6.10设置消息监听
在消息的接收客户端(包括接收者和订阅者以及消息消费者)都可以设置消息监听,当消息监听监听到消息目的地有消息,就接收消息,注意监听和接收在程序级别上是不可分隔的。JMS提供了一个消息监听接口,只需实现消息监听的onMessage(Message Msg)方法。
代码如下:
创建一个消息监听实现类:
Public class MsgListener implments MessageListener{
Public void onMessage(Message Msg){
…………….//实现代码,处理数据。
}
};
P2p:receiver.setMessageListener(new MsgListener());
p/s: subscriber.setMessageListener(new MsgListener());
注意:一个消息接收端设置一个监听,如果共用一个监听,可能会出现资源同步占用。
onmessage由于
6.11消息接收的过期
在消息接收当中,可以在receiver(Long TimeOut)设置接收消息的过期时间,如果在取消息的时候没有符合过滤器相对应的消息,那么在时间过期后返回一个null值,我们可以对这个null做判断,来关闭连接.这个方法可用于各种消息模式中.
注意:receive()这个动作是一次性的,一个recevie()动作只接收一个消息.消息的单位数也取决与send()这个动作的次数.既是,send()动作一次,那么所发送的消息个数为一.
代码如下:
Session se =new Session();
Receiver re= se.create(Queue queue,String messageselector );
Message msg;
msg = qrec.receive(3000);;//设置消息接收过期时间3秒.
………………………//消息处理
Msg.getText();//如果消息在过期时间内没有接受消息,那么返回一个null值.
如果在接收的时候,不需要等待,那么可以调用recevieNoWait();那么如果在queue没有相应的消息,立即返回一个null.
代码如下:
Session se =new Session();
Receiver re= se.create(Queue queue,String messageselector );
Message msg;
msg = qrec.receiveNoWait();;// 接收消息不等待.
………………………//消息处理
Msg.getText();//如果消息在过期时间内没有接受消息,那么返回一个null值.

posted @ 2010-07-17 07:37  采云摘月  阅读(579)  评论(0编辑  收藏  举报