J2EE的异步消息机制 |
作者:佚名 发布时间:2005-04-02 来源:不详
|
在分布式企业级应用程序中,异步消息机制用于有效地协调各个部分的工作。 |
J2EE为我们提供了JMS 个部件之间的异步消息传递
|
和消息驱动Bean(Message-Driv 。
|
en Bean),用来实现应用程序各
|
通常一个消息系统 ,需要一种异步的,非阻塞 求后,不在乎是否马上能得 应用程序在递交一个请求之 这是很高效的。消息系统提 者和使用者之间的"松耦合" 生了消息,产生者是否仍在 和灵活的系统。整个的子系
|
允许分开的未耦合的应用程序之 的消息传递。比如,一个客户端 到回应。这样,客户端没有理由 后,只需确保请求到达服务器端 供了许多其他分布式对象计算模 ,在它们之间有很高程度的事务 网络上以及消息是什么时候产生 统能被修改而不会影响系统的其
|
间可靠地异步通信。在企业应用时 可能希望给一个服务器发送一个请 必须等待服务器处理请求。客户端 后,就可以处理其他任务。通常, 型没有的优点。它鼓励在消息产生 处理。对于使用者,它不在乎谁产 的。这就允许建立动态的,可靠的 他部分。
|
另外的优点包括: 性。由于可靠性和可扩展性 许多应用程序的基础,这些 在JAVA技术中,处理异步消 象中间件提供一个标准的JA 了许多支持JMS的纯JAVA的
|
系统的高度可扩展性,容易与其 ,使得它们用于解决许多商业和 应用程序可以是工作流,网络管 息的能力是通过JMS来实现的。J VA接口。而这些产品是在一个企 产品。
|
他系统进行集成,以及高度的可靠 科学计算问题。比如,消息系统是 理,通信服务或供应链管理程序。 MS最初设计是为了给传统的消息对 业级应用程序中必须的。现在出现
|
1.发布/订阅(publish/subscribe) |
发布/订阅消息系统支持一个事 。产生者发布事件,而使用者订阅感兴趣 题(Topic)连在一起,消息系统根据使用
|
件驱动模型,消息产生者和使用者都参与消息的传递 的事件,并使用事件。产生者将消息和一个特定的主 者注册的兴趣,将消息传给使用者。
|
在点对点的消息系统中,消息分 。消息应用程序发送消息到一个特定的队
|
发给一个单独的使用者。它维持一个"进入"消息队列 列,而客户端从一个队列中得到消息。
|
JMS的目的是提供 这样,客户端的应用程序可 之间转移。JMS客户端都是 连接,使用JAVA BEAN组件 API来实现企业级应用服务
|
给消息系统客户一个固定的接口 以在不同的机器和操作系统中移 建立在JAVA技术上的,从而也能 模型,JDNI名字服务,JTA客户 程序。
|
,而且与底层的消息提供者无关。 植,而且能在不同的消息系统产品 使用其他JAVA API,如JDBC数据库 端事务处理控制以及J2SE和J2EE
|
图1显示了JMS对象,用于提供JMS客户端与JMS服务提供者相连的对象。 |
ConnectionFactory是一个客户 Connection创建时有授权和通信建立过程
|
端用来创建一个Connection的管理对象。由于在 ,因此这个对象是比较大的。
|
Destination对象
|
将一个消息的目的和服务提供者
|
有关的地址及配置信息包装起来。
|
Session是JMS实体 用于异步消息消费或能处理
|
,用来支持事务处理和异步消息 多个并发消息。通常,事务的复
|
消费。JMS并不需要客户端的代码 杂性都由一个Session来封装。
|
一个Session是一 困难。Session提供了在一
|
个原子单位的工作,与数据库的 个线程编程模式下的并发的优点
|
事务一样,要实现多线程事务比较 。
|
MessageProducer和MessageCons 。为了确保消息的传递,JMS服务提供者 式使得JMS提供者出问题后,也能让消息
|
umer对象由Session对象创建。用于发送和接受消息 处理的消息都要处于PERSISTENT模式。PERSISTENT模 保存下来。
|
Session,MessageProducer和Me ,Destination和Connection都支持并发
|
ssageConsumer都不支持并发,而ConnectionFactory 。
|
在消息系统中,应
|
用程序之间通信的关键是消息。
|
因此使用JMS必须要先理解消息。
|
MESSAGE HEADER用
|
于识别消息,比如用于判断一个
|
给定的消息是否是一个"订阅者"
|
PROPERITIES用于与应用程序相关的,提供者相关的和可选项的信息 |
BODY是消息的内容,支持几种格 和ObjectMessage(对任意对象的封装,
|
式,包括TextMessage(对String一个简单的封装) 但必须支持序列化),也支持其他格式。
|
一个TextMessage 它假设许多消息系统是建立
|
是一个String对象的封装。在只 在XML上的。从而TextMessage就
|
有文本对象传递时,是很有用的。 可以成为包装它们的容器。
|
创建一个TextMessage对象很简单,如下面的代码: |
TextMessage mess
|
age=session.createMessage();
|
|
message.setText("Hello, world!"); |
如名字所示,它是对一个JAVA对 ObjectMessage,如果必须将多个对象封 包括多个序列化对象。
|
象的封装的消息。任何可序列化的JAVA对象都能用于 装在一个消息里传递,可以使用Collection对象,来
|
ObjectMessage me
|
ssage=session.createObjectMe
|
ssage();
|
message.setObject(myObject); |
一个典型的JMS客户端由下面的几个基本步骤来创建: |
创建一个到消息系统提供者的连接(Connection) |
创建MessageProducer和Message
|
Consumer来创建和接收消息
|
当完成了上述步骤 使用者客户端会接收与一个
|
后,一个消息产生者客户端将创 主题相关的消息。
|
建并发布消息到一个主题,而消息
|
一个Connection提 过使用一个ConnectionFact
|
供客户端对底层的消息系统的访 ory来创建一个Connection,通
|
问。并实现资源的分配和管理。通 常用JDNI来指定:
|
Session是一个比较大的JMS对象 用者和消息产生者。
|
,他提供了生产和消费消息的手段。用于创建消息使
|
topicSession = t ion.AUTO_ACKNOWLEDGE);
|
opicConnection.createTopicSe
|
ssion(false,Sess
|
用JDNI来定位一个Topic,Topic 订阅者订阅一个给定的Topic,而发布者
|
用于识别发送或接收的消息,在发布/订阅系统中。 将它发布的消息与一个Topic相连。
|
下面是创建一个Topic "WeatherReport" |
Topic weatherTopic=messaging
|
.lookup("WeatherReport");
|
在上面的初始化步 为。一旦初始化结束,必须
|
骤之后,消息流是禁止的,用于 让Connection启动消息系统。
|
防止在初始化时发生不可预料的行
|
在发布/订阅里, 个产生者,以及后续的建立
|
一个产生者发布消息到一个指定 和发布一个简单文本消息。
|
的Topic。下面的代码显示创建一
|
TopicPublisher publisher=ses
|
sion.createPublisher(weatherTopic);
|
TexeMessage message=session.
|
createMessage();
|
publisher.publish(message); |
异步消息也可以由 分别是实体Bean(Entity B 塞方式来调用Bean的方法。
|
消息驱动Bean来实现。在EJB 1. ean)和会话Bean(Session Bea 消息驱动Bean将EJB和JMS的功能
|
1规范中,定义了两种类型的EJB。 n)。客户端通常是以同步的,阻 结合在一起。
|
正如前述,会话Be 常和一些在永久存储中的一 来与客户端交互。并且,这 Bean,通过阻塞式方法调用 理。消息驱动Bean通常配置 者。但消息驱动Bean没有HO 不知道使用者是一个消息驱 。消息驱动Bean没有会话性 Bean是类似的。将Bean的实 息驱动Bean必须间接或直接 javax.jms.MessageListene 任何有效的JMS消息类型。 仍出应用程序异常。当容器 Bean,然后,如果配置文件 管理任务完成时,接收到的 Bean又被重新放回到缓冲池
|
an通常实现商务逻辑,客户端不 些实体条目相对应的。这两种Be 些交互都是同步的,阻塞方式进 ,服务器返回一个相应。调用者 成是一个特别的主题(topic) ME和REMOTE接口。一个消息产生 动Bean。这就允许集成一个分布 质的状态,所有的实例在不处理 例放在缓冲池里,也是高效处理 地从javax.ejb.MessageDrivenB r继承而来。这个方法的一个参 方法的申明中并不包含一个thro 接收到消息时,它首先是从一个 需要的,容器还要设置一个和事 消息传递给onMessage()方法。 。
|
能共享一个会话Bean。实体Bean通 an通常都有REMOTE和HOME接口,用 行的。比如,一个请求发送给一个 在收到返回后,才能进行下一步处 或队列的客户端,作为消息的使用 者将消息写入TOPIC或队列时,并 式的计算系统时,有很大的灵活性 请求时是相同的,这与无状态会话 消息驱动Bean的一种方法。一个消 ean接口继承而来。这个接口是由 数是javax.jms.Message。可以是 wn语句。因此在消息处理中,不会 缓冲池里得到现成的一个消息驱动 务处理上下文的一个联系。当这些 一旦方法完成,事务确认或返回,
|
ejbRemove()在把 集。必须在ejbRemove()方
|
消息驱动Bean从任何存储上删除 法中释放所有Bean的实例用到的
|
时调用。并进行清楚操作和垃圾收 资源。
|
setMessageDriven ageDrivenContext的实例。 一个Bean的实例创建时,容 UserTranscation类,用于B
|
Connection()方法只有一个参数 MessageDrivenContext类与在实 器传入Bean用的上下文。上下文 ean管理事务处理的场合。
|
-javax.ejb.Mess 体和会话Bean中的上下文类似。当 中得到环境信息的方法,以及JTA
|
另外,Bean提供者 Bean进行设置。Bean实例可
|
必须提供一个ejbCreate()方法 以在ejbCreate()方法中取得任
|
(无参数),用于在EJB服务器对 何需要的资源。
|
消息驱动Bean大大地简化了创建 功能都交由EJB容器来做了。开发人员只 器,用来创建一个接收消息的商业逻辑部
|
一个JMS使用者,创建和配置一个JMS消息使用者这些 需简单地实现消息驱动Bean的接口,配置给EJB服务 件。
|
本文为了说明上面 Subscriber的代码。请参见
|
的概念,编写了一个消息驱动Be 附录的源代码。
|
an,一个Publisher和一个
|
下面讲一下怎样运 ,并已经安装好了。
|
行实例。这里假设读者已经从SU
|
N主页上下载了J2EE SDK 1.3 Bate
|
j2eeadmin -addJmsDestination
|
WeatherReport topic
|
D:j2sdkee1.3bin>j2eeadmin -listJmsDestination JmsDestination |
< JMS Destination : jms/Topic , javax.jms.Topic > |
< JMS Destination : jms/Queue , javax.jms.Queue > |
< JMS Destination : WeatherReport , javax.jms.Topic > |
D:mysourcecodetestjms>java -Djms.properties=%J2EE_HOME%configjms_client.properties jmssub |
Topic name is WeatherReport |
Java(TM) Message
|
Service 1.0.2 Reference Imp
|
lementation (build b10)
|
To end program, enter Q or q, then |
Reading message: A sunny day. |
set classpath=%J2EE_HOME%li
|
bj2ee.jar;.
|
java -Djms.prope
|
rties=%J2EE_HOME%configjms
|
_client.properties jmspub
|
Topic name is WeatherReport |
Java(TM) Message
|
Service 1.0.2 Reference Imp
|
lementation (build b10)
|
Publishing message: A sunny day. |
D:j2sdkee1.3bin>j2eeadmin -removeJmsDestination MyTopic |
下面是用消息驱动Bean实现接受 看到下面的信息:
|
消息。使用deploytool将附录中的Bean部署好,可以
|
Deploying messag
|
e driven bean MsgBean, consu
|
ming from WeatherReport
|
Application testjms deployed. |
然后再次运行Publisher。可以看到消息驱动Bean输出下面的结果: |
MESSAGE BEAN: Message receiv
|
ed: A sunny day.
|
|
|
|
|
|