SPRING整合JMS进行网络通信

来源:互联网 发布:linux 登录root 编辑:程序博客网 时间:2024/06/05 16:53

什么是JMS?

jms即Java消息服务(Java Message Service)应用程序接口是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。Java消息服务是一个与具体平台无关的API,绝大多数MOM提供商都对JMS提供支持。

JMS的优势

当前,CORBA、DCOM、RMI等RPC中间件技术已广泛应用于各个领域。但是面对规模和复杂度都越来越高的分布式系统,这些技术也显示出其局限性:

(1)同步通信:客户发出调用后,必须等待服务对象完成处理并返回结果后才能继续执行;

(2)客户和服务对象的生命周期紧密耦合:客户进程和服务对象进程 都必须正常运行;如果由于服务对象崩溃或者网络故障导致客户的请求不可达,客户会接收到异常;

(3)点对点通信:客户的一次调用只发送给某个单独的目标对 象。
面向消息的中间件(Message Oriented Middleware,MOM)较好的解决了以上问题。发送者将消息发送给消息服务器,消息服务器将消息存放在若干队列中,在合适的时候再将消息转发给接 收者。这种模式下,发送和接收是异步的,发送者无需等待;二者的生命周期未必相同:发送消息的时候接收者不一定运行,接收消息的时候发送者也不一定运行; 一对多通信:对于一个消息可以有多个接收者。
已有的MOM系统包括IBM的MQSeries、Microsoft的MSMQ和BEA的MessageQ等。由于没有一个通用的标准,这些系统很难实现 互操作和无缝连接。

Java Message Service(JMS)是SUN提出的旨在统一各种MOM系统接口的规范,它包含点对点(Point to Point,PTP)和发布/订阅(Publish/Subscribe,pub/sub)两种消息模型,提供可靠消息传输、事务和消息过滤等机制。JMS并不是一个产品而是一个规范,JMS的出现是一个巨大变革。

满足大量应用的需求,运行于多种硬件和操作系统平台,支持分布式计算,支持标准接口和协议。开发人员通过调用中间件提供的大量API,实现异构环境的通信,从而屏蔽异构系统中复杂的操作系统和网络协议。

由于标准接口对于可移植性和标准协议对于互操作性的重要性,中间件已成为许多标准化工作的主要部分。分布式应用软件借助中间件可以在不同的技术之间共享资源。

总的来说,中间件屏蔽了底层操作系统的复杂性,使程序开发人员面对一个简单而统一的开发环境,减少了程序设计的复杂性,将注意力集中与自己的业务上,不必再为程序在不同软件系统上的移植而重复工作,从而大大减少了技术上的负担。

Take in Action

在理解了什么是JMS后,在实践阶段Dreamforce会向你介绍在Spring中整合JMS,同时结合Apache ActiveMQ来实现一个模拟聊天器的功能。

来务场景: A在输入端输入相应消息,消息会异步发送到ActiveMQ,B端会监听这个队列,如果有新数据入队,则接收此消息。

根据本实例,你可以通过简单的修改实现双人或多人自由聊天功能。

在本例中,使用Apache 的ActiveMQ来作为JMS中间件,这是一款相当成熟且开源的产品,得到了许多业内人士的好评。

开发采用Spirng Maven集成开发环境,所有的Jar包通过Maven进行管理 , 如果对Spring Maven集成开发环境配置不熟悉的,可以先看这里:http://dreamforce.me/archives/87

新建一个ApplicationContext-JMS.xml

定义JMS连接工厂

Java代码 复制代码 收藏代码
  1. <bean id="jmsFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
  2. <property name="brokerURL" value="tcp://localhost:61616" /> </bean>

定义JMS Template

Java代码 复制代码 收藏代码
  1. <bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
  2. <property name="connectionFactory" ref="jmsFactory" /> </bean>
