Java 消息服务(Java Message Service,简称 JMS)是用于访问企业消息系统的开发商中立的API。企业消息系统可以协助应用软件通过网络进行消息交互。

 

       JMS的编程过程很简单,概括为:应用程序A发送一条消息到消息服务器的某个目得地(Destination),然后消息服务器把消息转发给应用程序B。因为应用程序A和应用程序B没有直接的代码关连,所以两者实现了解偶

 

           消息传递系统的中心就是消息。一条 Message 由三个部分组成:
                头(header),属性(property)和主体(body)。

                消息有下面几种类型,他们都是派生自 Message 接口。
          StreamMessage:一种主体中包含 Java 基元值流的消息。其填充和读取均按顺序进行。
          MapMessage:一种主体中包含一组名-值对的消息。没有定义条目顺序。
          TextMessage:一种主体中包含 Java 字符串的消息(例如,XML 消息)。
          ObjectMessage:一种主体中包含序列化 Java 对象的消息。
          BytesMessage:一种主体中包含连续字节流的消息。

 

 

JMS 支持两种消息传递模型:点对点(point-to-point,简称 PTP)和发布/订阅(publish/subscribe,简 称 pub/sub)。这两种消息传递模型非常相似,但有以下区别:

  PTP 消息传递模型规定了一条消息只能传递给一个接收方。 采用javax.jms.Queue 表示。
  Pub/sub 消息传递模型允许一条消息传递给多个接收方。采用javax.jms.Topic表示

  这两种模型都通过扩展公用基类来实现。例如:javax.jms.Queue 和javax.jms.Topic 都扩展自   javax.jms.Destination 类。

 

 

首先,开始JMS编程前,我们需要先配置消息到达的目标地址(Destination),因为只有目标地址存在了,我们才能发送消息到这个地址。由于每个应用服务器关于目标地址的配置方式都有所不同,下面以jboss为例,配置一个queue类型的目标地址。

<?xml version="1.0" encoding="UTF-8"?>
<server>  
  <mbean code="org.jboss.mq.server.jmx.Queue"
         name="jboss.mq.destination:service=Queue,name=foshanshop">
    <attribute name="JNDIName">queue/foshanshop</attribute>   
    <depends optional-attribute-name="DestinationManager">jboss.mq:service=DestinationManager</depends>
  </mbean>
</server>
Jboss使用一个XML文件配置队列地址,文件的取名格式应遵守*-service.xml
<attribute name="JNDIName">属性指定了该目标地址的全局JNDI名称。如果你不指定JNDIName属性,jboss会为你生成一个默认的全局JNDI,其名称由“queue”+“/”+目标地址名称组成。另外在任何队列或主题被部署之前,应用服务器必须先部署Destination Manager Mbean,所以我们通过<depends>节点声明这一依赖。并将其部署到jboss下。 
一般发送消息有以下步骤:
 
try {
   Properties props = new Properties();
  props.setProperty("java.naming.factory.initial","org.jnp.interfaces.NamingContextFactory");
  props.setProperty("java.naming.provider.url", "127.0.0.1:1099");

(1) 得到一个JNDI初始化上下文(Context)
   InitialContext ctx = new InitialContext(props);

(2) 根据上下文查找一个连接工厂 QueueConnectionFactory 。该连接工厂是由JMS提供的,不需我们自己创建,每个厂商都为它绑定了一个全局JNDI,我们通过它的全局JNDI便可获取它;
   QueueConnectionFactory factory = (QueueConnectionFactory) ctx.lookup

("QueueConnectionFactory");

(3) 从连接工厂得到一个连接 QueueConnection
   QueueConnection conn = factory.createQueueConnection();

(4) 通过连接来建立一个会话(Session);
   QueueSession session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);

 这句代码意思是:建立不需要事务的并且能自动确认消息已接收的会话。
(5) 查找目标地址:
   Destination destination = (Destination) ctx.lookup("queue/itcastQueue");

(6) 根据会话以及目标地址来建立消息生产者MessageProducer (QueueSender和TopicPublisher都扩展自MessageProducer接口)
 

MessageProducer producer = session.createProducer(destination);
   producer.send(session.createTextMessage("我的第一个JMS Queue消息"));
   session.close();
   conn.close();
   System.out.println("发送完了");
  } catch (NamingException e) {
   e.printStackTrace();
  } catch (JMSException e) {
   e.printStackTrace();
  }
 }

    这里用ejb的消息驱动bean来作为消息的接受端

 

消息驱动Bean(MDB)是设计用来专门处理基于消息请求的组件。它和无状态Session Bean一样也使用了实例池技术,容器可以使用一定数量的bean实例并发处理成百上千个JMS消息。正因为MDB具有处理大量并发消息的能力,所以非常适合应用在一些消息网关产品。

一个MDB通常要实现MessageListener接口,该接口定义了onMessage()方法。Bean通过它来处理收到的JMS消息。
package javax.jms;
public interface MessageListener {
    public void onMessage(Message message);
}

当容器检测到bean守候的目标地址有消息到达时,容器调用onMessage()方法,将消息作为参数传入MDB。MDB在onMessage()中决定如何处理该消息。你可以使用注释指定MDB监听哪一个目标地址(Destination)。当MDB部署时,容器将读取其中的配置信息。

 

 

//下面这段注解说明这个类是一个消息驱动bean
@MessageDriven(activationConfig = {
  @ActivationConfigProperty(propertyName="destinationType", propertyValue="javax.jms.Queue"),
  @ActivationConfigProperty(propertyName="destination", propertyValue="queue/itcastQueue")
})
public class QueueReceiver implements MessageListener { public void onMessage(Message msg) {
  if(msg instanceof TextMessage){
   TextMessage message = (TextMessage) msg;
   try {
    System.out.println(message.getText());
   } catch (JMSException e) {
    e.printStackTrace();
   }
  }
 }}
 
将其打包发布到jboss中,然后运行客户端,观察jboss服务端控制台打印的信息
 
 
PTP 消息传递模型规定了一条消息只能传递给一个接收方。 采用javax.jms.Queue 表示,如果要使用Pub/sub 消息传递模型允许一条消息传递给多个接收方。采用javax.jms.Topic表示即可。