Spring JMS
Spring 的 JMS 抽象框架简化了 JMS API 的使用,并与 JMS 提供者(比如 IBM 的 WebSphere MQ 5.3)平滑地集成。org.springframework.jms.core 包提供了在 Spring 中使用 JMS 的核心功能。它的模板类处理资源的创建和释放,简化了 JMS 的使用。
像其他大多数 Spring 模板类一样,JMS 模板类提供了执行公共操作的 helper 方法。在需要更复杂应用的情况下,类把处理任务的核心委托给用户实现的回调接口。JMS 类提供了方便的方法,用来发送消息、同步地使用消息以及向用户公开 JMS 会话和消息的制作者。
以下 JMS 包和 org.springframework.jms.core 一起构成了 Spring JMS 的功能:
- org.springframework.jms.support
- 提供转换
JMSException
的功能。转换代码把检测到的JMSException
层次结构转换成未检测到异常的镜像层次结构。 - org.springframework.jms.support.converter
- 提供
MessageConverter
抽象,以在 Java 对象和 JMS 消息之间进行转换。 - org.springframework.jms.support.destination
- 提供管理 JMS 目标的不同策略,比如针对 JNDI 中保存的目标的服务定位器。
- org.springframework.jms.connection
- 提供适合在独立应用程序中使用的
ConnectionFactory
实现。connection 还包含针对 JMS 的 SpringPlatformTransactionManager
实现。它允许把 JMS 作为事务性资源集成到 Spring 的事务管理机制中。
就像前面提到的,示例应用程序会用 Spring 的 JMS 框架通过 JMS 接口与 IBM 的 WebSphere MQ 集成。通过在应用程序和 Web 服务之间传递消息,WebSphere MQ 提供了可靠的、有恢复能力的应用程序集成。它使用队列和事务性工具帮助保持消息跨网络的完整性。WebSphere MQ 降低了信息丢失的风险和调和通信 IT 系统的需要。
WebSphere MQ 在它所支持的所有平台上提供了一致的应用程序编程接口,这有助于让集成的程序可移植。除了标准接口外,WebSphere MQ 还完整实现了JMS 接口,包括对发布-订阅消息传递的支持。WebSphere MQ Explorer 工具可以远程地管理和配置整个 MQ 网络。管理和配置工具基于开放源码的 Eclipse 框架,而且是可扩展的。
Spring 框架提供了 JmsTemplate
的两个实现。JmsTemplate
类使用 JMS 1.1 API,子类 JmsTemplate102
则使用 JMS 1.0.2 API。我的示例应用程序使用的是 JmsTemplate102
。
JMS 模板被用来发送和接收 JMS 消息。Spring 采用回调机制对 JMS 信息传递进行协调。MessageCreator
回调接口用 JmsTemplate
中的调用代码提供的 Session
创建消息。为了支持 JMS API 更复杂的应用,回调 SessionCallback
向用户提供了 JMS 会话,而callback ProducerCallback
则公开了 Session
和 MessageProducer
组合。
清单 1 显示了示例应用程序使用的 JMS 模板的配置。清单摘自 spring-mqseries-jms.xml 文件(请参阅 下载)。
清单 1. JMS 模板配置
<!-- JMS Queue Template --> <bean id="jmsQueueTemplate" class="org.springframework.jms.core.JmsTemplate102"> <property name="connectionFactory"> <ref bean="jmsQueueConnectionFactory"/> </property> <property name="destinationResolver"> <ref bean="jmsDestinationResolver"/> </property> <property name="pubSubDomain"> <value>false</value> </property> <property name="receiveTimeout"> <value>20000</value> </property> </bean> |
jmsQueueTemplate
bean 与 JMS 连接工厂和 JMS 目标解析器绑定在一起,用于解析 JMS 客户机通过 JNDI 提供的目标队列名。connectionFactory
属性指定了如何获得到 JMS 提供者的连接。在本例中,清单 2 显示了如何从 JNDI 检索连接工厂。
清单 2. 通过 JNDI 配置 JMS 连接工厂
<!-- JMS Queue Connection Factory --> <bean id="internalJmsQueueConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiTemplate"> <ref bean="jndiTemplate"/> </property> <property name="jndiName"> <value>MQ_JMS_MANAGER</value> </property> </bean> |
可以看到,JndiObjectFactoryBean
被绑定到 internalJmsQueueConnectionFactory
。JndiObjectFactoryBean
用 JndiTemplate
属性进行 JNDI 查询。Spring 将用 JndiTemplate
中指定的环境属性和初始上下文在 JNDI 中查询连接工厂。清单 3 显示了 JndiTemplate
配置 bean 的配置。
清单 3. JNDI 查询的 JNDI 模板配置
<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate"> <property name="environment"> <props> <prop key="java.naming.factory.initial"> com.sun.jndi.fscontext.RefFSContextFactory </prop> <prop key="java.naming.provider.url"> file:/C:/JNDI-Directory </prop> </props> </property> </bean> |
以上配置进行 JNDI 查询时用 com.sun.jndi.fscontext.RefFSContextFactory
指定初始上下文工厂,用基于文件的 file:/C:/JNDI-Directory 作为提供者 URL。根据示例应用程序的意图,JNDI 访问会采用基于文件的 FSContext
版本(请参阅 参考资料)的配置把 MQ 队列绑定到 JNDI。
有了定义好的 JMS 模板,下一步就是把它绑定到示例应用程序中,然后就可以用它发送和接收消息了。
JMS 模板可以绑定到应用程序中,以发送和接收 JMS 消息。在清单 4 中可以看出我如何把 清单 1 中的 JMS 模板绑定到示例应用程序中。
清单 4. 把 JmsTemplate 绑定到应用程序中
<bean id="jmsSender" class="springexample.client.JMSSender"> <property name="jmsTemplate102"> <ref bean="jmsQueueTemplate"/> </property> </bean> <bean id="jmsReceiver" class="springexample.client.JMSReceiver"> <property name="jmsTemplate102"> <ref bean="jmsQueueTemplate"/> </property> </bean> |
可以看到,我把 jmsQueueTemplate
绑定到用来发送和接收消息的 JmsSender
应用程序 bean 和 JmsReceiver
bean。清单 5 显示了与JMSSender
类有关的代码。
清单 5. 用 JmsTemplate 发送 JMS 消息的 JMSSender
public class JMSSender { private JmsTemplate102 jmsTemplate102; public JmsTemplate102 getJmsTemplate102() { return jmsTemplate102; } public void setJmsTemplate102(JmsTemplate102 jmsTemplate102) { this.jmsTemplate102 = jmsTemplate102; } public void sendMesage(){ jmsTemplate102.send("JMS_RequestResponseQueue", new MessageCreator() { public Message createMessage(Session session) throws JMSException { return session.createTextMessage("This is a sample message"); } }); } |
JMSSender
类用 jmsTemplate102.send()
方法发送 JMS 消息。send()
方法的第一个参数是 JNDI 队列名,队列名指定了消息应当发送到哪里。(很快就会看到如何把 WebSphere MQ 的队列名绑定到 JNDI。)send()
方法的第二个参数是 MessageCreator
类。JmsTemplate
中的调用代码提供了 Session
类,这个类提供了一个创建 JMS 消息的回调接口。
下一步是用 JMS 的 Session
类创建一个简单的文本消息。在代码执行时,消息会传递给 WebSphere MQ 服务器的队列。清单 6 显示了使用 JmsTemplate
检索 JMS 消息的 JMSReceiver
应用程序 bean 的代码。
清单 6. 用 JmsTemplate 检索 JMS 消息的 JMSReceiver
public class JMSReceiver { private JmsTemplate102 jmsTemplate102; public JmsTemplate102 getJmsTemplate102() { return jmsTemplate102; } public void setJmsTemplate102(JmsTemplate102 jmsTemplate102) { this.jmsTemplate102 = jmsTemplate102; } public void processMessage(){ Message msg = jmsTemplate102.receive("JMS_RequestResponseQueue"); try{ TextMessage textMessage = (TextMessage) msg; if( msg!=null){ System.out.println(" Message Received -->" + textMessage.getText()); } }catch(Exception e){ e.printStackTrace(); } } } |
JMSReceiver
类用 jmsTemplate102.receive()
方法同步地接收 JMS 消息。receive()
方法指定 JNDI 队列名,并从中检索消息。JMSTemplate
类的 processMessage()
方法由接收 JMS 客户机调用。JSMTemplate
bean 的属性 receiveTimeout(列在JMSTemplate
配置中)指定接收客户机同步地从队列中接收消息时要等候的时间。
现在应用程序的代码已完成!下一步就是配置 WebSphere MQ 队列并把它们绑定到 JNDI 对象。
在运行应用程序之前,需要设置 WebSphere MQ 的队列管理器和队列,并把它们绑定到 JNDI。如果喜欢的话,可以按照这部分的示例做:只需 下载 设置 WebSphere MQ 队列的批文件和应用程序的源代码和部署描述符即可。把 zip 文件解压到驱动器 C:。
设置队列
运行 C:\SpringSeriesPart4JMS\batch 文件夹中的 mqsetup.bat 文件。这个批文件要求在 path 环境变量中设置好 MQ 安装的 bin 文件夹(例如 C:\mqseries\bin)。运行了批文件之后,应当看到消息 “All valid MQSC commands were processed
”。要打开 MQ Explorer 并检查已经创建的队列管理器和队列,请选择 Start -> Programs -> IBM MQSeries -> MQSeriesExplorer。图 1 显示出示例应用程序 QueueManager
MQJMS.QManager
已经创建并正在运行。
图 1. WebSphere MQ 的 QueueManager 配置
请在应用程序屏幕左侧面板上点击 MQJMS.QManager
下的 Queues 文件夹。应当看到已经创建了一个队列 RequestResponseQueue
,如图 2 所示。
图 2. WebSphere MQ 的请求/响应队列配置
这就完成了队列的设置。
设置 JMS 和 JNDI 管理
在示例应用程序中,JNDI 的访问利用了可以从 JNDI 主页得到的基于文件的 FSContext
版本(请参阅 参考资料)。FSContext.jar 文件也包含在 WebSphere MQ 的 JMS 支持当中。请添加文件夹 \MQSeriesInstallable\MQSeries\Java\lib 和\MQSeriesInstallable\MQSeries\Java\bin 到系统的 PATH 环境变量中。而且,请把 \MQSeriesInstallable\MQSeries\Java\lib 文件夹中的所有 jar 文件添加到系统的 CLASSPATH 环境变量中。还可以运行 C:\SpringSeriesPart4JMS\batch 文件夹中的 classpath.cmd文件,它会设置必要的 path 和 CLASSPATH 变量。要做到这点,只需要修改 classpath.cmd 文件中的 MQ_JAVA_INSTALL_PATH
,把它指到 WebSphere MQ JMS 的安装目录。
接下来,修改 \MQSeriesInstallableDirectory\Java\bin 中的 JMSAdmin.config 配置文件,MQSeries JMS 管理程序用它指明应用程序要使用的上下文工厂和 JNDI 实现的地址。请取消以下行的注释:
INITIAL_CONTEXT_FACTORY=com.sun.jndi.fscontext.RefFSContextFactory |
并注释掉其余两个 INITIAL_CONTEXT_FACTORY
变量。还要取消以下行的注释:
PROVIDER_URL=file:/C:/JNDI-Directory |
并注释掉其余两个 PROVIDER_URL
变量。
可以在 C:\SpringSeriesPart4JMS\batch 文件夹中发现参考的示例配置文件。
为了保存 JNDI 对象,请在驱动器 C: 上创建名为 JNDI-Directory 的目录。切换到 \MQSeriesInstallableDirectory\Java\bin 目录并运行 JMSAdmin 批文件,应当看到 InitCtx 变量。
逐个输入以下内容:
def qcf(MQ_JMS_MANAGER) qmgr(MQJMS.QManager) |
现在已经把 WebSphere MQ 队列绑定到 JNDI 对象,作为应用程序客户可以通过 JNDI 查询对象。现在剩下的就是看代码的实际作用了!
要运行示例,请从 spring sourceforge download 下载 Spring 框架和它的所有依赖文件并解压,例如解压到 c:\。会创建文件夹C:\spring-framework-1.2-rc2(或最新版本)。
要运行 Spring 应用程序,请把本文的源代码解压到任意文件夹,例如 c:\。会创建文件夹 SpringSeriesPart4JMS。就像前面提到过的,还需要安装 Apache Ant 和它的 Spring 依赖 jar 文件。请把 Spring 库 —— 即 spring.jar(在 C:\spring-framework-1.2-rc2\dist中)和 commons-logging.jar(在 C:\spring-framework-1.2-rc2\lib\jakarta-commons 中)拷贝到 SpringSeriesPart4JMS\lib 文件夹。还要把所有的 jar 库从 \MQSeriesInstallableDirectory\Java\lib 目录拷贝到 SpringSeriesPart4JMS\lib 文件夹。其中包含 MQseries 和 JMS 的相关库。现在就拥有了构建的依赖集。
接下来,打开命令提示符,切换到 SpringProject4 目录,并在命令提示符下输入以下命令:
> ant -f build-jmssender.xml. |
这会构建并运行 SendMQSpringJMS
类,它会调用 JMSSender
类,发送消息到 WebSphere MQ RequestResponse
队列。SendMQSpringJMS
还会通过它的 ClassPathXmlApplicationContext
装入 spring 配置文件。一旦 bean 全部装载,就可以通过 Spring 的 ApplicationContext 的 getBean()
方法访问 JMSSender(请参阅清单 7)。
清单 7. 装入示例应用程序的 Spring 配置
ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(new String[] { "spring-mqseries-jms.xml" }); JMSSender jmsSender = (JMSSender) appContext.getBean("jmsSender"); |
消息传递到队列上之后,请运行 JMS 接收方客户机以检索消息。请打开命令提示符,切换到目录 SpringProject4,并输入:
> ant -f build-jmsreceiver.xml |
这会构建并运行 ReceiveMQSpringJMS
类,该类会调用 JMSReceiver
类,以从 WebSphere MQ 的 RequestResponse
队列接收文本消息。在控制台上会打印出以下消息:
Message Received --> This is a sample message. |
在 Spring 系列的最后这篇文章中,您学习了 Spring JMS 框架的基础。我首先介绍了示例应用程序的核心组件 —— Spring JMS 框架和 IBM 的 WebSphere MQ 5.3,然后介绍了如何用 Spring JMS 模板向 WebSphere MQ 队列发送消息和从中接收消息。虽然这个示例非常简单,但是可以把这里介绍的步骤应用到更复杂的应用程序。
我希望介绍 Spring 框架核心模块的这一系列对您有所帮助。请参阅 参考资料 学习更多有关 Spring 框架和 Spring JMS 的内容。