Spring JMS message processing - based on JNDI

        Spring JMS makes enterprise message processing a breeze, this article will give you a quick overview of the basics of JMS message processing using the Spring JMS framework and IBM WebSphere MQ7.5.0.2.

        JMS PG defines a standard way for Java applications to create and exchange messages through message-oriented middleware (MOM). A simple example will be used to demonstrate the features of Spring JMS. You'll join me in developing a peer-to-peer (P2P) message-based system using the Spring JMS framework to integrate with IBM's WebSphere MQ through a JMS interface. After completing the exercise, you will be able to send and receive simple text messages through this system.

一 .Spring JMS

        Spring's JMS abstraction framework simplifies the use of the JMS API and integrates smoothly with JMS providers such as IBM's WebSphere MQ 5.3. The org.springframework.jms.core package provides the core functionality for using JMS with Spring. Its template classes handle the creation and release of resources, simplifying the use of JMS.

        Like most other Spring template classes, the JMS template classes provide helper methods that perform common operations. In cases where a more complex application is required, the class delegates the core of the processing task to a callback interface implemented by the user. JMS classes provide convenience methods for sending messages, consuming messages synchronously, and exposing JMS sessions and message producers to users.

        The following JMS packages together with org.springframework.jms.core make up the functionality of Spring JMS:

org.springframework.jms.support

        Provides functionality to convert JMSExceptions. The transformation code transforms the detected JMSException hierarchy into a mirrored hierarchy of undetected exceptions.

org.springframework.jms.support.converter

        Provides the MessageConverter abstraction to convert between Java objects and JMS messages.

org.springframework.jms.support.destination

        Provides different strategies for managing JMS objects, such as a service locator for objects stored in JNDI.

org.springframework.jms.connection

        Provides a ConnectionFactory implementation suitable for use in stand-alone applications. connection also contains the Spring PlatformTransactionManager implementation for JMS. It allows the integration of JMS as a transactional resource into Spring's transaction management mechanism.

 

二.IBM WebSphere MQ

        As mentioned earlier, the sample application will use Spring's JMS framework to integrate with IBM's WebSphere MQ through a JMS interface. WebSphere MQ provides reliable, resilient application integration by passing messages between applications and Web services. It uses queues and transactional facilities to help maintain message integrity across the network. WebSphere MQ reduces the risk of information loss and the need to reconcile communicating IT systems.

        WebSphere MQ provides a consistent application programming interface on all platforms it supports, which helps make integrated programs portable. In addition to the standard interfaces, WebSphere MQ fully implements the JMS interfaces, including support for publish-subscribe messaging. The WebSphere MQ Explorer tool can remotely manage and configure an entire MQ network. The management and configuration tools are based on the open source Eclipse framework and are extensible.

 

3. Spring JMS template

        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 组合。

        下面显示了示例应用程序使用的 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 提供者的连接。如下显示了如何从 JNDI 检索连接工厂。

        通过 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 中查询连接工厂。如下显示了 JndiTemplate 配置 bean 的配置。

        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 模板,下一步就是把它绑定到示例应用程序中,然后就可以用它发送和接收消息了。

 

四.Spring JMS 实现

        JMS 模板可以绑定到应用程序中,以发送和接收 JMS 消息。如下可以看出如何把JMS模板绑定到示例应用程序中。

        把 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。如下显示了与 JMSSender 类有关的代码。

        用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 服务器的队列。如下显示了使用 JmsTemplate 检索 JMS 消息的 JMSReceiver 应用程序 bean 的代码。

        用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 队列的批文件和应用程序的源代码和部署描述符即可。

1.设置队列

        运行SpringSeriesPart4JMS\batch文件夹中的 mqsetup.bat 文件。这个批文件要求在 path 环境变量中设置好 MQ 安装的 bin 文件夹(例如IBM\WebSphere MQ\bin)。运行了批文件之后,应当看到消息 “All valid MQSC commands were processed”。要打开 MQ Explorer 并检查已经创建的队列管理器和队列,请选择 Start -> Programs -> IBM WebSphere MQ -> WebSphere MQ Explorer。下图显示出示例应用程序 QueueManagerMQJMS.QManager 已经创建并正在运行。


        这就完成了队列的设置。

