1月份不知道在做什么,就没写,忽然觉得一个月没写好像缺了点什么,正好这几天研究了一下JMS,就写一点自己的心得.
JMS,全称是JAVA MESSAGE SERVICE,从名字可以看出来,就是一个消息服务,也就是说可以用来发送和接受消息的一个服务,我也是刚开始学习,所以就记录下这两天的一些收获.
至于JMS的一些背景我就没有兴趣去细看了,反正我的目的就是学他的实现过程.我在这里不会详细介绍每一个接口的方法,详细内容可以去SUN网站下载JMS的API文档.
首先要看的就是JMS的体系结构.
JMS 应用程序由以下元素组成:
- JMS 客户机。 用 JMS API 发送和接收消息的 Java 程序。
- 非 JMS 客户机。 认识到传统程序通常整个 JMS 应用程序的一部分是非常重要的,在规划时必须优先考虑它们的存在。
- 消息。就JMS 应用程序设计而言,通过JMS 和非 JMS 客户机所交换的消息的格式和内容是完整的。
- JMS 提供者。 如前所述,JMS 定义了一组接口,供应者必须提供特定于其 MOM 产品的具体实现。
- 管理对象。 消息系统提供者的管理员创建的、独立于提供者的专有技术的对象。
JMS 提供者必须提供允许创建受管理对象及它们在 JNDI 名字空间中的存放地的工具。 有两种受管理对象:
ConnectionFactory
:用于创建到提供者的底层消息系统的连接。Destination
:用 JMS 客户机来指定正发送消息的目的地或正接收消息的来源。
尽管受管理对象本身就是特定于提供者实现的类的例子,但可以使用可移植机制(JNDI)检索它们,并且可以通过可移植接口(JMS)访问它们。JMS 程序只需要知道管理对象的 JNDI 名称和 JMS 接口类型即可,无需了解特定于提供者的知识。
高级接口包括:
ConnectionFactory
:一个创建Connection
的受管理对象。Connection
:连接到提供者的活动连接。Destination
:一个封装消息目的地的身份的受管理对象,如消息的来源地和发送地。Session
:发送和接收消息的单线程环境。为了简化,并且因为Session
控制事务的缘故,通过多个线程进行并发访问受到了限制。可以将多个Session
用于多线程应用程序。MessageProducer
:用于发送消息。MessageConsumer
:用于接收消息。
一个典型的 JMS 程序要经过以下步骤才能开始产生和使用消息:
- 通过 JNDI 查询
ConnectionFactory
。 - 通过 JNDI 查询一个或者多个
Destination
。 - 用
ConnectionFactory
创建一个Connection
。 - 用
Connection
创建一个或者多个Session
。 - 用
Session
和Destination
创建所需要的MessageProducer
和MessageConsumer
。 - 启动
Connection
。
这里我有必要介绍一些名称:
ConnectionFactory
:
ConnectionFactory
是一个可以从JNDI检索的受管理对象,它建立了到提供者的连接。它包含 createConnection()
方法,该方法返回了一个 Connection
对象。
Connection
封装了一个连接到提供者的活动连接。它的一些方法包括:
createSession(boolean, int)
:返回一个Session
对象。boolean
参数指出Session
是否被处理,int
则指出确认模式.start()
:激活提供者发送消息。stop()
:临时停止消息的发送,可以用start()
重新开始发送。close()
:关闭到提供者的连接,并释放以它的名义占用的所有资源。
Session
是用来发送和接收消息的单线程的上下文。它的一些方法包括:
createProducer(Destination)
:返回一个MessageProducer
对象,向指定的Destination
发送消息。createConsumer(Destination)
:返回一个MessageConsumer
对象来接收来自指定Destination
的消息。commit()
:提交当前事务的所有使用的或者产生的消息。rollback()
:回滚当前事务所有使用的或者产生的消息。create<MessageType>Message(...)
:一组返回<MessageType>Message
的方法——例如,MapMessage
、TextMessage
等。
Destination
:
封装消息的目的地。它是一个从 JNDI 检索的受管理对象。
MessageProducer
:用来发送信息.
MessageConsumer
:用来接受信息.
MessageListener
MessageListener
是有一个单一方法——onMessage(Message)
——的接口,它提供了消息的异步接收和处理。
再讲一个概念
,”确认”
确认是通知提供者已经成功接收到消息的一种机制。
如果被处理的是接收消息的 Session
,则确认的处理是自动的。如果被处理的不是 Session
,则在创建 Session
时确定确认的类型。
有三种类型的确认:
Session.DUPS_OK_ACKNOWLEDGE
:消息发送的延迟回执,它通过最小化工作的重复来减少开销,只有在可以预计和处理重复消息时,才可以使用这种确认。Session.AUTO_ACKNOWLEDGE
:在完成接收消息的方法时自动确认消息的发送。Session.CLIENT_ACKNOWLEDGE
:通过调用Message
的acknowledge()
方法显式确认消息发送。
我这里附上一些代码实例,来源于IBM的教程.我自己添加了一些注释.
import java.io.*;
import javax.jms.*;
import javax.naming.*;
public class Sender {
public static void main(String[] args) {
new Sender().send();
}
public void send() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
//Prompt for JNDI names
System.out.println("Enter ConnectionFactory name:");
String factoryName = reader.readLine();
System.out.println("Enter Destination name:");
String destinationName = reader.readLine();
//Look up administered objects
InitialContext initContext = new InitialContext();
ConnectionFactory factory =
(ConnectionFactory) initContext.lookup(factoryName);
//lookup(String) return object,so have to convert by force
Destination destination = (Destination) initContext.lookup(destinationName);
initContext.close();
//Create JMS objects
Connection connection = factory.createConnection();
Session session =
connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer sender = session.createProducer(destination);
//Send messages
,if you input “quit”,the programe will be end.
String messageText = null;
while (true) {
System.out.println("Enter message to send or 'quit':");
messageText = reader.readLine();
if ("quit".equals(messageText))
break;
TextMessage message = session.createTextMessage(messageText);
sender.send(message);
}
//Exit
,close Connection ,will close Session and
Destination
automatic.
System.out.println("Exiting...");
reader.close();
connection.close();
System.out.println("Goodbye!");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
}
Receiver
类与 Sender
类非常类似,都有一个 main(String[])
方法,它只是举例说明了 Receiver
并调用它的主要方法 receive()
。
提示输入 JNDI 的名称并查找受管理对象的代码与 Sender
中的代码完全一样。
不过,在这个类中有两处不一样的地方:
boolean stop
实例变量用来指出程序应该退出。Receiver
实现了MessageListener
接口,为了异步接收消息。
import java.io.*;
import javax.jms.*;
import javax.naming.*;
public class Receiver implements MessageListener {
private boolean stop = false;
public static void main(String[] args) {
new Receiver().receive();
}
public void receive() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
//Prompt for JNDI names
System.out.println("Enter ConnectionFactory name:");
String factoryName = reader.readLine();
System.out.println("Enter Destination name:");
String destinationName = reader.readLine();
reader.close();
//Look up administered objects
InitialContext initContext = new InitialContext();
ConnectionFactory factory =
(ConnectionFactory) initContext.lookup(factoryName);
Destination destination = (Destination) initContext.lookup(destinationName);
initContext.close();
//Create JMS objects
Connection connection = factory.createConnection();
Session session =
connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageConsumer receiver = session.createConsumer(queue);
receiver.setMessageListener(this);
connection.start();
//Wait for stop
while (!stop) {
Thread.sleep(1000);
}
//Exit
System.out.println("Exiting...");
connection.close();
System.out.println("Goodbye!");
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
public void onMessage(Message message) {
try {
String msgText = ((TextMessage) message).getText();
System.out.println(msgText);
if ("stop".equals(msgText))
stop = true;
} catch (JMSException e) {
e.printStackTrace();
stop = true;
}
}
}
在运行这个程序之前,需要使用 JMS 提供者提供的管理工具创建受管理对象 ConnectionFactory
和 Destination
,并将它们放到 JNDI 名字空间中。
对于点对点编程和pub/sub,是JMS的扩展,目前首选仍然是公共接口,所以, JMS还有很多内容,有兴趣的话可以去SUN网站下载API文档,我也是在初学阶段,先写这么多吧.