`

用Spring JMS使异步消息变得简单

    博客分类:
  • Java
阅读更多

 
用Spring JMS使异步消息变得简单
 
 

异步处理通信是面向服务架构(SOA)的重要部分,因为企业中的许多系统通信,尤其是跟外部系统通信本来就是异步的。Java消息服务(JMS)就是用来编写异步消息J2EE应用的API。使用JMS API的传统消息实现涉及到象这样的一些步骤:查找对列连接工厂、队列资源以及在实际发送和接受消息前,创建JMS会话(JMS session)。

Spring framework简化了用JEE组件(包括JMS)开发JMS应用的工作。它提供了一个模板机制来隐藏典型的JMS实现细节,所以开发者可以专注于消息处理任务而不用担心怎样创建、访问和释放JMS资源。

本文用一个运行在JBoss MQ server上的简单Web应用概述了Spring JMS API和怎样使用它异步处理(发送和接受)消息。我将对比JMS实现的传统方法和Spring JMS实现方法,以显示使用Spring JMS来处理消息是多么的简单和灵活。

异步消息和SOA

现实世界中,大多数Web请求是同步处理的。例如,当用户登陆一个站点,他或她输入用户名和口令以及服务器识别登陆凭证。如果身份验证成功,程序让用户进入站点。这里,登陆请求从客户端被接受后,立即被处理。信用卡授权也是一个同步处理的例子;仅当服务器核实了发送进来的信用卡号是有效并且该客户的帐号有足够的信用额度后,才允许客户继续进行下一步动作。让我们来考察一下订单处理系统中的支付结算步骤。一旦系统核实了那个用户的信用卡信息是正确的,而且帐户上有足够的资金,那么不需要等到支付细节和转帐最终完成。支付结算用异步方式处理,如此客户便可以继续进行结帐处理。

与典型的同步请求相比,异步处理用于需要长时间来处理的请求。异步处理的另外一个例子是住房贷款处理应用中,处理提交到AUS(Automated Underwriting System)的贷款请求。贷款人提交贷款申请后,抵押公司发送请求到AUS取得信用历史信息。因为该请求要取得综合详细的信用报告如贷款人当前和过去的信用帐户,最近的支付以及其它金融详细信息,所以从请求到获得响应常常需要很长时间。对客户端程序来说开一个到服务器的连接并且长时间等待响应是没有意义的。于是就有了异步通信;也就是,一旦请求被提交,它就被放入队列里面并且客户断开服务器连接。然后,AUS服务从特定队列摘取请求,处理它,把结果消息放入另外一个消息队列。最后客户程序从消息队列摘取响应结果继续处理信用历史结果信息。

JMS

如果用过JMS的话,会发现它类似写JDBC或JCA代码。它有创建或检索JMS资源的样板代码,每当你需要编写一个新类来发送或接受消息时,都得重复编写那个样本代码。下面列出了传统JMS实现涉及的步骤:

1、创建JNDI初始上下文context;
2、从JNDI上下文获得队列连接工厂;
3、从队列连接工厂取得队列Queue;
4、创建一个Session对象;
5、创建一个发送或接受对象;
6、利用第5部创建的发送或接受对象发送或接受消息;
7、处理完消息后,关闭所有JMS资源。

如你所见,只有第6步是处理消息的步骤。其他步骤都只是管理JMS资源,与实际业务需求无关,但开发者不得不编写和维护那些附加步骤代码。

Spring JMS

Spring框架提供一个模板机制来隐藏Java API细节。JEE开发者可用JDBCTemplate和JNDITemplate类来分别访问后端数据库和JEE资源(数据源,连接池)。JMS没有异常。Spring提供了JMSTemplate类,所以开发者不必为JMS实现编写样本代码。当开发JMS应用时,Spring提供了一下一些优势:

1、提供了一个JMS的抽象API,简化了JMS的使用。如:访问目的地(队列或主体)和出版消息到特定目的地。
2、JEE开发者不必关心JMS不同版本之间的差异(如JMS 1.0.2 同 JMS 1.1);
3、开发者不必特定地处理JMS异常,因为Spring为JMS代码抛出的任何JMS异常提供了一个unchecked异常。

一旦你在JMS应用中开始使用Spring,你将会欣赏到异步消息处理的简易性。Spring JMS框架提供了各种java类使JMS开发变得简单。

image

表1:Spring JMS类

随后的部分,我将详细解释表1中的类(如JmsTemplate, DestinationResolver,和 MessageConverter)。

#p#

JMSTemplate

JmsTemplate提供了几个helper方法来执行基本操作。开始使用JmsTemplate前,有必要知道JMS提供者支持哪种JMS规范。JBoss AS 4.0.2 和 WebLogic 8.1服务器支持JMS1.0.2规范。WebLogic 服务器 9.0包含JMS1.1支持。JMS1.1统一了PTP和Pub/Sub编程接口。有了这个改变,开发者可以创建一个事务会话,然后在同一个JMS事务中,从Queue(PTP)接受消息和发送一个消息到Topic(Pub/Sub)。JMS1.1向后兼容JMS1.0,因此基于JMS1.0编写的代码仍然能跟JMS1.1工作。

JmsTemplate提供各种方法来接收和发送消息。表2是方法列表。

image

表2:JMS模板方法

使用JNDI上下文存储和检索目的地。当配置Spring应用上下文时,我们用JndiObjectFactoryBean获得JMS目的地引用。DestinationResolver用来解析目的地名称到一个JMS目的地,当应用有许多目的地时,那是很有帮助的。DynamicDestinationResolver(缺省DestinationResolver实现)用于解析动态目的地。

MessageConverter接口定义了java对象和JMS消息之间转换的契约。使用转换器,应用代码可以专注于业务对象,不用操心它是如何代表JMS消息的。SimpleMessageConverter(和SimpleMessageConverter102)是缺省MessageConverter实现。它们用于将String、字节数组((byte[])、Map、Serializable对象分别转换成JMS TextMessage、JMS BytesMessage,JMS MapMessage,JMS ObjectMessage。你可以编写MessageConverter接口的定制实现并结合XML绑定框架如JAXB, Castor, Commons Digester, XMLBeans, 或 XStream来转换XML文档到TextMessage。

样本应用

我将用一个样本贷款应用处理系统(叫LoanProc)来说明怎样在JMS应用中使用Spring。作为贷款处理的一部分,LoanProc发送贷款详细资料(loan ID, borrower name, borrower's SSN, loan expiration date, and loan amount)从AUS系统请求信贷历史。为让例子简单一点,我们将基于两个参数:信用评分和贷款数量来获得信贷历史详细资料。让我们假定处理信用检查请求的业务规则如下:

1、如果贷款数量等于或小于$500,000,那么贷款人必须至少有一个“good”信用(例如,贷款人的信用评分在680到699之间);
2、如果贷款数量超过$500,000,那么贷款人必须至少要有一个“very good”信用,这意味他/她的信用评分超过700。

贷款应用Use Case

贷款请求处理Use Case由下列步骤组成:

1、用户在贷款申请web页面输入贷款详细资料并提交贷款申请;
2、然后程序发送贷款详细资料到AUS系统取得信用历史详细资料。用发送请求到名叫CreditRequestSendQueue的消息队列来完成。
3、AUS系统从队列摘取贷款详细资料并用贷款参数来从数据库检索信用历史信息;
4、然后AUS系统用找到的贷款人信用历史信息创建一个新的消息并发送到名叫CreditRequestReceiveQueue的消息队列;
5、最后LoanProc从接收消息队列摘取响应消息并处理贷款申请,决定申请是被核准还是拒绝。

应用中,在同样的JBoss MQ server中配置了两个消息队列。Use Case用序列图1表示如下:

image

图1:贷款处理应用的序列图

技术

表3列出了例子应用中用到的一些技术和开源框架

image

表3:JMS应用中用到的框架

#p#

使用Hermes 的JMS资源设置

为异步处理消息,首先,我们需要消息队列来发送和接收消息。我们在JBoss中使用xml配置文件创建消息队列并且用JMS控制台来浏览队列详细资料。清单1显示了XML配置文件JMS配置片断。(这个片断可以被添加到%JBOSS_HOME%\server\all\deploy-hasingleton\jms目录下的jbossmq-destinations-service.xml文件中。)

清单1:JBoss MQ服务器中JMS队列配置

<!--  Credit Request Send Queue  --> <mbean code="org.jboss.mq.server.jmx.Queue"   name="jboss.mq.destination:service=Queue,name=CreditRequestSendQueue">    <depends optional-attribute-name="DestinationManager">       

jboss.mq:service=DestinationManager    </depends></mbean> <!--  Credit Request Receive Queue  --> <mbean code="org.jboss.mq.server.jmx.Queue"   

name="jboss.mq.destination:service=Queue,name=CreditRequestReceiveQueue">  <depends optional-attribute-name="DestinationManager">     

jboss.mq:service=DestinationManager  </depends> </mbean>  

现在,让我们看看怎么使用一个叫做Hermes的JMS工具浏览消息队列。Hermes是一个Java Swing应用,它能创建、管理和监控JMS提供者中的JMS destination。这样的JMS提供者有JBossMQ, WebSphereMQ, ActiveMQ 和 Arjuna。从website下载Hermes并解压zip文件到一个本地目录(如c:\dev\tools\hermes)。一旦安装,双击hermes.bat (在bin目录)启动程序。

为在Hermes中配置JBossMQ服务器,参考Hermes站点上的demo。它一步一步形象说明了JBoss MQ的配置。

当配置一个新的JNDI初始上下文时,输入下面的配置信息。

providerURL = jnp://localhost:1099 initialContextFactory = org.jnp.interfaces.NamingContextFactory urlPkgPrefixes = org.jnp.interfaces:org.jboss.naming securityCredentials = admin securityPrincipal = admin

当创建一个新destinations时,输入queue/CreditRequestSendQueue和queue/CreditRequestReceiveQueue。图2显示了JMS控制台主屏幕,它显示了为样本JMS应用创建的新消息。

image

图2:Hermes中所有destinations的截屏

图3是消息发送者发送一些消息到CreditRequestSendQueue后,Hermes JMS控制台显示的消息队列详细资料。你能看到这里队列中有5个消息并且控制台显示了消息的详细信息如message ID、message destination、time stamp、和实际的消息。

image

图3:Hermes中队列详细资料截屏

使用Spring JMS,异步消息变得简单

用在样本应用中的这些消息队列名和其它JMS以及JNDI参数如下表4所示。

image

表4:Spring JMS配置参数

#p#

Spring配置

已经有了运行样本应用所需的JMS destinations,现在该是进入用XML Spring配置文件(叫做spring-jms.xml)装配JMS组件的细节的时候了。用IOC设计模式中的setter依赖注入原理装入这些组件。让我们仔细看看组件,为每一个JMS组件显示了一个XML配置片断。

JNDI上下文是获取JMS资源的入口,所以我们首先配置一个JNDI模板。清单2显示了一名为jndiTemplate的Spring bean,它具有取得JNDI初始上下文必须的常用参数。

清单2:JNDI上下文模板

<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">     <property name="environment">         <props>             <prop key="java.naming.factory.initial">               

org.jnp.interfaces.NamingContextFactory             </prop>             <prop key="java.naming.provider.url">                 localhost             </prop>             <prop key="java.naming.factory.url.pkgs">                                    

          org.jnp.interfaces:org.jboss.naming             </prop>         </props>     </property> </bean>  

下一步,我们配置队列连接工厂。清单3显示了队列连接工厂。

清单3:JMS对了连接工厂配置

<bean id="jmsQueueConnectionFactory"           

class="org.springframework.jndi.JndiObjectFactoryBean">     <property name="jndiTemplate">         <ref bean="jndiTemplate"/>     </property>     <property name="jndiName">          <value>UIL2ConnectionFactory</value>     </property> </bean> 

我们定义了两个JMS destinations来发送和接收消息。清单4和清单5显示了这些细节。

清单4:发送队列配置

<bean id="sendDestination"     class="org.springframework.jndi.JndiObjectFactoryBean">     <property name="jndiTemplate">         <ref bean="jndiTemplate"/>     </property>     <property name="jndiName">         <value>queue/CreditRequestSendQueue</value>     </property> </bean>  

清单5:接收队列配置

<bean id="receiveDestination"     class="org.springframework.jndi.JndiObjectFactoryBean">     <property name="jndiTemplate">         <ref bean="jndiTemplate"/>     </property>         <property name="jndiName">         <value>queue/CreditReqeustReceiveQueue</value>         </property> </bean>  

然后,我们配置JmsTemplate组件。我们在样本应用中使用JmsTemplate102。使用defaultDestination属性来指定JMS destination。

清单6:JMS template配置

<bean id="jmsTemplate"        class="org.springframework.jms.core.JmsTemplate102">     <property name="connectionFactory">         <ref bean="jmsQueueConnectionFactory"/>     </property>     <property name="defaultDestination">         <ref bean="destination"/>      </property>     <property name="receiveTimeout">         <value>30000</value>     </property> </bean>

最后,我们配置发送和接收者组件。清单7和清单8显示了Sender 和Receiver对象配置。

清单7:JMS Sender配置

Listing 7. JMS Sender configuration <bean id="jmsSender" class="springexample.client.JMSSender">     <property name="jmsTemplate">         <ref bean="jmsTemplate"/>     </property> </bean>  

清单8:JMS Receiver配置

<bean id="jmsReceiver" class="springexample.client.JMSReceiver">     <property name="jmsTemplate">         <ref bean="jmsTemplate"/>     </property> </bean>

#p#

测试和监控

我借了一个叫做LoanApplicationControllerTest的测试类来测试LoanProc应用。我们使用这个类来设置贷款参数和调用那个信用请求服务类。

让我们看看使用传统JMS而不用Spring JMS API的消息发送者实现。清单9显示了MessageSenderJMS这个类的sendMessage方法,这个类具备使用JMS API处理消息的所有必须步骤。

清单9:传统JMS实现

public void sendMessage() {     queueName = "queue/CreditRequestSendQueue";         System.out.println("Queue name is " + queueName);     /*     * Create JNDI Initial Context     */     try {         Hashtable env = new Hashtable();         env.put("java.naming.factory.initial",                       

"org.jnp.interfaces.NamingContextFactory");         env.put("java.naming.provider.url","localhost");         env.put("java.naming.factory.url.pkgs",                       

"org.jnp.interfaces:org.jboss.naming");         jndiContext = new InitialContext(env);     } catch (NamingException e) {            System.out.println("Could not create JNDI API " +            "context: " + e.toString());    }      /*          * Get queue connection factory and queue objects from JNDI context.      */     try {         queueConnectionFactory = (QueueConnectionFactory)         jndiContext.lookup("UIL2ConnectionFactory");         queue = (Queue) jndiContext.lookup(queueName);    } catch(NamingException e) {         System.out.println("JNDI API lookup failed: " +                        e.toString());    }    /*    * Create connection, session, sender objects.    * Send the message.    * Cleanup JMS connction.    */     try {         queueConnection =                                                         

queueConnectionFactory.createQueueConnection();         queueSession = queueConnection.createQueueSession(false,                           

             Session.AUTO_ACKNOWLEDGE);         queueSender = queueSession.createSender(queue);              message = queueSession.createTextMessage();         message.setText("This is a sample JMS message.");         System.out.println("Sending message: " + message.getText());                       

        queueSender.send(message);     } catch (JMSException e) {         System.out.println("Exception occurred: " + e.toString());     } finally {         if (queueConnection != null){             try {                 queueConnection.close();             } catch (JMSException e) {}         }     } }

现在,让我们看看用Spring实现的消息发送者。清单10显示了MessageSenderSpringJMS类中send方法代码。

清单10:用Spring API的JMS实现

public void send() {     try {         ClassPathXmlApplicationContext appContext =             new ClassPathXmlApplicationContext(new String[]             { "spring-jms.xml"});                 System.out.println("Classpath loaded");          JMSSender jmsSender = (JMSSender)appContext.getBean("jmsSender");                 

       jmsSender.sendMesage();         System.out.println("Message sent using Spring JMS.");     } catch(Exception e) {         e.printStackTrace();       } }  

如你所见,所有与管理JMS资源相关的资源步骤都由Spring容器用配置文件处理。我们仅需要获取JMSSender引用并且调用它上面的sendMessage即可。

结论

本文中,我们看到Spring框架如何简化了使用JMS API的异步消息应用开发的工作。Spring移走了所有JMS消息处理必须的样板代码,如获取连接工厂,从Java代码创建队列和会话对象并在运行时用配置文件装配它们。由于这个强大的IOC原理,我们可以不必修改Java代码便可动态交换JMS资源对象。

因为异步消息是构成SOA框架整体所需的一部分,Spring非常适合放入SOA工具集。同样,JMS管理工具如Hermes使得创建,管理和控制JMS资源变得简单,尤其对系统管理员。

(责任编辑 火凤凰 sunsj@51cto.com  TEL:(010)68476636-8007)

 
  • 大小: 73.9 KB
  • 大小: 26.8 KB
  • 大小: 26.8 KB
  • 大小: 12.1 KB
  • 大小: 12.1 KB
  • 大小: 41.3 KB
  • 大小: 24.1 KB
分享到:
评论

相关推荐

    Spring JMS使异步消息变得简单.doc

    Spring JMS使异步消息变得简单.docSpring JMS使异步消息变得简单.doc

    spring jms tomcat 异步消息传递入门实例

    1. **Spring JMS**:Spring框架提供了JMS模块,使得在Spring应用中集成JMS变得简单。通过`org.springframework.jms.core.JmsTemplate`,我们可以方便地发送和接收消息。配置JMS模板,需要指定ConnectionFactory,它...

    tomcat spring jms 异步消息传递入门实例

    Spring提供了对JMS的抽象,使得配置变得简单。 ```xml <bean id="jmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean"> <bean id="destination" class="org.springframework....

    使用Spring JMS轻松实现异步消息传递.pdf

    【Spring JMS 知识点详解】 Spring JMS 是 Spring ...总结来说,Spring JMS 通过提供模板和容器化的消息处理,大大简化了 JMS 的使用,使得异步消息传递变得简单易用。这对于构建高可用、可扩展的 SOA 系统至关重要。

    Spring发送接收JMS消息

    Spring的JMS支持使得在应用中使用消息传递变得简单且灵活。通过配置`ConnectionFactory`、`JmsTemplate`和消息监听器,我们可以方便地实现消息的发送和接收,从而提高系统的可扩展性和解耦性。同时,Spring提供的...

    Spring JMS 消息处理-基于JNDI

    它为不同的消息中间件提供商提供了一个统一的API,使得在不同中间件之间切换变得相对简单。消息中间件如ActiveMQ、RabbitMQ、IBM WebSphere MQ等,通过JMS接口与应用程序交互。 Spring JMS是Spring框架对JMS的封装...

    JMS整合Spring实例

    而Spring框架是Java开发中广泛使用的轻量级框架,它提供了一个全面的编程和配置模型,使得开发企业级应用变得更加简单。整合JMS与Spring可以帮助我们构建更高效、可扩展的消息驱动系统。 在Spring框架中,我们可以...

    java EE入门基础资料

    Spring JMS(Java Message Service)使得异步消息处理变得简单,用Spring JMS使异步消息变得简单.docx将介绍如何使用Spring框架集成JMS,实现应用程序间的非阻塞通信,提高系统的响应速度和可扩展性。 Spring MVC是...

    spring-jms

    这个jar包,即`spring-jms-3.1.1.RELEASE.jar`,包含了Spring对JMS API的抽象和扩展,使得在Spring应用中使用JMS变得更加简单和灵活。 **Spring JMS核心概念** 1. **JMS模板(JmsTemplate)**: 这是Spring提供的一...

    activemq消息中间件的使用demo,以及spring集合jms实现消息发送和处理。

    Spring对JMS的支持使得在应用中集成消息服务变得简单。在Spring中,你可以使用`JmsTemplate`或声明式的方式(如`@JmsListener`注解)来发送和接收消息。JMS(Java消息服务)是Java平台上的一个标准接口,它定义了...

    Spring In Action 使用Spring发送和接收JMS消息

    《Spring In Action 使用Spring...总之,Spring框架为JMS提供了一套强大且灵活的抽象层,简化了开发者的工作,让消息传递变得更加高效和可靠。通过实践和学习,我们可以更好地利用这一特性,提升应用的性能和稳定性。

    Spring JMS消息处理-不基于JNDI

    Spring JMS提供了一组高级抽象,如`JmsTemplate`和`MessageListenerContainer`,使得处理JMS消息变得更加简单。`JmsTemplate`用于发送和接收消息,而`MessageListenerContainer`则用于监听消息队列并执行相应的回调...

    JMS实例,整合spring,含jar

    Spring框架是一个广泛使用的Java开发框架,它提供了对JMS的全面支持,使得集成和管理消息变得更加简单。 本实例中,"JMS实例,整合spring,含jar"表明这是一个具体的项目示例,展示了如何在Spring框架中配置和使用JMS...

    spring-jms:Spring JMS教程

    Spring Boot与Spring JMS的结合使得配置变得更加简单,只需几行代码即可快速启动和运行JMS应用。 ### 2. JMS基础 JMS是一种标准API,用于在分布式环境中交换消息。它定义了生产者(发送消息)和消费者(接收消息)...

    Spring整合JMS

    Spring的JMS模块使得集成JMS变得简单且灵活,无论是在简单的消息传递还是复杂的消息转换场景下。 1. **配置JMS** 在Spring中,我们可以通过XML或Java配置来设置JMS连接工厂、目的地(队列或主题)以及消息监听器。...

    JMS之ActiveMQ与Spring整合源码

    通过以上知识点的讲解,我们可以看到,ActiveMQ与Spring的整合使得在Java应用中使用JMS变得更加简单和高效。无论是消息的生产还是消费,都能通过Spring的抽象和ActiveMQ的稳定性能得到很好的支持。在实际项目中,...

    spring整合JMS-居于ActiveMQ实现

    Spring的`MessageListenerAdapter`使得监听器的实现变得简单,只需要提供处理消息的方法即可。例如: ```java @Component public class MyMessageListener { @JmsListener(destination = "myQueue") public void ...

    jms Spring+ActiveMQ 5.4.2

    1. **Spring JMS模块**:Spring框架提供了JMS模块,使得在Spring应用中集成JMS变得简单。它提供了Template和Container抽象,用于发送和接收消息。 2. **配置ActiveMQ**:在Spring应用中使用ActiveMQ,需要配置...

    spring使用activeMQ实现消息发送

    Spring提供了`spring-jms`模块,它包含了一组丰富的API和配置选项,使得在Spring应用中集成ActiveMQ变得简单。通过使用`JmsTemplate`类,我们可以方便地发送和接收消息。 1. **配置ActiveMQ**:在开始之前,我们...

    spring-kms-test源码

    标签"spring-jms"提示我们关注的是Spring对JMS的集成,Spring JMS Test通过`JmsTemplate`抽象了JMS操作,使得测试变得简单易行。`JmsTemplate`提供了一组模板方法,如`convertAndSend()`、`send()`、`receive()`等,...

Global site tag (gtag.js) - Google Analytics