细心!用心!耐心!

吾非文人,乃市井一俗人也,读百卷书,跨江河千里,故申城一游; 一两滴辛酸,三四年学业,五六点粗墨,七八笔买卖,九十道人情。

BlogJava 联系 聚合 管理
  1 Posts :: 196 Stories :: 10 Comments :: 0 Trackbacks

快速应用JMS控件访问JMS资源

 

JMS定义了Java中访问消息中间件的接口,是企业资源异步访问的主要形式。JMS可以和EJB技术集成使用,也就是常说的消息驱动BEAN。

  因为访问JMS和访问Entity EJB和SessionEJB的调用方法有很大的差异,所以Beehive中提供了专门的JMS控件来完成JMS资源的访问。

创建JMS控件的典型步骤
  Beehive中提供的JMS控件无法直接用于访问JMS资源,使用者必须继承JMS控件来创建自己的访问控件,设置相关的环境后才能完成JMS资源的访问。一个继承控件中只能对应的访问唯一一个消息队列/主题,如果需要向多个消息队列/主题发送消息,必须针对每个消息队列/主题提供相应的控件。

  你可以使用下面的步骤来创建自己的控件实现对JMS资源的访问:

创建新的Java接口,继承JMSControl接口
用@ControlExtension关键字注释新创建的Java接口,通知解析器这个接口继承了另外的某个控件。
使用@JMSControl.Destination注释新创建的Java接口,说明控件如何搜索消息队列/主题,同时使用sendType声明发送目标是消息队列还是消息主题。
创建新的业务方法,使用JMSControl.Message注释来声明被发送消息的类型,或者使用不同的参数来区别不同的消息类型。
使用控件访问消息队列的例子
  在本节中,我们将通过简单的例子演示如何使用JMS控件来访问监听消息队列的消息驱动Bean。我们假设存在一个消息驱动Bean,他接受用户传递的文本消息(TextMessage),随后将该文本消息打印在应用服务器的控制台上。该消息驱动Bean监听消息队列(jndiname=”queue/helloworld”)。

  Beehive并不仅仅限于WebLogic平台使用,我们这里以JBoss为例。我们使用Eclipse+WTP(Web Tools Platform)工具开发符合要求的消息驱动Bean以及JMS队列,发布在JBoss上。

  本文中所有例子的源代码可以在通过资源下载区中的连接完成下载。

开发消息驱动Bean
  现在我们来开发提供上述功能的消息驱动Bean,使用WTP的向导完成消息驱动Bean的创建工作,剩下的工作就是根据业务的需求完成onMessage方法的编写了。

  根据演示实例的要求,我们修改onMessage方法,让它处理TextMessage类型的消息,并且将消息的内容打印在控制台上,清单1中列出了消息驱动Bean类的源代码。如何开发、编译和部署请参考JBoss的帮助文档,这里不提供详细的说明。

  接下来的JMS、EJB开发、部署和控件访问部分内容针对JBoss应用服务器。实际情况下,你可能根据不同情况选择其他的J2EE容器比如Websphere 、WebLogic、Geronimo、JOnAS等作为EJB容器,请根据下面的提示信息进行适当的调整。

  清单1 ejbsrc\org\vivianj\beehive\controls\examples\ejb\MessageBeanOnQueue.java

1. package org.vivianj.beehive.controls.examples.ejb;
2. 
3. import javax.ejb.*;
4. import javax.jms.*;
5. 
6. public class MessageBeanOnQueue
7.   implements MessageDrivenBean, MessageListener
8. {
9.   public void onMessage(Message msg) {
10.     TextMessage tm = null;
11.     if (msg instanceof TextMessage){
12.         tm = (TextMessage) msg;
13.         try{
14.         System.out.println(tm.getText());
15.         }catch(Exception e){
16.             e.printStackTrace();
17.         }
18.     }
19.   }
20. }
  在部署消息驱动Bean之前,我们还应该在JBoss服务器上配置一个JNDI名称为“queue/helloworld”的消息队列。请大家参考JBoss应用服务器的帮助文档完成这部分工作。

JMS控件开发
  现在我们来使用JMS控件编写代码访问消息驱动Bean。由于消息驱动Bean没有本地或者远程访问方法,只能通过向JMS目标发送消息来完成消息驱动Bean资源的调用。

  清单2中的代码是访问一个JMS目标对列的简单例子,它提供sendTextMessage方法,接收String类型的参数msn,当sendTextMessage方法被调用时,控件负责连接到JMS对列(“queue/helloworld”),将接收到的参数msg发送到目标服务器上。

  清单2 src\org\vivianj\beehive\controls\examples\controls\

  HelloWorldQueueJMSControl.java

