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

上传人:b****7 文档编号:9830410 上传时间:2023-02-06 格式:DOCX 页数:14 大小:22.88KB
下载 相关 举报
使用Spring JMS轻松实现异步消息传递.docx_第1页
第1页 / 共14页
使用Spring JMS轻松实现异步消息传递.docx_第2页
第2页 / 共14页
使用Spring JMS轻松实现异步消息传递.docx_第3页
第3页 / 共14页
使用Spring JMS轻松实现异步消息传递.docx_第4页
第4页 / 共14页
使用Spring JMS轻松实现异步消息传递.docx_第5页
第5页 / 共14页
点击查看更多>>
下载资源
资源描述

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

《使用Spring JMS轻松实现异步消息传递.docx》由会员分享,可在线阅读,更多相关《使用Spring JMS轻松实现异步消息传递.docx(14页珍藏版)》请在冰豆网上搜索。

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

使用SpringJMS轻松实现异步消息传递

使用SpringJMS轻松实现异步消息传递

异步进程通信是面向服务架构(SOA)一个重要的组成部分,因为企业里很多系统通信,特别是与外部组织间的通信,实质上都是异步的。

Java消息服务(JMS)是用于编写使用异步消息传递的JEE应用程序的API。

传统的使用JMSAPI进行消息传递的实现包括多个步骤,例如JNDI查询队列连接工厂和Queue资源,在实际发送和接收消息前创建一个JMS会话。

Spring框架则简化了使用JEE组件(包括JMS)的任务。

它提供的模板机制隐藏了典型的JMS实现的细节,这样开发人员可以集中精力放在处理消息的实际工作中,而不用担心如何去创建,访问或清除JMS资源。

本文将对SpringJMSAPI作一个概述,并通过一个运行在JBossMQ服务器上的web例程来介绍如何使用SpringJMSAPI来异步处理(发送和接收)消息。

我将通过传统JMS实现和SpringJMS实现两者间的比较,来展示使用SpringJMS处理消息是如何的简单和灵活。

异步消息传递和面向服务架构

在现实中,大多数web请求都是同步处理的。

例如,当用户要登入一个网站,首先输入用户名和密码,然后服务器验证登录合法性。

如果验证成功,程序将允许该用户进入网站。

这里,登录请求在从客户端接收以后被即时处理了。

信用卡验证是另一个同步处理的例子;只有服务器证实输入的信用卡号是有效的,同时客户在帐户上有足够的存款,客户才被允许继续操作。

但是让我们思考一下在顺序处理系统上的支付结算步骤。

一旦系统证实该用户信用卡的信息是准确的,并且在帐户上有足够的资金,就不必等到所有的支付细节落实、转账完成。

支付结算可以异步方式进行,这样客户可以继续进行核查操作。

需要比典型同步请求耗费更长时间的请求,可以使用异步处理。

另一个异步处理的例子是,在本地贷款处理程序中,提交至自动承销系统(AUS)的信用请求处理过程。

当借方提交贷款申请后,抵押公司会向AUS发送请求,以获取信用历史记录。

由于这个请求要求得到全面而又详细的信用报告,包括借方现今和过去的帐户,最近的付款和其他财务资料,服务器需要耗费较长的时间(几小时或着有时甚至是几天)来对这些请求作出响应。

客户端程序(应用)要与服务器连接并耗费如此长的时间来等待结果,这是毫无意义的。

因此通信应该是异步发生的;也就是,一旦请求被提交,它就被放置在队列中,同时客户端与服务器断开连接。

然后AUS服务从指定的队列中选出请求进行处理,并将处理得到的消息放置在另一个消息队列里。

最后,客户端程序从这个队列中选出处理结果,紧接着处理这个信用历史数据。

JMS

如果您使用过JMS代码,您会发现它与JDBC或JCA很像。

它所包含的样本代码创建或JMS资源对象回溯,使得每一次您需要写一个新类来发送和接收消息时,都具有更好的代码密集性和重复性。

以下序列显示了传统JMS实现所包括的步骤:

创建JNDI初始上下文(context)。

从JNDI上下文获取一个队列连接工厂。

从队列连接工厂中获取一个Quene。

创建一个Session对象。

创建一个发送者(sender)或接收者(receiver)对象。

使用步骤5创建的发送者或接收者对象发送或接收消息。

处理完消息后,关闭所有JMS资源。

您可以看到,步骤6是处理消息的唯一地方。

其他步骤都只是管理与实际业务要求无关的JMS资源,但是开发人员必须编写并维护这些额外步骤的代码。

SpringJMSSpring框架提供了一个模板机制来隐藏JavaAPIs的细节。

