引用
核心提示:异步进程通信是面向服务架构(SOA)一个重要的组成部分,因为企业里很多系统通信,特别是与外部组织间的通信,实质上都是异步的。Java消息服务(JMS)是用于编写使用异步消息传递的JEE应用程序的API。传统的使用JMS API进行消息传递的实现包括多个步骤,例如JNDI
异步进程通信是面向服务架构(SOA)一个重要的组成部分,因为企业里很多系统通信,特别是与外部组织间的通信,实质上都是异步的。Java消息服务(JMS)是用于编写使用异步消息传递的JEE应用程序的API。传统的使用JMS API进行消息传递的实现包括多个步骤,例如JNDI查询队列连接工厂和Queue资源,在实际发送和接收消息前创建一个JMS会话。
Spring框架则简化了使用JEE组件(包括JMS)的任务。它提供的模板机制隐藏了典型的JMS实现的细节,这样开发人员可以集中精力放在处理消息的实际工作中,而不用担心如何去创建,访问或清除JMS资源。
本文将对Spring JMS API作一个概述,并通过一个运行在JBoss MQ服务器上的web例程来介绍如何使用Spring JMS API来异步处理(发送和接收)消息。我将通过传统JMS实现和Spring JMS实现两者间的比较,来展示使用Spring JMS处理消息是如何的简单和灵活。
异步消息传递和面向服务架构
在现实中,大多数web请求都是同步处理的。例如,当用户要登入一个网站,首先输入用户名和密码,然后服务器验证登录合法性。如果验证成功,程序将允许该用户进入网站。这里,登录请求在从客户端接收以后被即时处理了。信用卡验证是另一个同步处理的例子;只有服务器证实输入的信用卡号是有效的,同时客户在帐户上有足够的存款,客户才被允许继续操作。但是让我们思考一下在顺序处理系统上的支付结算步骤。一旦系统证实该用户信用卡的信息是准确的,并且在帐户上有足够的资金,就不必等到所有的支付细节落实、转账完成。支付结算可以异步方式进行,这样客户可以继续进行核查操作。
需要比典型同步请求耗费更长时间的请求,可以使用异步处理。另一个异步处理的例子是,在本地贷款处理程序中,提交至自动承销系统(AUS)的信用请求处理过程。当借方提交贷款申请后,抵押公司会向AUS发送请求,以获取信用历史记录。由于这个请求要求得到全面而又详细的信用报告,包括借方现今和过去的帐户,最近的付款和其他财务资料,服务器需要耗费较长的时间(几小时或着有时甚至是几天)来对这些请求作出响应。客户端程序(应用)要与服务器连接并耗费如此长的时间来等待结果,这是毫无意义的。因此通信应该是异步发生的;也就是,一旦请求被提交,它就被放置在队列中,同时客户端与服务器断开连接。然后AUS服务从指定的队列中选出请求进行处理,并将处理得到的消息放置在另一个消息队列里。最后,客户端程序从这个队列中选出处理结果,紧接着处理这个信用历史数据。
JMS
如果您使用过JMS代码,您会发现它与JDBC或JCA很像。它所包含的样本代码创建或JMS资源对象回溯,使得每一次您需要写一个新类来发送和接收消息时,都具有更好的代码密集性和重复性。以下序列显示了传统JMS实现所包括的步骤:
创建JNDI初始上下文(context)。
从JNDI上下文获取一个队列连接工厂。
从队列连接工厂中获取一个Quene。
创建一个Session对象。
创建一个发送者(sender)或接收者(receiver)对象。
使用步骤5创建的发送者或接收者对象发送或接收消息。
处理完消息后,关闭所有JMS资源。
您可以看到,步骤6是处理消息的唯一地方。其他步骤都只是管理与实际业务要求无关的JMS资源,但是开发人员必须编写并维护这些额外步骤的代码。
Spring JMS
Spring框架提供了一个模板机制来隐藏Java APIs的细节。JEE开发人员可以使用JDBCTemplate和JNDITemplate类来分别访问后台数据库和JEE资源(数据源,连接池)。JMS也不例外。Spring提供JMSTemplate类,因此开发人员不用为一个JMS实现去编写样本代码。接下来是在开发JMS应用程序时Spring所具有一些的优势。
提供JMS抽象API,简化了访问目标(队列或主题)和向指定目标发布消息时JMS的使用。
JEE开发人员不需要关心JMS不同版本(例如JMS 1.0.2与JMS 1.1)之间的差异。
开发人员不必专门处理JMS异常,因为Spring为所有JMS异常提供了一个未经检查的异常,并在JMS代码中重新抛出。
示例程序
说明:因为只是为了演示如何使用spring编写jms的应用,所以本例没有什么实际用途。
程序功能:MessageProducer.java根据一用户信息产生一个消息发送到 JMS Provider;由MessageConsumer.java接收。
1.在Jboss里配置XML文件创建一个新的JMS provider。
打开位于%JBOSS_HOME%server\default\deploy\jms文件夹下的jbossmq-destinations-service.xml文件,加入以下代码片断:
<!-- Register User Send/Receive Queue --> <mbean code="org.jboss.mq.server.jmx.Queue" name="jboss.mq.destination:service=Queue,name=registerUserQueue"> <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends> </mbean> <!-- Register User Send/Receive Topic --> <mbean code="org.jboss.mq.server.jmx.Topic" name="jboss.mq.destination:service=Topic,name=registerUserTopic"> <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends> </mbean>
2.在spring的配置文件中配置JMS组件的具体细节。
(1)JNDI上下文是取得JMS资源的起始位置,因此首先我们要配置JNDI模板:
<!-- JNDI上下文(它是取得JMS资源的起始位置) --> <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>
注意:此JNDI模板用到了org.jnp.interfaces.NamingContextFactory所以要把%JBOSS_HOME%\client下的jbossall-client.jar加到你的项目的classpath中。
(2)配置连接工厂:
<!-- JMS连接工厂 --> <bean id="jmsConnectionFactory"class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiTemplate"> <ref bean="jndiTemplate" /> </property> <property name="jndiName"> <value>XAConnectionFactory</value> </property> </bean>
注意:XAConnectionFactory这个JNDI名字是在%JBOSS_HOME%server\default\deploy\jms文件夹下的jms-ds.xml中定义的(它是由JBoss指定的)。
(3)配置JmsTemplate组件。在例程中我们使用JmsTemplate102。同时使用defaultDestination属性来指定JMS目标。
<!-- JMS模板配置 --> <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate102"> <property name="connectionFactory" ref="jmsConnectionFactory" /> <property name="defaultDestination" ref="destination" /> <property name="pubSubDomain"> <value>true</value> </property> <!-- 等待消息的时间(ms) --> <property name="receiveTimeout"> <value>30000</value> </property> </bean>
注意:如果使用topic-subscribe(主题订阅)模式,该模板的pubSubDomain属性值为true;若使用PToP(点对点)模式,pubSubDomain属性值为false或不配置该属性。
(4)定义一个JMS目标来发送和接收消息:
<bean id="destination" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiTemplate"> <ref bean="jndiTemplate" /> </property> <property name="jndiName"> <value>topic/registerUserTopic</value> </property> </bean>
(5)配置发送者和接收者组件:
<!-- 消息发布者 --> <bean id="msgProducer" class="com.boco.jms.MessageProducer"> <property name="jmsTemplate" ref="jmsTemplate" /> </bean> <!-- 消息接收者 --> <bean id="msgConsumer" class="com.boco.jms.MessageConsumer"> <property name="jmsTemplate" ref="jmsTemplate" /> </bean>
3.相应的类:
(1). User对象。
/** * User.java * created on Jul 2, 2006 * Copyrights 2006 BOCO,Inc. All rights reserved. */ package com.boco.dto; import java.io.Serializable; /** * desc: 用户信息 Bean * @author qiujy */ public class User { private int id; private String username; private String password; private String email; public User(){} //以下为Getter,setter方法略 ...... }
(2).消息生产者:
/** * MessageProducer.java * created on Jul 22, 2006 * Copyrights 2006 BOCO,Inc. All rights reserved. */ package com.boco.jms; import javax.jms.JMSException; import javax.jms.MapMessage; import javax.jms.Message; import javax.jms.Session; import org.springframework.jms.core.JmsTemplate; import org.springframework.jms.core.MessageCreator; import com.boco.dto.User; /** * desc:消息生产者 * @author qiujy * */ public class MessageProducer { /** JMS模板 */ private JmsTemplate jmsTemplate; public void setJmsTemplate(JmsTemplate jmsTemplate){ this.jmsTemplate = jmsTemplate; } public void sendMessage(final User user){ //调用模板的send来发送消息 jmsTemplate.send(new MessageCreator(){ public Message createMessage(Session session) throws JMSException { //构造一个要发送的消息 MapMessage message = session.createMapMessage(); message.setInt("id", user.getId()); message.setString("username", user.getUsername()); message.setString("password", user.getPassword()); message.setString("email", user.getEmail()); System.out.println("send success!!"); return message; } }); } }
(3).消息消费者:
/** * MessageConsumer.java * created on Jul 22, 2006 * Copyrights 2006 BOCO,Inc. All rights reserved. */ package com.boco.jms; import javax.jms.JMSException; import javax.jms.MapMessage; import org.springframework.jms.core.JmsTemplate; import com.boco.dto.User; /** * desc:消息消费者 * @author qiujy * */ public class MessageConsumer { /** JMS模板 */ private JmsTemplate jmsTemplate; public void setJmsTemplate(JmsTemplate jmsTemplate){ this.jmsTemplate = jmsTemplate; } public User receiveMessage(){ //参数为Destination的JNDI名字去掉前面的模式类型标识 //MapMessage msg = (MapMessage)jmsTemplate.receive("registerUserQueue"); MapMessage msg = (MapMessage)jmsTemplate.receive("registerUserTopic"); User user = new User(); try { user.setId(msg.getInt("id")); user.setUsername(msg.getString("username")); user.setPassword(msg.getString("password")); user.setEmail(msg.getString("email")); } catch (JMSException e) { // TODO Auto-generated catch block e.printStackTrace(); } return user; } }
(4).测试用例:
//======== 生产者测试用例 =============== /** * TestMsgProducer.java * created on Jul 22, 2006 * Copyrights 2006 BOCO,Inc. All rights reserved. */ package com.boco.jms; import junit.framework.TestCase; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.boco.dto.User; /** * desc: * @author qiujy * */ public class TestMsgProducer extends TestCase { private ApplicationContext context; /** * @param arg0 */ public TestMsgProducer(String arg0) { super(arg0); context = new ClassPathXmlApplicationContext("applicationContext_jms.xml"); } /* (non-Javadoc) * @see junit.framework.TestCase#setUp() */ protected void setUp() throws Exception { super.setUp(); } /* (non-Javadoc) * @see junit.framework.TestCase#tearDown() */ protected void tearDown() throws Exception { super.tearDown(); } /** * Test method for {@link com.boco.jms.MessageProducer#sendMessage(com.boco.dto.User)}. */ public void testSendMessage() { User user = new User(); user.setId(132); user.setUsername("JMSTest"); user.setPassword("password"); user.setEmail("support@boco.com.cn"); MessageProducer producer = (MessageProducer)context.getBean("msgProducer"); producer.sendMessage(user); } }
//============ 消费者测试用例 =============== /** * TestMsgConsumer.java * created on Jul 22, 2006 * Copyrights 2006 BOCO,Inc. All rights reserved. */ package com.boco.jms; import junit.framework.TestCase; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.boco.dto.User; /** * desc: * @author qiujy * */ public class TestMsgConsumer extends TestCase { private ApplicationContext context; /** * @param arg0 */ public TestMsgConsumer(String arg0) { super(arg0); context = new ClassPathXmlApplicationContext("applicationContext_jms.xml"); } /* (non-Javadoc) * @see junit.framework.TestCase#setUp() */ protected void setUp() throws Exception { super.setUp(); } /* (non-Javadoc) * @see junit.framework.TestCase#tearDown() */ protected void tearDown() throws Exception { super.tearDown(); } /** * Test method for {@link com.boco.jms.MessageConsumer#receiveMessage()}. */ public void testReceiveMessage() { MessageConsumer consumer = (MessageConsumer)context.getBean("msgConsumer"); User user = consumer.receiveMessage(); assertNotNull(user); System.out.println( "id========" + user.getId() + "\nname======" + user.getUsername() + "\npassword==" + user.getPassword() + "\nemail=====" + user.getEmail()); } }
相关推荐
SpringJMS是Spring框架的一部分,它提供了一种与Java消息服务(JMS)进行交互的简单方式。在本文中,我们将深入探讨SpringJMS的基本概念、如何与ActiveMQ集成,以及如何通过示例代码理解其工作原理。 1. **Spring...
详细内容: SpringJMS整合ActiveMQ.doc 详细说明文档 apache-activemq-5.8.0-bin.zip ActiveMQ安装包 JMSTest.rar MyEclipse8.5下web工程
Spring JMS Spring JMS 是一个基于 Java 消息服务(JMS)的框架,它提供了一个简洁的方式来使用 JMS API。Spring JMS 框架提供了一个抽象层,简化了 JMS 的使用,使得开发者可以更容易地使用 JMS。 Spring JMS 的...
【Spring JMS】是Spring框架中的一个模块,用于简化Java消息服务(JMS)的使用,使得异步消息处理变得更加简单和灵活。Spring JMS通过提供一个模板类,抽象了JMS API的底层细节,让开发者能够更加专注于消息的处理...
Spring对JMS提供了很好的支持,可以通过JmsTemplate来方便地实现消息服务。本例通过activeMQ服务器模拟了消息的发送与接收。需要注意的是,activeMQ的运行依赖jdk的环境,而且对jdk的版本也有要求,我用的是jdk1.6+...
Spring JMS(Java Message Service)是Spring框架的一部分,专门用于集成JMS消息传递系统,以实现异步通信和解耦应用程序组件。在这个入门级实例中,我们将探讨如何使用Maven、Spring和ActiveMQ来构建一个简单的...
这篇博客“Spring JMS 消息处理-基于JNDI”将深入探讨如何在Spring应用中使用JMS进行消息处理,并利用JNDI(Java Naming and Directory Interface)来查找和配置消息资源。 JMS是Java平台上的一个标准接口,它定义...
在Java中,Spring框架提供了强大而灵活的支持,使得开发人员能够轻松地实现基于Java消息服务(JMS)的网络编程。JMS是一个标准接口,它允许应用程序创建、发送、接收和读取消息,这些消息可以在不同的应用之间传递,...
本人开发的spring jms项目,已经上线近一年了,这里是我项目jms配置文件,使用的是spring jms 整合weblogic jms。如果真的需要,请咨询我,并且附上我上传的这个配置文件,附近中没有带有这个文件,一律不作任何回答...
在本文中,我们将深入探讨Spring框架中的Java消息服务(JMS)支持,特别是不依赖于JNDI(Java Naming and Directory Interface)的方式。Spring JMS为应用程序提供了与消息中间件交互的能力,允许我们构建可扩展且...
【Spring JMS 知识点详解】 Spring JMS 是 Spring 框架的一部分,它提供了一种简单且灵活的方式来处理 Java 消息服务 (JMS)。在面向服务架构 (SOA) 中,异步消息传递是关键组件,特别是在企业级系统间通信,特别是...
在IT行业中,Spring框架是Java应用开发的基石,它提供了丰富的功能来简化应用程序的构建,而JMS(Java Message Service)则是处理异步通信的一种标准API。Tomcat作为轻量级的应用服务器,常用于部署Spring应用。在这...
**JMS整合Spring实例** Java消息服务(Java Message Service,简称JMS)是Java平台中用于企业级应用间异步通信的一种标准接口。它允许应用程序创建、发送、接收和读取消息,以此来解耦生产者和消费者。而Spring框架...
本项目"jms整合spring工程"是一个已经准备就绪的Java工程,它展示了如何在Spring框架中集成JMS,以便利用消息队列进行通信。主要依赖的是Apache ActiveMQ,这是一款流行的开源JMS提供者,能够实现高效、可靠的实时...
**Spring JMS源码分析** 在Java世界里,消息队列(JMS,Java Message Service)是一种标准,它定义了一种规范,使得不同的消息中间件提供商可以为开发者提供一致性的API,以实现在应用程序间传递消息。Spring JMS是...
在实际应用中,`SpringJMS`可能包含以下示例代码片段: ```xml <bean id="jmsConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory"> <!-- 这里配置具体的JMS提供商实现 -->...