在开始之前需要说明,为了理解本文,我们希望读者拥有java编程的相当坚实的基础。我们将试图尽可能简单地解释什么是jms,但是在你能够建立自己的程序并正确地理解它们之前,你需要有一些使用jndi开发实际应用程序的经验。
jms(java消息服务)是一个消息交换标准,它允许使用j2ee应用程序组件建立、发送、接收和读取消息。它假设分布式通讯拥有自由(free)的连接、是可靠的(reliable)和异步的(asynchronous)。
exchange(交换)系统
消息交换反映了程序组件或应用程序之间的一种交互作用。消息交换系统是一种类似于下的系统:一个相似系统的客户端可以发送和接收任何其它客户端的消息。每个客户端都并入系统的代理中,它提供了建立、发送、接收和读取消息的可能。
交换系统使得分布式的交互操作成为可能。组件在目的地(destination)发送消息,收件人也可以在相同的目的地中得到这个消息。发送者和收件人不一定是互相熟悉的。换句话说,它并没有强迫发送者知道一些收件人的信息,也没有强迫收件人知道某些发送者的信息。发送者和收件人只需要知道消息的格式以及要到达的目的地。在这种情形下,上述的系统不同于与它紧密相连的一些技术,例如远程方法调用(rmi),它只要求开发人员了解rmi中的一些方法。
消息传递系统
消息传递系统是一种分布式的系统,是基于系统组件之间的异步消息交换。面向消息的中间件(message-oriented middleware,mom)就是这种产品,消息传递系统是在它的原理上建立的。
消息传递系统应用软件不会直接地通讯(这与传统的系统(基于rmi的)形成鲜明的对照),而需要依赖mom的帮助。如果系统的某个组件希望给另一个组件发送消息,它将把给定的消息发送给mom,接着mom把该消息发送给收件人。
![]() |
与传统的基于rmi构建的系统相比,它有以下优点:
? 发送消息的应用程序不需要期待回应,可以继续执行。
? 没有强迫发送消息的应用程序和特定消息的收件人在某个特定的时刻是激活的。如果消息的收件人不是激活的,mom保证收件人一旦激活就立即收到该消息。
? 系统组件没有直接地彼此相连。它们被分离开了,这就是在运行时刻能把组件从一个主机传输到另一个、却不会中断系统可用性的原因。
消息交换模型:点对点模型和发表-预订模型
目前有两种“基本的”消息交换模型:点对点模型和发表-预订(pub-sub)模型。点对点模型应用于一个或多个组件(发送者)仅仅给一个组件收件人(接收者)发送消息的情形。这种模型是基于消息队列概念的:发送者把消息发送到队列中,接收者从该队列中读取消息。在点对点模型中,相同的队列上可能存在多个接收者,但是mom只给其中一个传递消息。给哪一个传递消息依赖于mom的实现(implementation)。
发表-预订模型应用于一个或多个组件(发表者)给一个或多个组件收件人(预订者)发送消息的情形。这种特定的模型是基于消息主题(message topic)概念的:发表者把消息发送到某个主题中,而该特定主题的预订者接收这些消息。
发表-预订模型看起来更加“优雅”,但是很多发表-预订模型不能保证消息按照发送的次序传递(它与点对点模型相反,点对点队列实现了fifo(先进先出)原理)。因此,消息的次序很重要(或者为了同步需要使用消息的头和属性部分)的时候,就应该避免采用发表-预订模型。
java消息服务(jms)是使用面向消息中间件的一套java api,它允许你的应用程序建立、发送、接收和读取消息。这组程序集位于j2ee程序包结构树上的javax.jms程序包中。jms在很多mom产品中得到了实现,其中iplanet message queue、 ibm mqseries、progress software sonicmq、bea weblogic server、prism technologies openfusion等最有名气,也存在一些免费的实现。
jms同时支持消息交换的两种“基本的”模型。但是,其说明(specification)并没有要求厂商同时实现两种模型,尽管大多数jms产品实现了点对点和发表-预订模型。
jms应用程序
jms应用程序的主要部分是:
? 产生连接的部分和目的地
? 连接
? 对话
? 产生消息的部分
? 使用消息的部分
? 消息
产生连接的部分(connectionfactory)是负责建立jms连接的对象。每个connectionfactory都是queueconnectionfactory或topicconnectionfactory的一个副本(copy)。mom管理器建立特定的对象,并把它与jndi树关联起来,这样jms客户端就能够使用标准的jndi查找表得到connectionfactory的入口。在点对点的模型中,它使用了javax.jms.queueconnectionfactory;在发表-预订模型中,它使用的是javax.jms.topicconnectionfactory。
目的地(destination)――它是队列或主题,这依赖于我们使用了下面哪种模型:javax.jms.queue或javax.jms.topic。
连接(connection)――它可能是客户端和服务应用之间的开放的tcp/ip。它可以被用于建立一个或少量的对话。在你的应用程序能够接收消息前,你必须调用start()方法。为了暂停发送消息,你需要调用stop()。
对话(session)――在jms连接的帮助下建立的对象,被客户端用作发送和接收消息。
产生消息的部分(messageproducer)――对话建立的对象,被用于在目的地中发送消息。
使用消息的部分(messageconsumer)――对话建立的对象,用于接收消息。为了同步接收消息,需要使用receive()方法。对于异步的情形,使用messagelistener和唯一的方法――onmessage()。在该方法中,在定义的消息到达后应该执行一定的操作。
消息(message)――消息本身。jms消息由三个部分组成:
? 消息头
? 属性(不是必要的)
? 消息体(不是必要的)
本文没有解释更多的细节信息,你可以在官方文档中找到具体的细节。
什么时候使用ejb 2.0
请注意下述各项内容:
在新的ejb 2.0规范中,与jms的集成是通过建立新的ejb类型――消息驱动bean(mdb)来实现的。mdb的特性是客户端不会使用远程接口(remote interface)与它通讯。其交互操作的唯一途径是通过消息发送。mdb仅仅是消息监听程序,是一个实现了javax.ejb.messagedrivenbean和javax.jms.messagelistener接口的类,没有任何其它的功能。其中的第一个接口只有两个方法:setmessagedrivencontext() 和ejbremove()。第二个接口只有一个方法:onmessage()。这个规范还需要一个不带参数的ejbcreate()建立方法。客户端不会直接与mdb通讯;它不会建立mdb。容器(container)自身决定什么时候和需要多少个mdb来处理来自特定目的地的消息。mdb的主要缺陷是它只能从一个目的地接收到消息。 代码示例
我们假设你已经安装了j2se(可以在http://java.sun.com/j2se/找到它),并且已经安装并运行了jboss应用程序服务器(可以在http://www.jboss.org/找到它)。
为了编译下面的示例,你需要输入:
javac -classpath .;c:/jboss-3.2.3/client/jbossall-client.jar simplesender.java
为了运行它,你需要输入:
java -classpath .;c:/jboss-3.2.3/client/jbossall-client.jar simplesender
(在输入时,请用你自己的jboss目录代替c:/jboss-3.2.3。同时还要记住,在你能够运行这些示例前,jboss服务器必须处于运行状态。)
好了,现在我们开始建立示例发送程序和接收程序了:
| // simplesender.java import java.util.properties; import javax.jms.*; import javax.naming.*; public class simplesender { public static void main(string argv[]) { new simplesender(); } public simplesender() { try { queueconnectionfactory myqconnfactory; queue myqueue; properties properties = new properties(); properties.put(context.initial_context_factory, "org.jnp.interfaces.namingcontextfactory"); properties.put(context.url_pkg_prefixes, "org.jnp.interfaces"); properties.put(context.provider_url, "localhost"); context ctx = new initialcontext(properties); myqconnfactory = (queueconnectionfactory)ctx.lookup ("uil2connectionfactory"); myqueue = (queue) ctx.lookup("queue/testqueue"); ctx.bind ("simplesender", myqueue); queueconnection con = myqconnfactory.createqueueconnection(); queuesession session = con.createqueuesession(false, session.auto_acknowledge); textmessage textmessage = session.createtextmessage(); queuesender sender = session.createsender(myqueue); con.start(); for (int i=0; i<10; i++) { textmessage.settext("hello world #" + i); sender.send(textmessage); } con.close(); ctx.close(); } catch(exception e) { e.printstacktrace(); } } } |
我们有两种接收消息的途径。第一种是使用javax.jms.queuereceiver的receive()方法向队列同步请求消息。这可能阻塞接收程序,直到它不接收消息为止,或者如何某个消息没有在特定的时间间隔内到达而返回超时操作。第二种是一旦可以访问消息了就异步接收消息,使用javax.jms.messagelistener调用onmessage()方法,它会处理消息的内容。
建立接收程序的很多步骤与建立发送程序的步骤类似:
| // syncreceiver.java import java.util.properties; import javax.jms.*; import javax.naming.*; public class syncreceiver { public static void main(string argv[]) { new syncreceiver(); } public syncreceiver() { try { queueconnectionfactory myqconnfactory; queue myqueue; properties properties = new properties(); properties.put(context.initial_context_factory, "org.jnp.interfaces.namingcontextfactory"); properties.put(context.url_pkg_prefixes, "org.jnp.interfaces"); properties.put(context.provider_url, "localhost"); context ctx = new initialcontext(properties); myqconnfactory = (queueconnectionfactory)ctx.lookup("uil2connectionfactory"); myqueue = (queue) ctx.lookup("queue/testqueue"); ctx.bind("syncreceiver", myqueue); queueconnection con = myqconnfactory.createqueueconnection(); queuesession session = con.createqueuesession(false,session.auto_acknowledge); queuereceiver receiver = session.createreceiver(myqueue); con.start(); for (int i=0; i<10; i++) { textmessage textmessage = (textmessage) receiver.receive(); system.out.println("got: " + textmessage.gettext()); } con.close(); ctx.close(); } catch(exception e) { e.printstacktrace(); } } } |
后记
数据库是长时间数据存储的理想途径,但是用户变更的临时数据和用户通知的存储不是它们的强项。尽管被认为是效率低下的,但是数据库查询还是频繁地用于现实中。所有请求都需要大量额外的“隐藏的”工作,如果大量的对象频繁地访问一个数据库,可能会导致数据库服务器和网络的严重的负载。在大多数时候,请求不会返回任何数据,更糟的情形是,将已知的信息返回到处理过程中。
简单地说,数据库不是计划用于频繁的查询或事件的。如果一旦数据或任何事件发生了改变就要立即作出反应,那么更简单和效率更高的途径将是使用异步消息。
技术处理的应用程序(例如公文流通、认领的处理等)大多数使用了mq(消息队列),因为mq模型与技术处理模型的统计特征类似,它承认“办公室”的形式,在其中每个人都有自己接收和发送的邮件箱。
这类应用程序的典型特征是使用了大量的代理(代理可能是人、自动处理的操作、甚至于物理设备,例如打印机或设备),其中每个代理都会遇到一些小的性能难题,并按照业务逻辑把它传递到下一个代理。在建立这类应用程序的时候,开发的主要事务是对快速的性能的把握,同时要把握开发时失败的缺乏。使用数据库的mq服务器简化了处理应用程序中的技术处理的过程;这样做更加灵活、容易扩展。
同样,对于聚焦于事务的应用程序,使用mq技术也是非常方便的。这涉及到处理财政金融和新服务领域的一些应用程序。在财政金融市场,操作必须很快地完成;用户对于即时发生的改变感兴趣。

闽公网安备 35060202000074号