定义消息目的地
Java代码 复制代码 收藏代码
  1. <bean id="dreamDestination"class="org.apache.activemq.command.ActiveMQQueue"> <constructor-arg index="0" value="dream.force" /> </bean>
定义接收监听器
Java代码 复制代码 收藏代码
  1. <bean id="myTextListener"class="com.darcy.jms.TextListener">
  2. </bean>

定义一个JMS话题
Java代码 复制代码 收藏代码
  1. <bean id="jmsTopic" class="org.apache.activemq.command.ActiveMQTopic"
  2. autowire="constructor">
  3. <constructor-arg value="STOCKS.Dreamforce.jms" />
  4. </bean>

定义消费者(接收端)
Java代码 复制代码 收藏代码
  1. <bean id="javaConsumer"
  2. class="org.springframework.jms.listener.DefaultMessageListenerContainer">
  3. <property name="connectionFactory" ref="jmsFactory" />
  4. <property name="destination" ref="chartDestination" />
  5. <property name="messageListener" ref="myTextListener" />
  6. </bean>

定义发布者
Java代码 复制代码 收藏代码
  1. <bean id="publisher" class="com.darcy.jms.SpringPublish">
  2. <property name="template">
  3. <ref local="jmsTemplate" />
  4. </property>
  5. <property name="destinations" ref="chartDestination" />
  6. </bean>

JAVA核心代码一般由三个部分组成: 监听器(Listener),发布端(Publisher), 消息生产者(Creator)

监听器

Java代码 复制代码 收藏代码
  1. package com.darcy.jms;
  2. import java.util.Date;
  3. import javax.jms.JMSException;
  4. import javax.jms.Message;
  5. import javax.jms.MessageListener;
  6. import javax.jms.TextMessage;
  7. import org.apache.activemq.command.ActiveMQMapMessage;
  8. public class TextListenerimplements MessageListener{
  9. public void onMessage(Message message) {
  10. ActiveMQMapMessage msg = null;
  11. System.out.println("ONMessage-----------------"+message.toString());
  12. try {
  13. if (message instanceof ActiveMQMapMessage) {
  14. msg = (ActiveMQMapMessage) message;
  15. String sentDate = msg.getString("date");
  16. String reMessage = msg.getString("message");
  17. int sentCount = msg.getInt("count");
  18. System.out.println("-------------New Message Arrival-----------"+new Date());
  19. System.out.println("It's "+sentCount+" time From Darcy: "+reMessage+" ---Send time :" + sentDate);
  20. }
  21. } catch (JMSException e) {
  22. System.out.println("JMSException in onMessage(): " + e.toString());
  23. } catch (Throwable t) {
  24. System.out.println("Exception in onMessage():" + t.getMessage());
  25. }
  26. }
  27. }

发布端

Java代码 复制代码 收藏代码
  1. package com.darcy.jms;
  2. import java.util.HashMap;
  3. import java.util.Scanner;
  4. import javax.jms.Destination;
  5. import org.springframework.jms.core.JmsTemplate;
  6. public class SpringPublish {
  7. private JmsTemplate template;
  8. private Destination[] destinations;
  9. public void chart(){
  10. boolean chart = true;
  11. int count = 0;
  12. while(chart){
  13. count ++;
  14. Scanner cin=new Scanner(System.in);
  15. System.out.println("输入聊天内容,输入N停止聊天");
  16. String text=cin.nextLine();
  17. if(text.equals("N")) {
  18. chart = false;
  19. }
  20. System.out.println("我:"+text);
  21. sendChartMessage(count,text);
  22. }
  23. }
  24. protected void sendChartMessage(int count , String strMessage) {
  25. MyMessageCreator creator = new MyMessageCreator(count,strMessage);
  26. template.send(destinations[0], creator);
  27. }
  28. public JmsTemplate getTemplate() {
  29. return template;
  30. }
  31. public void setTemplate(JmsTemplate template) {
  32. this.template = template;
  33. }
  34. public Destination[] getDestinations() {
  35. return destinations;
  36. }
  37. public void setDestinations(Destination[] destinations) {
  38. this.destinations = destinations;
  39. }
  40. }