1. package org.vivianj.beehive.controls.examples.controls;
2. 
3. import org.apache.beehive.controls.api.bean.ControlExtension;
4. import org.apache.beehive.controls.system.jms.JMSControl;
5. 
6. /**
7. * HelloWorldQueueJMSControl 是访问JMS资源的控件
8. * 可向JMS对列发送字符串类型的消息
9. */
10. 
11. @ControlExtension
12. @JMSControl.Destination(sendJndiName = “queue/helloworld”,
13.      jndiConnectionFactory =
14.         “org.jnp.interfaces.NamingContextFactory”,
15.      jndiProviderURL=“jnp://localhost:1099”,
16.      sendType=DestinationType.Queue)
17. public interface HelloWorldQueueJMSControl
18.     extends JMSControl {
19.       @JMSControl.Message(MessageType.Text)
20.      public void sendTextMessage(String msg);
21. }
JMS控件调用
  现在我们可以使用如下方法来完成上面所创建控件的调用。

  使用声明式控件实例化定义成员变量_jmsControl.

   @Control

   HelloWorldQueueJMSControl _jmsControl;

   调用控件的业务方法完成向JMS对列发送消息的功能。由于消息服务本身是没有返回内容的,所以我们只需要完成业务方法的调用即可。

  下面的调用代码可以实现向服务器发送”Hello World!”字符串的功能。

  _jmsControl.sendTextMessage(“Hello World!”);

测试控件
  一切准备就绪后,启动JBoss服务器,参考《控件入门》中“使用JUnit测试控件”部分的内容,编写单元测试TestCase测试新创建的JMS控件。

实例分析
  从上面的例子中我们可以看到,访问JMS资源的时候,开发者的工作被大大的简化了。开发者只需要开发一个继承自JMS控件的控件,使用JMS控件中规定的注释提供访问JMS资源所需要的一些环境参数,随后便可以使用声明式控件实例化方式完成控件的实例化,通过调用该控件实例的相关业务方法完成JMS资源的访问。

  现在我们来分析一下上面创建的EJB控件-- HelloWorldQueueJMSControl (参见清单2)中的主要代码。

11.   @ControlExtension
 在控件例子的11行,我们通过@ControllerExcention关键词来说明接下来声明的这个接口是另外一个控件的扩展。
12.   @JMSControl.Destination(sendJndiName = “queue/helloworld”,
13.      jndiConnectionFactory =
14.        “org.jnp.interfaces.NamingContextFactory”,
15.     jndiProviderURL=“iiop://localhost:7001”,
16.     sendType=DestinationType.Queue))
  在第12~16行代码中我们使用JMSControl.Destination关键词和它的sendJndiName、jndiConnectionFactory、jndiProviderURL和sendType属性来设置我们要访问消息队列/主题在目标服务器中发布时使用的jndiName和访问目标服务器需要提供的相关环境变量。

