分类: Java
2010-11-21 12:21:36
则简化了使用JEE组件(包括JMS)的任务。它提供的模板机制隐藏了典型的JMS实现的细节,这样开发人员可以集中精力放在处理消息的实际工作中,而不用担心如何去创建,访问或清除JMS资源。
本文将对Spring JMS API作一个概述,并通过一个运行在JBoss MQ服务器上的web例程来介绍如何使用Spring JMS API来异步处理(发送和接收)消息。我将通过传统JMS实现和Spring JMS实现两者间的比较,来展示使用Spring JMS处理消息是如何的简单和灵活。
在现实中,大多数web请求都是同步处理的。例如,当用户要登入一个网站,首先输入用户名和密码,然后服务器验证登录合法性。如果验证成功,程 序将允许该用户进入网站。这里,登录请求在从客户端接收以后被即时处理了。信用卡验证是另一个同步处理的例子;只有服务器证实输入的信用卡号是有效的,同 时客户在帐户上有足够的存款,客户才被允许继续操作。但是让我们思考一下在顺序处理系统上的支付结算步骤。一旦系统证实该用户信用卡的信息是准确的,并且 在帐户上有足够的资金,就不必等到所有的支付细节落实、转账完成。支付结算可以异步方式进行,这样客户可以继续进行核查操作。
需要比典型同步请求耗费更长时间的请求,可以使用异步处理。另一个异步处理的例子是,在本地贷款处理程序中,提交至自动承销系统(AUS)的信用请求处理 过程。当借方提交贷款申请后,抵押公司会向AUS发送请求,以获取信用历史记录。由于这个请求要求得到全面而又详细的信用报告,包括借方现今和过去的帐 户,最近的付款和其他财务资料,服务器需要耗费较长的时间(几小时或着有时甚至是几天)来对这些请求作出响应。客户端程序(应用)要与服务器连接并耗费如 此长的时间来等待结果,这是毫无意义的。因此通信应该是异步发生的;也就是,一旦请求被提交,它就被放置在队列中,同时客户端与服务器断开连接。然后 AUS服务从指定的队列中选出请求进行处理,并将处理得到的消息放置在另一个消息队列里。最后,客户端程序从这个队列中选出处理结果,紧接着处理这个信用 历史数据。
如果您使用过JMS代码,您会发现它与JDBC或JCA很像。它所包含的样本代码创建或JMS资源对象回溯,使得每一次您需要写一个新类来发送和接收消息时,都具有更好的代码密集性和重复性。以下序列显示了传统JMS实现所包括的步骤:
您可以看到,步骤6是处理消息的唯一地方。其他步骤都只是管理与实际业务要求无关的JMS资源,但是开发人员必须编写并维护这些额外步骤的代码。
Spring框架提供了一个模板机制来隐藏Java APIs的细节。JEE开发人员可以使用JDBCTemplate和JNDITemplate类来分别访问后台数据库和JEE资源(数据源,连接池)。 JMS也不例外。Spring提供JMSTemplate类,因此开发人员不用为一个JMS实现去编写样本代码。接下来是在开发JMS应用程序时 Spring所具有一些的优势。
说明:因为只是为了演示如何使用spring编写jms的应用,所以本例没有什么实际用途。
程序功能:MessageProducer.java根据一用户信息产生一个消息发送到 JMS Provider;由MessageConsumer.java接收。
1.在Jboss里配置XML文件创建一个新的JMS provider。
打开位于%JBOSS_HOME%server\default\deploy\jms文件夹下的jbossmq-destinations-service.xml文件,加入以下代码片断:
2.在spring的配置文件中配置JMS组件的具体细节。
(1)JNDI上下文是取得JMS资源的起始位置,因此首先我们要配置JNDI模板:
org.jnp.interfaces.NamingContextFactory
org.jnp.interfaces:org.jboss.naming
注意:此JNDI模板用到了org.jnp.interfaces.NamingContextFactory所以要把%JBOSS_HOME%\client下的jbossall-client.jar加到你的项目的classpath中。
(2)配置连接工厂:
注意:XAConnectionFactory这个JNDI名字是在%JBOSS_HOME%server\default\deploy\jms文件夹下的jms-ds.xml中定义的(它是由JBoss指定的)。
(3)配置JmsTemplate组件。在例程中我们使用JmsTemplate102。同时使用defaultDestination属性来指定JMS目标。
注意:如果使用topic-subscribe(主题订阅)模式,该模板的pubSubDomain属性值为true;若使用PToP(点对点)模式,pubSubDomain属性值为false或不配置该属性。
(4)定义一个JMS目标来发送和接收消息:
(5)配置发送者和接收者组件:
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 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("");
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 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());
}
}