消息生产者

Java代码 复制代码 收藏代码
  1. package com.darcy.jms; import java.util.Date;
  2. import javax.jms.JMSException;
  3. import javax.jms.MapMessage;
  4. import javax.jms.Message;
  5. import javax.jms.Session;
  6. import org.springframework.jms.core.MessageCreator;
  7. public class MyMessageCreatorimplements MessageCreator {
  8. private int msgNo;
  9. private String strMessage;
  10. public MyMessageCreator(int no,String paramMessage) {
  11. this.msgNo = no;
  12. this.strMessage = paramMessage;
  13. }
  14. public Message createMessage(Session session)throws JMSException {
  15. MapMessage message = session.createMapMessage();
  16. message.setString("date", new Date().toString());
  17. message.setString("message", strMessage);
  18. message.setInt("count", msgNo);
  19. return message;
  20. }
  21. }

完成上述的代码,聊天器的功能已经实现了,现在开始写一个TestCase来运行以上的代码

本例的TestCase用例是基于Spring的集成测试环境,同时你要保证将applicationContext-jms.xml纳入Spring的管理。

如果还不清楚如何搭建Spring集成测试环境的童鞋,请移步到这里 搭建Spring集成测试环境

Java代码 复制代码 收藏代码
  1. package test.JSM;
  2. import com.darcy.common.BaseTestCase;
  3. import com.darcy.jms.SpringPublish;
  4. import org.springframework.jms.listener.DefaultMessageListenerContainer;
  5. public class SpringJmsTestMainextends BaseTestCase {
  6. private SpringPublish publisher;
  7. private DefaultMessageListenerContainer javaConsumer;
  8. public SpringPublish getPublisher(){
  9. return publisher;
  10. }
  11. public void setPublisher(SpringPublish publisher){
  12. this.publisher = publisher;
  13. }
  14. public void testJMS(){
  15. javaConsumer.start();
  16. publisher.chart();
  17. }
  18. public void setJavaConsumer(DefaultMessageListenerContainer javaConsumer) {
  19. this.javaConsumer = javaConsumer;
  20. }
  21. public DefaultMessageListenerContainer getJavaConsumer() {
  22. return javaConsumer;
  23. }
  24. }
至此代码书写已经完成。但是在运行之前我们需要启动Apache ActionMQ,以使JAVA端能访问到JMS组件。

下载地址:http://activemq.apache.org/download.html

解压后,进入Conf目录,打开ActiveMQ.xml编辑

Java代码 复制代码 收藏代码
  1. <transportConnectors>
  2. <transportConnector name="openwire" uri="tcp://localhost:61616"/>
  3. </transportConnectors>
上面的代码是JMS通信地址,这里需要和Spring配置地址一致

启动ActionMQ, 运行bin目录里的ActionMQ.bat.

同时你也可以进入WEB Console, 默认访问地址为:http://localhost:8161/admin/

activeMQ console

运行TestCase,开始聊天吧~~~嘿嘿,不可上面的代码只支持单人聊天模式,接受端只是从JMS获取消息并输出。

附录:

Maven相关Denpendency(JMS

Java代码 复制代码 收藏代码
  1. <dependency>
  2. <groupId>org.springframework</groupId>
  3. <artifactId>spring-jms</artifactId>
  4. <version>3.1.1.RELEASE</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.apache.geronimo.specs</groupId>
  8. <artifactId>geronimo-jms_1.1_spec</artifactId>
  9. <version>1.1</version>
  10. </dependency>

由于各种原因,javax.jms包不能从maven默认的repository上下载,所以请使用这个dependency,当然jboss也提供了这个jms包的下载,请自由选择。
原创粉丝点击