17.    public interface HelloWorldQueueJMSControl
18.        extends JMSControl {
 在第17~18行中,我们声明该控件继承了JMSControl接口。
19.   @JMSControl.Message(MessageType.Text)
 在第19行,我们使用@JMSControl.Message关键字来声明接下来的这个业务方法发送消息的类型是TextMessage。
20.    public void sendTextMessage(String msg);
   第20行代码我们声明了一个方法,这个方法需要向目标消息队列/主题发送参数msg提供的字符串。

  完成这些工作,我们就可以调用该控件声明的方法实现向目标消息队列/主题发送JMS消息了,如何与目标应用服务器交互的工作由控件来辅助完成。

使用注释定制JMS控件
  在上面的内容中,我们已经新建了一个JMS控件,它提供sendTextMessage方法,调用该方法能够向消息对列”queue/helloworld”发送消息。在JMS控件代码中,我们使用了@JMSControl.Destination我们使用了@JMSControl.Destination和@JMSControl.Message两个注释来提供访问JMS资源的参数。

  JMS控件支持10个注释,他们分别是@JMSControl.CorrelationId、@JMSControl.Delivery 、@JMSControl.Destination 、@JMSControl.Expiration 、@JMSControl.Message 、@JMSControl.Priority 、@JMSControl.Properties 、@JMSControl.Property 、@JMSControl.PropertyValue 、@JMSControl.Type

  下面我们详细的介绍其中最常用的@JMSControl.Destination和@JMSControl.Message两个注释的属性和用法,了解如何用这注释定制JMS控件的更多细节。

Destination注释
  Destination注释是类级别的注释,用于定制JMS控件发送消息的目标消息队列/主题的jndiName和它们所在目标容器的相关参数。Destination注释提供了八个参数用于用户定制,下面将介绍常用的四个:sendJndiName、jndiConnectionFactory、 sendType、jndiProviderURL,其中sendJndiName和jndiConnectionFactory是必须的,其他的可以根据不同的情况选择性的使用。

sendJndiName
  字符串类型的属性,用于设置目标消息队列或者主题的JNDI名称。

sendType
  JMSControl.DestinationType类型的属性,可选值有三个:DestinationType.Auto(自动适配类型),DestinationType.Topic(主题)和DestinationType.Queue(队列),如果使用DestinationType.AUTO,控件将根据sendJndiName中指定的目标消息类型进行适配。

jndiConnectionFactory
  字符串类型的属性,设置访问EJB JNDI上下文环境需要使用工厂类,和具体的目标EJB服务器相关。比如访问JBoss服务器上的JMS资源时可以设置jndiConnectionFactory为“org.jnp.interfaces.NamingContextFactory”。

jndiProviderURL
  字符串类型的属性,设置目标EJB容器的相关属性,包括访问JNDI上下文环境使用的协议、目标服务器IP地址、服务端口等,比如访问JBoss容器中消息队列时,providerURL可以写成”jnp://localhost:1099”。

Message注释
  Message注释是JMS控件中方法级别的注释,它的参数为JMSControl.MessageType类型,用于注释新创建JMS控件的业务方法,声明该业务方法发送消息的类型,可选参数包括MessageType.Text、MessageType. Bytes(字节类型)、MessageType.Object(对象类型), MessageType.Map (Map类型)、MessageType.JMSMessage(JMS消息类型)、MessageType.Auto(自动适配类型),默认的消息类型是MessageType.Auto。

  如果使用默认的消息类型或者设置被发送消息的类型为MessageType.Auto,控件将根据被发送消息的类型来决定发送消息时使用的消息类型:

如果被发送的消息是字符串内容或者是XML对象,控件将发送TextMessage类型的消息给目标消息队列/主题;
如果被发送的消息内容是字节数组,控件将发送StreamMessage类型的消息给目标消息队列/主题;
如果被发送的消息内容是字节数组,控件将发送StreamMessage类型的消息给目标消息队列/主题;
如果被发送的消息内容是Map对象,控件将发送MapMessage类型的消息给目标消息队列/主题;
如果被发送的消息内容是JMSMessage对象,控件将发送JMSMessage类型的消息给目标消息队列/主题;
如果被发送的消息内容实现了Serializable接口,控件将发送ObjectMessage类型的消息给目标消息队列/主题;
其他的消息内容,控件将不发送消息,而是抛出一个违例。
JMS控件内置的方法
  JMS控件提供了很多可以在运行时对JMS控件进行定制的Java方法,开发者使用这些内置的方法可以在使用JMS控件的过程中根据不同的情况灵活的加以应用,以便能够完成各种复杂的业务逻辑。

getSession()
  获取当前访问消息队列/主题的会话对象。

getDestination()
  获取当前访问消息队列/主题的目标服务的相关信息。

getConnection()
  获取当前访问消息队列/主题和目标服务器之间的连接。

setHeaders(Map)
setHeader(HeaderType,Object)
  这两个方法都用于设置被发送消息的头信息,只有调用了这两个方法后接着发送的消息才使用这部分头信息,其他的消息不具备这些头信息。如果发送的消息中也设置了同样的信息,使用setHeaderX方法设置的参数将覆盖消息中设置的参数。

  被设置的头信息包括JMSCorrelationID、JMSExpriation 、Priority 、JMSType,用于发送消息时标识身份或者提供消息发送所需要的路由。

setProperties(Map)
setProperty(String,Object)
  这两个方法用于在发送消息的同时提供更多的属性信息,可以用于在应用中作为扩展头信息而使用,可发送的类型可以是boolean, byte, short, int, long, float, double, or String等基本Java数据类型。

结束语
  JMS是J2EE框架中最重要的部分,也是企业应用中提供异步消息访问的技术实现,然而JMS的客户端编写对于开发者而言不是一件轻松的事情。控件架构中的JMS控件大大的简化了JMS资源的复杂性、难度,开发者只需要通过简单的继承org.apache.beehive.controls.system.jms.JMSControl,然后通过提供相应的注释就可以完成JMS资源的访问。

posted on 2007-05-06 12:54 张金鹏 阅读(184) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航: