1、 TongTech TongLINK/Q8.1 系统开发 手册 -JMS 编程参考 2011 年 7 月 TongLINK/Q V8.1 系统开发手册 _JMS 编程参考 北京东方通科技股份有限公司 地址:北京市海淀区彩和坊路 10 号 1+1 大厦 2、 3 层 客户服务热线: 400-650-7088 Email: 版权声明 版权 2006-2016 东方通科技 版权所有。 版权保护说明 未经 东方通科技 公司书面许可,本文档 不得整体或部分地复印、复制、翻译或缩减成任何电子介质或计算机可以阅读的格式。本文档中的信息可能不加通知进行修改。 商标 2006-2016 东方通科技 版权所有 。
2、 、 TongTech、 TongLINK、 TongLINK/Q、TongIntegrator、 TongSEC、 TongWeb、 TongEASY、 TongWorkflow 是东方通科技的注册商标。其他所有的公司和产品名称可能为第三方所有。 前言 本手册 主要 介绍 TongLINK/Q JMS应用体系结构 、 JAVA目录说明、使用 TLQJMS程序的步骤、 TLQJMS程序配置说明 、 TLQJMS环境设置、 编写 TLQ JMS程序 、 编写发布订阅应用 、JMS消息 、 JMS中的加密 第 5 章 TLQJMS 环境设置 13 第 5章 TLQJMS 环境设置 下面主要是对使用
3、普通 JMS 程序的环境 变量 设置进行说明 , TLQ 有关环境变量设置请参见 TongLINKQ8.1 系统安装手册 _服务端安装,在此就不介绍了 。 5.1 Windows 环境变量设置 set CLASSPATH=%CLASSPATH%;%TLQHOMEDIR%java libjavaee.jar; %TLQHOMEDIR%java libTongJMS.jar; 5.1.1 环境变量说明 WINDOWS 安装完毕后,运行所需的环境变量会自动加载,不需要用户设置。若想新建一个节点,则需为此节点设置环境变量,且可根据实际环境修改。 安装完毕,运行所需的环境变量会自动加载,运行节点需要设置
4、的环境变量说明如下: CLASSPATH- JMS 的 相关配置及 java 类库设置在 CLASSPATH 中 。 5.1.2 环境 变量举例 若需要新建一个节点,则需 在 setenv 批处理文件中 设置 JMS 环境变量,用户可根据实际环境修改。 例如: #用户运行的 TLQ 目录 set TLQHOMEDIR=E:TLQ8 #JMS 使用的环境变量 set CLASSPATH=%CLASSPATH%;%TLQHOMEDIR%javalibjavaee.jar; %TLQHOMEDIR%javalibTongJMS.jar; 5.2 Unix 环境变量设置 TLQHOMEDIR=$PWD
5、; export TLQHOMEDIR PATH=$TLQHOMEDIR/bin:.:$PATH; export PATH CLASSPATH=$TLQHOMEDIR/java/lib/javaee.jar:$TLQHOMEDIR/java/lib/TongJMS.jar:.:$CLASSPATH; export CLASSPATH 5.2.1 环境变量说明 安装完毕,运行环境变量 . setp,运行节点在 setp 批处理文件中设置的环境变量说明如下: TLQHOMEDIR-TLQ8 的系统安装路径 ; PATH-可执行程序的存放目录。 CLASSPARH-JMS 的 相关配置及 java
6、类库设置在 CLASSPATH 中 。 第 5 章 TLQJMS 环境设置 14 5.2.2 环境变量举例 可在用户的 .profile 中进行设置,也可用一个单独的批处理文件 (如 setp 文件 )进行设置,用户可根据实际环境修改。 例如: #TLQ8.1 安装目录 TLQHOMEDIR=/usr/TLQ8 export TLQHOMEDIR #JMS 使用的环境变量 PATH=$TLQHOMEDIR/bin:.:$PATH; export PATH CLASSPATH=$TLQHOMEDIR/java/lib/javaee.jar:$TLQHOMEDIR/java/ /lib/TongJ
7、MS.jar:.:$CLASSPATH; export CLASSPATH 第 6 章 编写 TLQJMS 程序 15 第 6章 编写 TLQ JMS 程序 6.1 JMS 模型 JMS 定义了一个普通的消息传输服务模型,普通的 JMS 模型是建立在如下的接口上的,这些接口定义在 javax.jms 包中。 Connection 提供了基础传输的方法,用于创建 Session。 为临时队列提供了使用范围,同时提供了连接到 TLQ的连接控制参数,参 数包括 JMSServer的 Host和 Port等 Session 提供了生产和消费消息的上下文,包括用来创建 MessageProducer和
8、MessageConsumer的方法。同时,定义了一个事务的范围。 MessageProducer 和 MessageConsumer MessageProducer用来发送消息; MessageConsumer用来接收消息。 注 意: Connection是线程安全的,但是 Session、 MessageProducers和 MessageConsumers不是线程安全的,所以 , 在多线程应用中,建议 一个 Session中只能 用 在 一个 线程中 。 由于 一个 Session 中 只 能 用 在 一个 线程 的 限 制 , 一 个 Session 相 关 的 MessageProd
9、ucer 和 MessageConsumer不能在线程间并发使用。 具有继承关系的 JMS接口有如下的子类: 对于 “Point-to-Point” : QueueConnection QueueSession QueueSender QueueReceiver 编写 JMS应用程序时,是建议只使用 javax.jms中定义的接口,所有 JMS提供 商相关的特定信息都封装在如下的实现中: QueueConnectionFactory TopicConnectionFactory Queue Topic 这些对象可以使用提供商提供的工具进行管理,相关信息存放在 JNDI名字空间中, JMS应用可
10、以从名字空间中获取这些对象,而不需要知道实现到底是由哪个提供商完成。 6.2 建立 Connection(连接 ) Connection不能直接创建,必须使用 connection factory 进行创建。连接工厂的对象可以存储在 JNDI名字空间中,这样,就使用户 在编写 JMS应用时不需要考虑 JMS提供相关的特定信息。也可以没有 JNDI的名字空间,这样, connectionFactory必须在运行时创建。 第 6 章 编写 TLQJMS 程序 16 6.2.1 通过 JNDI 获取 Factory 要从 JNDI名字空间中获取一个对象,必须首先设置初始化上下文,如下: import
11、 javax.jms.*; import javax.naming.*; import javax.naming.directory.*; String icf=xxxxx; String url=yyyyyy; java.util.Properties prop = new java.util.Properties(); prop.put(Context.INITIAL_CONTEXT_FACTORY, icf); prop.put(Context.PROVIDER_URL, url); Context ctx = new InitialContext( prop ); Connection
12、Factory factory; factory = (ConnectionFactory)ctx.lookup(“ivtQCF“); 其中: icf:定义了 factory类的初始化上下文 url:定义了上下 文 的 URL 6.2.2 程序运行时创建 factory 当没有 JNDI名字空间,可以在程序运行过程中实时创建 factory。然而,使用这种方式将降低 JMS应用的可移植性,因为应用中需要直接引用 TLQ特定的类。 下面的代码为创建 ConnectionFactory 的用例举例: ConnectionFactory factory = new com.tongtech.tmqi
13、.QueueConnectionFactory(), 6.2.3 使用 factory 创建 Connection 下面的代码为创建 Connection的代码用例举例: Connection connection; connection = factory.createConnection(); 6.2.4 启动 Connection JMS规范规定了连接在建立时必须为停止状态,即连接创建后并不能立即使用。只有连接被启动后,消息的消费者和生产者才能收发消息。要启动一个连接,使用如下的方式: connection.start(); 第 6 章 编写 TLQJMS 程序 17 6.2.5 使用
14、短连接连接工厂 如果 您 的应用程序需要在短时间内建立大量的连接,而这些连接又会在收发很少量 的消息后就进行关闭, 由于 这样的操作会频繁的开关底层网络连接 , 会 对应用程序的性能会造成很大的影响 。因此 在这种应用模式下,建议 您 采用短连接 连接工厂的方式 来创建连接 ,该 连接工厂会 维持一个内部的连接池 ,从而提高应用程序的消息收发速度。 6.2.5.1 使用方法 使用 JNDI 的方式: 配置 请参见 4.1.2.2.1 小节的配置说明 进行配置。 程序运行时创建的方式 com.tongtech.tmqi.pool.PooledConnectionFactory cf = com.
15、tongtech.tmqi.pool.PooledConnectionFactory(); 设置参数: 设置池中最大物理连接数: setMaxConnections(int maxConnections) 设置每个连接可创建的最大 session 数 setMaxSessions(int maxSessions) 6.2.5.2 对应用程序的影响 由于此连接工厂创建出来的 网络 连接 会被多个 连接共用,因此 您调用 stop 方法不会 停止此连接的消息接收,如果您需要 停止消息接收,请关闭相应的消息接收者。 由于 此连接工厂会在内部 连接池 中维护 着物理 连接,当您的应用退出时这些连接并不
16、会 自动 关闭 ,如果您需要完全退出并关闭这些连接请调用 ConnectionFactory 上的 close 方法。 如果您是使用的 JNDI 方式,请将 lookup 出的 ConnectionFactory 转换成com.tongtech.jms.ConnectionFactory 类型后再调用 close 方法。 6.3 获取 session(会话 ) 连接一旦建立,使用 Connection 的方法 createSession 就可以获得一个 session。此方法有两个参数: 1. transacted(Boolean):此 session 是否为事务类型。 2. acknowle
17、dgeMode(int):事务的确认模式。如果 session 为 (transacted)事务类型,此参数被忽略。如果为( non-transacted)非事务类型,此参数决定了消费者或客户端收到消息后的确认方式。合法的取值为: Session.AUTO_ACKNOWLEDGE, Session.CLIENT_ACKNOWLEDGE, and Session.DUPS_OK_ACKNOWLEDGE。 下面的例子为一个非事务类型的 session: Session session; boolean transacted = false; session = connection.createS
18、ession(transacted,Session.AUTO_ACKNOWLEDGE); 【 提示 】 连接是线程安全的,但 Session不是。所以,在多线程应用中, 一个 Session中只能 用 在 一个 线程中 。 第 6 章 编写 TLQJMS 程序 18 6.4 Message(消息 ) 消息分为三部分: Header(头信息):所有的消息都支持相同集合的 Header 域。 Properties(自定义属性):每个消息都包含一个内置的机制以支 持应用自定义的属性。自定义属性为应用使用自己的消息过滤方式提供了有效的解决方案。 Body(消息体): JMS API 定义了多种类型的消
19、息体,覆盖了目前使用的大多数的消息风格。 JMS提供多种消息类型,每种类型都有其各自的内容和特点, Message由 Session对象创建。消息类型有如下几种: 1. BytesMessage 2. MapMessage 3. ObjectMessage 4. StreamMessage 5. TextMessage 下面为一个简单的例子 1: String content=”I am creating a textMessage”; TextMessage message=session.createTextMessage(); message.setText(content); 6.5
20、发送消息 消息由 MessageProducer 发送。对于点对点( PtoP)的应用情况,这其实就是通过调用 QueueSession的 createSender 方法创建的一个 QueueSender。 QueueSender 通常情况下是为某个特定的队列创建的,所以,所有使用此 sender 发送的消息都会到达同一个目的地,此目的地被指定为一 个 Queue 对象。 Queue对象可以在应用运行时创建,也可以从 JNDI 中获取。 下面为通过 JNDI获取 Queue对象的例子: Queue queue; queue=(Queue)ctx.lookup(“queue1”); Queue对
21、象一旦得到,则一定会被传入到方法 createSender中创建一个 QueueSender或传入createProducer中创建一个 MessageProducer,然后调用 send方法进行消息发送。 代码举例如下: TextMessage message session.createTextMessage(“A message body“); QueueSender queueSender = session.createSender(queue); queueSender.send(message); 或 MessageProducer Producer = session.crea
22、teProducer(queue); Producer.send(message); 第 6 章 编写 TLQJMS 程序 19 6.6 接收消息 消息是使用 QueueReceiver 进行接收的, QueueReceiver 由 Session 的 createReceiver 方法创建,方法的参数为 Queue, Queue 为消息接收的源队列。代码举例如下: QueueReceiver receiver=session.createReceiver(queue); Message message=receiver.receive(5000); 或者 MessageConsumer co
23、nsumer =session.createConsumer(queue); Message message=consumer.receive(5000); 传 入 receive 的参数为超时时间,单位为毫秒, TongLINK/Q 只支持 毫 秒级的超时时间。此参数定义了当队列中没有消息时所等待的时间。此参数也可以忽略掉,这样,方法就会无限期阻塞。如果想使用无等待的接收模式,可以使用 receiveNoWait 方法,这样当队列中没有消息时,方法会立刻返回。接收方法返回适当类型的 Message,如 TextMessage。 6.6.1 消息类型判断 要从消息的消息体得到内容,最好是从 M
24、essage 造型成更具体的子类,如 TextMessage。如果事先不知道消息的具体类型,可以使用 instanceof 进行判断。编写应用时,最后先测试一下消息的类型。代码举例如下: if (message instanceof TextMessage) String text=(TextMessage)message).getText(); System.out.println(text); else if(message instanceof ObjectMessage) . 6.6.2 Message selectors JMS 提供一种方式,使得应用可以根据条件接收队列中的消息某个
25、子集。当创建一个 QueueReceiver时,可以提供一个语法为 SQL 语句,即 Selector 来决定那些消息可以被搜索到。 Selector 可以包含 JMS标准的自定义属性 (包含: JMSCorrelationID、 JMSPriority 和 JMSMessageID)以及用户的自定义属性。 下面的代码为使用用户自定义属性作为 selector 的例子: String selector=”ProductName=TLQ”; QueueReceiver receiver=session.createReceiver(queue,selector); 下面的代码为使用 JMS 标准
26、 自定义属性作为 selector 的例子: String selector1= “ JMSCorrelationID = ID:abcdefd AND JMSPriority = 5“ QueueReceiver receiver1=session.createReceiver(queue,selector1); JMS规范规定,跟一个 receiver相关的 selector不能修改,也就是说,一旦 receiver被创建,则相关的selector的生命周期即被确定。 如果应用需要另外的 selector,则必须创建新的 receiver。 6.6.3 异步接收 JMS 还提供另外一种自动
27、调用 QueueReceiver.receive()的方法,使得一旦有合适的消息,此方法即被调用。下面的代码举例说明了这一原理: import java.jms.*; 第 6 章 编写 TLQJMS 程序 20 pulic class myListener implements MessageListener /*当消息到达后,对消息进行处理 */ public void onMessage(Message message) if (message instanceof TextMessage) else if(message instanceof ByteMessage) else myLi
28、stener mylistener=new myListener(); QueueReceiver.setMessageListener(mylistener); 说明: 当使用 QueueReceiver的异步接收功能时,整个 session即被标记为异步模式,所以,在此 session内,不允许显式调用 QueueReceiver的 receive方法。 6.7 对象关闭 应用中,可能需要创建多个 Session 以及或更低级别的 JMS 对象,由于 TongLINK/Q 的垃圾回收功能并不能实时地释放所有所占有 的 资源,所 以 ,在使用完这些 JMS 对象后,及时调用对象 close(
29、)方式是非常重要的。这些对象相关的类包括 Connection, Session, MessageProducer, MessageConsumer 等。 对象关闭的顺序最好跟创建或获得对象的顺序相反。 6.8 错误处理 JMS 应用运行过程中出现的任何错 误都会以异常的形式抛出,大多数的 JMS 方法抛出JMSException 来表明错误出现,应用程序中应该及时捕捉这些异常并以合适的方式输出。 不像其他一般的 Java 异常, JMSExeception 可能包含更深一层的异常。底层传输中产生的异常,往往会嵌入到 JMSException 中。下面的例子为获得 TongLINK/Q 相关的错误信息的举例: try . catch(JMSException e) . System.out.println(e.getErrorCode(); 6.9 PtoP 应用编写举例 下面的举例符合 JMS1.1 标准。 请 参见 安装目录 samplesdemo_javajmsptp 下的 DOME 文件 PtoP.java。 import javax.jms.*; / The JMS classes import javax.jms.QueueReceiver;