JEE开发人员可以使用JDBCTemplate和JNDITemplate类来分别访问后台数据库和JEE资源(数据源,连接池)。

JMS也不例外。

Spring提供JMSTemplate类,因此开发人员不用为一个JMS实现去编写样本代码。

接下来是在开发JMS应用程序时Spring所具有一些的优势。

提供JMS抽象API,简化了访问目标(队列或主题)和向指定目标发布消息时JMS的使用。

JEE开发人员不需要关心JMS不同版本(例如JMS1.0.2与JMS1.1)之间的差异。

开发人员不必专门处理JMS异常,因为Spring为所有JMS异常提供了一个未经检查的异常,并在JMS代码中重新抛出。

一旦您在JMS应用程序中开始使用Spring,您将会欣赏到它在处理异步消息传递上的简便。

SpringJMS框架提供多种Java类,可以轻松实现JMS应用。

表1列出了这些类的一部分。

表1.SpringJMS类

类名包功能JmsExceptionorg.springframework.jms只要发生一个JMS异常,Spring框架就会抛出异常,这个类是这些所抛出的异常的基(抽象)类。

JmsTemplate,JmsTemplate102org.springframework.jms.core这些是辅助类,用于简化JMS的使用,处理JMS资源(如连接工厂,目标和发送者/接收者对象)的创建和释放。

JmsTemplate102是JmsTemplate的子类,使用JMS1.0.2规范MessageCreatororg.springframework.jms.core这是JmsTemplate类使用的回叫接口,它为指定的会话创建JMS消息。

MessageConverterorg.springframework.jms.support.converter这个接口充当一个抽象,用来在Java对象与JMS消息之间进行转换。

DestinationResolverorg.springframework.jms.support.destination这是JmsTemplate用来解析目标名的接口。

该接口的默认实现是DynamicDestinationResolver和JndiDestinationResolve

在接下来的部分,我将详细解释表1所列的一部分类(例如JmsTemplate,DestinationResolver和MessageConverter)。

JMSTemplateJmsTemplate提供了几种辅助方法,用来执行一些基本操作。

要开始使用JmsTemplate前,您需要知道JMS供应商支持哪个JMS规范,JBossAS4.0.2和WebLogic8.1服务器支持JMS1.0.2规范。

WebLogicServer9.0包括了对JMS1.1规范的支持。

JMS1.1统一了点对点(PTP)和发布/订阅(Pub/Sub)域的编程接口。

这种改变的结果就是,开发人员可以创建一个事务会话,然后在这同一个JMS会话里,可以从一个Queue(PTP)中接收消息,同时发送另一个消息到一个Topic(Pub/Sub)。

JMS1.1向后兼容JMS1.0,应此根据JMS1.0编写的代码仍可以适用于JMS1.1。

JmsTemplate提供多种发送和接收消息的方法。

表2列出了这些方法的一部分。

表2.JMStemplate方法

方法名称功能send发送消息至默认或指定的目标。

JmsTemplate包含send方法,它通过javax.jms.Destination或JNDI查询来指定目标。

receive从默认或指定的目标接收消息,但只会在指定的时间后传递消息。

我们可以通过receiveTimeout属性指定超时时间。

convertAndSend这个方法委托MessageConverter接口实例处理转换过程,然后发送消息至指定的目标。

receiveAndConvert从默认或指定的目标接收消息。

并将消息转换为Java对象。

目标可以通过JNDI上下文保存和获取。

当配置Spring程序上下文(applicationcontext)时,我们可以用JndiObjectFactoryBean类取得对JMS的引用。

DestinationResolver接口是用来把目标名称解析成JMS目标,当应用程序存在大量目标时,这是非常有用的。

DynamicDestinationResolver(DestinationResolver的默认实现)是用来解析动态目标的。

MessageConverter接口定义了将Java对象转换为JMS消息的约定。

通过这个转换器,应用程序代码可以集中于处理事务对象,而不用为对象如何表示为JMS消息这样的内部细节所困饶。

SimpleMessageConverter(和SimpleMessageConverter102)是MessageConverter的默认实现。

可使用它们分别将String转换为JMSTextMessage,字节数组(byte)转换为JMSBytesMessage,Map转换为JMSMapMessage,和Serializable对象转换为JMSObjectMessage。

您也可以编写自定义的MessageConverter实例,通过XML绑定框架(例如JAXB,Castor,CommonsDigester,XMLBeans或XStream),来实现XML文档到TextMessage对象的转换。

示例程序

我将用一个贷款申请处理系统(命名为LoanProc)示例来演示如何在JMS应用程序中使用Spring。

