JMS的简单应用:
点对点模型(Point-to-Point)
点对点消息传送模型允许JMS客户端通过队列(queue)这个虚拟通道来同步和异步发送、接收消息。在点对点模型中,消息生产者称为发送者(Sender),而消息消费者则称为接收者(receiver)。传统上,点对点模型是一个基于拉取(Pull)或基于轮询(polling)的消息传送模型,这种模型从队列中请求消息,而不是自动地将消息推送到客户端。点对点消息传送模型的一个突出特点就是:发送到队列的消息被一个而且仅仅一个接收者所接收,即使可能有多个接收者在一个队列中侦听同一消息时,也是如此。
点对点消息传送模型既支持异步“即发即弃(fire and forget)”消息传送方式,又支持同步请求/应答消息传送方式。点对点消息传送模型比发布/订阅模型具有更强的耦合性,发送者通常会知道消息将被如何使用,而且也会知道谁将接收该消息。举例来说,发送者可能会向一个队列发送一个证券交易订单并等待响应,响应中应包含一个交易确认码。这样一来,消息发送者就会知道消息接收者将要处理交易订单。另一个例子就是一个生成长时间运行报告的异步请求。发送者发出报告请求,而当该报告准备就绪时,就会给发送者发送一条通知消息。在这种情况下,发送者就会知道消息接收者将要处理该消息并创建报告。
点对点模型支持负载均衡,它允许多个接收者侦听同一队列,并以此来分配负载。如图1-4所示,JMS提供者负责管理队列,确保每条消息被组内下一个可用的接收者消费一次,而且仅仅一次。JMS规范没有规定在多个接收者中间分发消息的规则,尽管某些JMS厂商已经选择实现此规则来提升负载均衡能力。点对点模型还具有其他优点,比如说,队列浏览器允许客户端在消费其消息之前查看队列内容——在发布/订阅模型中,并没有这种浏览器的概念。
在JBoss下面JMS的简单开发点对点的JMS应用:
部署关于JMS的配置过程如下:
备注:
JMS配置文件必须在JBoss的在%JBoss_HOME%\server\default\deploy中,同时文件的命名必须以xxx-service.xml中。
jboss-jms-service.xml配置信息如下:
<?xml version="1.0" encoding="UTF-8"?> <!-- $Id: mail-service.xml 62350 2007-04-15 16:50:12Z [email protected] $ --> <server> <!-- ==================================================================== --> <!-- Mail Connection Factory --> <!-- ==================================================================== --> <mbean code="org.jboss.mq.server.jmx.Queue" name="jboss.mq.destination:service=Queue,name=longgangbai"> <attribute name="JNDIName">queue/longgangbai</attribute> <depends optional-attribute-name="DestinationManager" >jboss.mq:service=DestinationManager</depends> </mbean> </server>
在客户端:
备注下面为:JMS1.1 TopicConnectionFactory 和QueueConnectionFactory合并为ConnectionFactory
package com.easyway.jboss.jms.ptp.service; import java.util.Properties; import javax.jms.BytesMessage; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MapMessage; import javax.jms.MessageProducer; import javax.jms.Queue; import javax.jms.QueueConnection; import javax.jms.QueueConnectionFactory; import javax.jms.QueueSession; import javax.jms.StreamMessage; import javax.jms.TextMessage; import javax.naming.Context; import javax.naming.InitialContext; /** * 队列消息的发送者 * 采用JMS点对点,一对一的(PTP消息传递模型) * @author longgangbai * */ public class QueueSender { /** * * @param args */ public static void main(String[] args) { QueueConnection conn=null; QueueSession session=null; try { //得到一个JNDI初始化上下文 Properties props=new Properties(); //设置 props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); props.setProperty(Context.PROVIDER_URL, "localhost:1099"); props.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); InitialContext ctx=new InitialContext(props); //根据上下文查找一个连接工厂TopicConnectionFactory/QueueConnectionFactory (有了两种连接工厂, //根绝topic、queue来是哟偶那个相应的类型),该连接工厂是有JMS提供的,不需要我们自己创建,每一个 //厂商为他绑定一个全局的JNDI,我们功过JNDI便可获取它。 QueueConnectionFactory factory=(QueueConnectionFactory)ctx.lookup("ConnectionFactory"); //从连接工厂 中得到一个连接(Connect 的类型有两种,TopicConnection、QueueConnection) conn=factory.createQueueConnection(); //通过连接来建立一个会话(Session) //建立一个不需要事物的并且能自动确认消息已接收的会话 session=conn.createQueueSession(false,QueueSession.AUTO_ACKNOWLEDGE); //查找目的地(目的地的类型有两种:Topic、Queue) Destination destination =(Queue)ctx.lookup("queue/longgangbai"); //根绝会话以及目的地建立消息生产者MessageProducter(QueueSender 和TopicPublisher都扩展自MessageProducer接口) MessageProducer producer=session.createProducer(destination); TextMessage msg=session.createTextMessage("hi ,longgangbai ,this is jboss jms MDB message"); //发送文本消息 producer.send(msg); //发送对象消息 producer.send(session.createObjectMessage(new SMS("wangnabaobao","this is my girl friend"))); MapMessage mapmsg=session.createMapMessage(); mapmsg.setObject("name", "baobao"); producer.send(mapmsg); BytesMessage bmsg=session.createBytesMessage(); bmsg.writeBytes("I am a good boy !".getBytes()); producer.send(bmsg); StreamMessage smsg=session.createStreamMessage(); smsg.writeString("阿里巴巴,http://www.alibaba.com"); producer.send(smsg); } catch (Exception e) { e.printStackTrace(); }finally{ try { session.close(); conn.close(); } catch (JMSException e2) { e2.printStackTrace(); } } } }
运行JBoss在:
在jboss.mq.destination中的选择相关的消息服务信息:
选择listMesages:
查询
接受消息的代码如下:
package com.easyway.jboss.jms.ptp.service; import java.io.ByteArrayOutputStream; import javax.ejb.ActivationConfigProperty; import javax.ejb.MessageDriven; import javax.jms.BytesMessage; import javax.jms.MapMessage; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.ObjectMessage; import javax.jms.StreamMessage; import javax.jms.TextMessage; /** * Queue消息的接受方的MDB * @author longgangbai * * * 在JBoss 的%JAVA_HOME%\server\default\deploy目录下添加相关配置 * @author longgangbai */ @MessageDriven(activationConfig={ @ActivationConfigProperty(propertyName = "destinationType", //消息的目标的类型: 取值可以为javax.jms.Queue或者javax.jms.Topic propertyValue = "javax.jms.Queue"), @ActivationConfigProperty(propertyName = "destination", //消息的目标的地址,取值是目标地址的JDNI名称: propertyValue = "queue/longgangbai"), @ActivationConfigProperty(propertyName = "acknowledgeMode", //消息的确认模式,却只可以为:Auto-acknowledge或者Dups_ok_acknowledge //消息确认:是指JMS客户端通知JMS provider确认消息已经到达的一种机制,在EJB中,收到消息后发送确认是EJB容器的职责, //确认消息就是JMS Provider ,EJB容器已经收到并处理了消息,如没有确认,JMS provider 就不知道容器是否收到了,消息,进而重发消息 propertyValue = "Auto-acknowledgeMode") }) public class DisplayMessage implements MessageListener{ @Override public void onMessage(Message msg) { try { if(msg instanceof TextMessage){ TextMessage tmsg=(TextMessage)msg; String content=tmsg.getText(); System.out.println(content); }else if(msg instanceof ObjectMessage){ ObjectMessage tmsg=(ObjectMessage)msg; SMS sms=(SMS)tmsg.getObject(); String content=sms.getUsername()+":"+sms.getMessage(); System.out.println(content); }else if(msg instanceof MapMessage){ MapMessage mmsg=(MapMessage)msg; String content=mmsg.getString("name"); System.out.println(content); }else if(msg instanceof BytesMessage){ BytesMessage bytesmsg=(BytesMessage)msg; ByteArrayOutputStream byteStream=new ByteArrayOutputStream(); byte[] buffer=new byte[256]; int length=0; while((length=bytesmsg.readBytes(buffer))!=-1){ byteStream.write(buffer,0,length); } String context=new String(byteStream.toByteArray()); System.out.println(context); }else if(msg instanceof ObjectMessage){ ObjectMessage tmsg=(ObjectMessage)msg; SMS sms=(SMS)tmsg.getObject(); String content=sms.getUsername()+":"+sms.getMessage(); System.out.println(content); }else if(msg instanceof StreamMessage){ StreamMessage tmsg=(StreamMessage)msg; String content=tmsg.readString(); System.out.println(content); } } catch (Exception e) { e.printStackTrace(); } } }
package com.easyway.jboss.jms.ptp.service; import java.util.Properties; import javax.jms.Destination; import javax.jms.JMSException; import javax.jms.MessageConsumer; import javax.jms.Queue; import javax.jms.QueueConnection; import javax.jms.QueueConnectionFactory; import javax.jms.QueueSession; import javax.jms.TopicSession; import javax.naming.Context; import javax.naming.InitialContext; /** * 队列消息的接受者 * 采用JMS点对点的模式 * @author longgangbai * */ public class QueueReceive { /** * * @param args */ public static void main(String[] args) { QueueConnection conn=null; QueueSession session=null; try { //得到一个JNDI初始化上下文 Properties props=new Properties(); //设置 props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory"); props.setProperty(Context.PROVIDER_URL, "localhost:1099"); props.setProperty(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); InitialContext ctx=new InitialContext(props); //根据上下文查找一个连接工厂TopicConnectionFactory/QueueConnectionFactory (有了两种连接工厂, //根绝topic、queue来是哟偶那个相应的类型),该连接工厂是有JMS提供的,不需要我们自己创建,每一个 //厂商为他绑定一个全局的JNDI,我们功过JNDI便可获取它。 QueueConnectionFactory factory=(QueueConnectionFactory)ctx.lookup("ConnectionFactory"); //从连接工厂 中得到一个连接(Connect 的类型有两种,TopicConnection、QueueConnection) conn=factory.createQueueConnection(); //通过连接来建立一个会话(Session) //建立一个不需要事物的并且能自动确认消息已接收的会话 session=conn.createQueueSession(false,TopicSession.AUTO_ACKNOWLEDGE); //查找目的地(目的地的类型有两种:Topic、Queue) Destination destination =(Queue)ctx.lookup("queue/longgangbai"); //根绝会话以及目的地建立消息生产者MessageProducter(QueueSender 和TopicPublisher都扩展自MessageProducer接口) MessageConsumer consumer=session.createConsumer(destination); DisplayMessage ml = new DisplayMessage(); consumer.setMessageListener(ml); System.out.println("开始处理休息.."); conn.start(); System.out.println("消息处理完毕..."); } catch (Exception e) { e.printStackTrace(); }finally{ try { session.close(); conn.close(); } catch (JMSException e2) { e2.printStackTrace(); } } } }