2.设置 JMS 和 JNDI 管理

        在示例应用程序中,JNDI 的访问利用了可以从 JNDI 主页得到的基于文件的 FSContext 版本。FSContext.jar 文件也包含在 WebSphere MQ 的 JMS 支持当中。请添加文件夹 \MQSeriesInstallable\WebSphere MQ\Java\lib 和 \MQSeriesInstallable\WebSphere MQ\Java\bin 到系统的 PATH 环境变量中。而且,请把 \MQSeriesInstallable\WebSphere MQ\Java\lib 文件夹中的所有 jar 文件添加到系统的 CLASSPATH 环境变量中。还可以运行 C:\SpringSeriesPart4JMS\batch 文件夹中的 classpath.cmd 文件,它会设置必要的 path 和 CLASSPATH 变量。要做到这点,只需要修改 classpath.cmd 文件中的 MQ_JAVA_INSTALL_PATH,把它指到 WebSphere MQ JMS 的安装目录。

        接下来,修改 \MQSeriesInstallableDirectory\WebSphere MQ\Java\bin 中的JMSAdmin.config 配置文件,WebSphere MQ JMS 管理程序用它指明应用程序要使用的上下文工厂和 JNDI 实现的地址。请取消以下行的注释:

INITIAL_CONTEXT_FACTORY=com.sun.jndi.fscontext.RefFSContextFactory

        并注释掉其余两个 INITIAL_CONTEXT_FACTORY 变量。还要取消以下行的注释:

PROVIDER_URL=file:/C:/JNDI-Directory

        并注释掉其余两个 PROVIDER_URL 变量。

        Reference sample configuration files can be found in the \SpringSeriesPart4JMS\batch folder.

        To save JNDI objects, create a directory named JNDI-Directory on drive C:. Change to the \MQSeriesInstallableDirectory\WebSphere MQ\Java\bin directory and run the JMSAdmin batch file, you should see the InitCtx variable. Enter the following one by one:

def qcf(MQ_JMS_MANAGER) qmgr(MQJMS.QManager)

        press enter

def q(JMS_RequestResponseQueue) qmgr(MQJMS.QManager)  queue(RequestResponseQueue)
        press enter


        Now that the WebSphere MQ queue has been bound to the JNDI object, the object can be queried through JNDI as an application client. Now all that's left is to see the code in action!

 

6. Running the example

        To run the example, download the Spring framework and all its dependencies, unzip it, and copy the Spring library and commons-logging.jar to the SpringSeriesPart4JMS\lib folder. Also copy all jar libraries from the \MQSeriesInstallableDirectory\WebSphere MQ\Java\lib directory to the SpringSeriesPart4JMS\lib folder. It contains related libraries for MQseries and JMS.

        Introduce SpringSeriesPart4JMS into Eclipse and run the SendMQSpringJMS class, which calls the JMSSender class to send messages to the WebSphere MQ RequestResponse queue. SendMQSpringJMS also loads spring configuration files through its ClassPathXmlApplicationContext. Once the beans are all loaded, the JMSSender can be accessed through the getBean() method of Spring's ApplicationContext.

        Load the Spring configuration of the sample application

ClassPathXmlApplicationContext appContext =
new ClassPathXmlApplicationContext(new String[] { "spring/spring-mqseries-jms.xml"
});
JMSSender jmsSender = (JMSSender)appContext.getBean("jmsSender");
        Running the SendMQSpringJMS class will print the following message on the console:
SendMQSpringJMS started
Classpath loaded
SendMQSpringJMS end

        There will be one more message in the MQ queue manager as shown below.


        After the message is delivered to the queue, run the JMS receiver client to retrieve the message. Run the ReceiveMQSpringJMS class, which calls the JMSReceiver class to receive text messages from WebSphere MQ's RequestResponse queue. The following message is printed on the console:

ReceiveMQSpringJMS started
Classpath loaded
 Message Received -->This is a sample message
ReceiveMQSpringJMS end

 

七.结束语

        在Spring 系列的这篇文章中,我们学习了 Spring JMS 框架的基础。首先介绍了示例应用程序的核心组件——Spring JMS 框架和 IBM 的 WebSphere MQ7.5.0.2,然后介绍了如何用 Spring JMS 模板向 WebSphere MQ 队列发送消息和从中接收消息。虽然这个示例非常简单,但是可以把这里介绍的步骤应用到更复杂的应用程序。

 

文章来源:http://www.ibm.com/developerworks/cn/java/wa-spring4/

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326933081&siteId=291194637