作为贷款申请的一部分,LoanProc通过发送贷款详情(贷款ID,借方名字,借方的SSN,贷款期限和贷款数额),从AUS系统获得信用历史详情。

为了简便起见,我们基于两个基本参数来表示信用历史详情:

信用分数(又名FICO得分)和贷款数额。

让我们假设处理信用检查请求是按以下业务规则进行的:

如果贷款数额等于或低于,000,借方必须至少有一个"好"的信用(也就是,借方的FICO得分在680到699之间)。

如果贷款数额高于,000,借方必须至少有"很好"的信用,意味着借方的信用得分要高于700。

贷款申请使用案例

信用请求处理使用案例包括以下几个步骤:

用户在贷款申请页面输入贷款详情并提交贷款申请。

发送请求到一个名为CreditRequestSendQueue的消息队列。

然后程序发送贷款详情到AUS系统,获取信用历史详情。

AUS系统从队列中挑出贷款详情,并使用贷款参数从它的数据库中获取信用历史信息。

然后AUS将找到的借方的信用历史信息创建一个新的消息,发送到一个新的名为CreditRequestReceiveQueue的消息队列。

最后,LoanProc从接收队列中选出响应消息,处理贷款申请来决定是否批准或否决申请。

在这个例程中,两个消息队列都配置在同一个JBossMQserver上。

使用案例用图1的序列图(SequenceDiagram)表示

图1.贷款处理程序的序列图

下面的表3显示了在例程中我所使用的不同技术和开源框架,并按应用逻辑层排列。

表3.在JMS应用程序中使用的框架

逻辑层技术/框架MVCSpringMVCServiceSpringFramework(version2.1)JMSAPISpringJMSJMSProviderJBossMQ(version4.0.2)JMSConsoleHermesIDEEclipse3.1

使用Hermes设置JMS资源

为了异步处理消息,首先我们需要消息队列发送和接收消息。

我们可以用Jboss里的配置XML文件创建一个新的消息队列,然后使用JMS控制台浏览队列的详细情况。

清单1显示了配置JMS的XML配置代码片断(这个应该加入到jbossmq-destinations-service.xml文件,位于%JBOSS_HOME%serverlldeploy-hasingletonjm文件夹下。

清单1.JBossMQServer上JMS队列的配置

--CreditRequestSendQueue--

mbeancode="org.jboss.mq.server.jmx.Queue"

name="jboss.mq.destination:

service=Queue,name=CreditRequestSendQueue"

dependsoptional-attribute-name="DestinationManager"

jboss.mq:

service=DestinationManager

/depends

/mbean

--CreditRequestReceiveQueue--

mbeancode="org.jboss.mq.server.jmx.Queue"

name="jboss.mq.destination:

service=Queue,name=CreditRequestReceiveQueue"

dependsoptional-attribute-name="DestinationManager"

jboss.mq:

service=DestinationManager

/depends

/mbean

现在,让我们看看如何使用一个名为Hermes的JMS工具来浏览消息队列。

Hermes是一个JavaSwing应用程序,它可以创建、管理和监视JMS提供商(例如JBossMQ,WebSphereMQ,ActiveMQ和Arjuna服务器)里的JMS目标。

从它的网站上下载Hermes,解压缩.zip文件到本地目录(例如,c:

devoolshermes)。

一旦安装完成,双击文件hermes.bat(位于bin文件夹下)启动程序。

要在Hermes里配置JBossMQ服务器,请参考Hermes网站上的这个演示。

它有着出色的step-by-step可视化指示来配置JBossMQ。

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

providerURL=jnp:

//localhost:

1099initialContextFactory=org.jnp.interfaces.NamingContextFactoryurlPkgPrefixes=org.jnp.interfaces:

org.jboss.namingsecurityCredentials=adminsecurityPrincipal=admin

当您创建新的目标时,请输入queue/CreditRequestSendQueue和queue/CreditRequestReceiveQueue。

图2显示了JMS控制台的主窗口,其中有为JMS例程创建的新的消息队列。

图2.Hermes中所有目标的截图

下面的图3显示了在从消息发送者类发送消息到CreditRequestSendQueue后,HermesJMS控制台及消息队列的截图。

您可以看见有5个消息在队列中,控制台显示了消息详情,例如消息ID,消息目标,时间戳和实际的消息内容。

图3.Hermes中所有队列的截图

在例程中使用的队列名称和其他JMS和JNDI参数见表4。

表4.SpringJMS配置参数

参数名称参数值InitialContextFactoryorg.jnp.interfaces.NamingContextFactoryProviderURLlocalhost:

8080InitialContextFactoryURLPackagesorg.jnp.interfaces:

org.jboss.namingQueueConnectionFactoryUIL2ConnectionFactoryQueueNamequeue/CreditRequestSendQueue,queue/CreditRequestReceiveQueueSpring配置

既然我们已经有了运行例程所需要的JMS目标,现在该了解用XMLSpring配置文件(名为spring-jms.xml)来组配JMS组件的具体细节了。

这些组件是根据InversionofController(IOC)设计模式里的设置方式注入原则(setterinjectionprinciple),用JMS对象实例类组配的。

让我们详细查看这些组件,并为每一个JMS组件演示一段XML配置代码。

JNDI上下文是取得JMS资源的起始位置,因此首先我们要配置JNDI模板。

清单2显示了名为jndiTemplate的Springbean,其中列有JNDI初始上下文所必需的常用参数。

清单2.JNDI上下文模板

beanid="jndiTemplate"class="org.springframework.jndi.JndiTemplate"

propertyname="environment"

propspropkey="java.naming.factory.initial"

org.jnp.interfaces.NamingContextFactory

/proppropkey="java.naming.provider.url"

localhost

/proppropkey="java.naming.factory.url.pkgs"

org.jnp.interfaces:

org.jboss.naming

/prop

/props

/property

/bean

接着,我们配置队列连接工厂。

清单3显示了队列连接工厂的配置。

清单3.JMS队列连接工厂配置

beanid="jmsQueueConnectionFactory"

class="org.springframework.jndi.JndiObjectFactoryBean"

propertyname="jndiTemplate"

refbean="jndiTemplate"/

/propertypropertyname="jndiName"

valueUIL2ConnectionFactory/value

/property

/bean

我们定义2个JMS目标来发送和接收消息。

详情见清单4和5。

清单4.发送队列配置

beanid="sendDestination"

class="org.springframework.jndi.JndiObjectFactoryBean"

propertyname="jndiTemplate"

refbean="jndiTemplate"/

/propertypropertyname="jndiName"

valuequeue/CreditRequestSendQueue/value

/property

/bean

清单5.接收队列配置

beanid="receiveDestination"

class="org.springframework.jndi.JndiObjectFactoryBean"

propertyname="jndiTemplate"

refbean="jndiTemplate"/

/propertypropertyname="jndiName"

valuequeue/CreditReqeustReceiveQueue/value

/property

/bean

然后我们再来配置JmsTemplate组件。

在例程中我们使用JmsTemplate102。

同时使用defaultDestination属性来指定JMS目标。

清单6.JMS模板配置

beanid="jmsTemplate"

class="org.springframework.jms.core.JmsTemplate102"

propertyname="connectionFactory"

refbean="jmsQueueConnectionFactory"/

/propertypropertyname="defaultDestination"

refbean="destination"/

/propertypropertyname="receiveTimeout"

value30000/value

/property

/bean

最后我们配置发送者和接收者组件。

清单7和8分别是Sender和Receiver对象的配置。

清单7.JMSSender配置

beanid="jmsSender"class="springexample.client.JMSSender"

propertyname="jmsTemplate"

refbean="jmsTemplate"/

/property

/bean

清单8.JMSReceiver配置

beanid="jmsReceiver"class="springexample.client.JMSReceiver"

propertyname="jmsTemplate"

refbean="jmsTemplate"/

/property

/bean

测试及监视

我写了一个测试类,命名为LoanApplicationControllerTest,用来测试LoanProc程序。

我们可以使用这个类来设定贷款参数以及调用信用请求服务类。

让我们看一下不使用SpringJMSAPI而使用传统JMS开发途径的消息发送者实例。

清单9显示了MessageSenderJMS类里的sendMessage方法,其中包含了使用JMSAPI处理消息的所有必需步骤。

清单9.传统JMS实例

publicvoidsendMessage(){

queueName="queue/CreditRequestSendQueue";

System.out.println("Queuenameis"+queueName);

/*

*CreateJNDIInitialContext

*/

try{

Hashtableenv=newHashtable();

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=newInitialContext(env);

}catch(NamingExceptione){

System.out.println("CouldnotcreateJNDIAPI"+

"context:

"+e.toString());

}

/*

*GetqueueconnectionfactoryandqueueobjectsfromJNDIcontext.

*/

try{

queueConnectionFactory=(QueueConnectionFactory)

jndiContext.lookup("UIL2ConnectionFactory");

queue=(Queue)jndiContext.lookup(queueName);

}catch(NamingExceptione){

System.out.println("JNDIAPIlookupfailed:

"+

e.toString());

}

/*

*Createconnection,session,senderobjects.

*Sendthemessage.

*CleanupJ

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 总结汇报 > 学习总结

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1