Java消息服务(JMS)实现了异步消息的传递,在企业级的应用中,极大的简化了异步通信系统的实现,使用消息传递的优点在于保持了系统的松散耦合。

    JMS支持点到点(P2P)模式和发布-订阅(pub/sub)模式。点到点消息模式依赖于消息队列概念,它将消息发送到称为队列(Queue)的特定目的地,接受者从队列中获取消息,对其进行处理。发布-订阅模式则是将消息发送到成为主题(Topic)的目的地,使用者通过订阅消息来获取。因此,我们可以简单的将Queue和Topic理解为消息的存储器,或者接受器,通过它将消息转发给消息最终的接收者。对于消息,可以是一个简单的字符串,一段二进制流,或者一个任意的对象,当前JMS支持五种类型的消息:TextMessage、MapMessage、ByteMessage、StreamMessage、ObjectMessage。

     下面来看一段P2P的完整实现,
       sender:  

       Context context = new InitialContext();
       QueueConnectionFactory queueConnectionFactory 
= (QueueConnectionFactory) context.lookup("QueueConnectionFactoryTest");
       QueueConnection queueConnection 
= queueConnectionFactory.createQueueConnection();
       QueueSession queueSession 
= queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
       Queue queue 
= (Queue) context.lookup("QueueTest");
       QueueSender queueSender 
= queueSession.createSender(queue);
       TextMessage message 
= queueSession.createTextMessage();
       message.setText(
"Hello JMS!");
       queueSender.send(message);
       queueConnection.close();

       Receiver:

       Context context = new InitialContext();
       QueueConnectionFactory queueConnectionFactory 
= (QueueConnectionFactory) context.lookup("QueueConnectionFactoryTest");
       QueueConnection queueConnection 
= queueConnectionFactory.createQueueConnection();
       QueueSession queueSession 
= queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
       Queue queue 
= (Queue) context.lookup("QueueTest");
       QueueReceiver queueReceiver 
= queueSession.createReceiver(queue);
       queueConnection.start();
       
while (true) {
            Message m 
= queueReceiver.receive();
            
if (m instanceof TextMessage) {
                TextMessage message 
= (TextMessage) m;
                System.out.println(
"Reading message: " + message.getText());
            } 
else {
                
break;
            }
       }
       queueConnection.close();

      由上代码可以看出,sender和receiver的实现基本是相同的,下面我们再来对比一下pub/sub模式的实现,
      publisher:

      Context context = new InitialContext();
      TopicConnectionFactory topicConnectionFactory 
= (TopicConnectionFactory) context.lookup("TopicConnectionFactoryTest");
      TopicConnection topicConnection 
= topicConnectionFactory.createTopicConnection();
      TopicSession topicSession 
= topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
      Topic topic 
= (Topic) context.lookup("TopicTest"); 
      TopicPublisher topicPublisher 
= topicSession.createPublisher(topic);
      TextMessage sentMessage 
= topicSession.createTextMessage();
      sentMessage.setText(
"Here is a message" + i);
      System.out.println(
"PUBLISHER THREAD: Publishing message: " + sentMessage.getText());
      topicPublisher.publish(sentMessage);
      topicConnection.close();

      Subscriber:   

      Context context = new InitialContext();
      TopicConnectionFactory topicConnectionFactory 
= (TopicConnectionFactory) context.lookup("TopicConnectionFactoryTest");
      TopicConnection topicConnection 
= topicConnectionFactory.createTopicConnection();
      TopicSession topicSession 
= topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
      Topic topic 
= (Topic) context.lookup("TopicTest");
      TopicSubscriber topicSubscriber 
= topicSession.createSubscriber(topic, nulltrue);
      topicConnection.start();
      TextMessage inMessage 
= (TextMessage) topicSubscriber.receive();
      System.out.println(
"SUBSCRIBER THREAD: Reading message: "+ inMessage.getText());
      topicConnection.close();

      以上是对P2P和pub/sub两种模式最简单的实现,对于JMS的基本使用来说足够了,对比以上两种模式的实现,我们不难发现一些共同点:都是通过QueueConnectionFactory/TopicConnectionFactory来生成QueueConnection/TopicConnection的实例,QueueConnection/TopicConnection用来建立和JMS的连接并生成会话实例QueueSession/TopicSession,QueueSender的send方法和TopicPublisher的publish方法发送消息到Destination。 QueueReceiver和TopicSubscriber直接使用父接口MessageConsumer中定义的方法receive、recieveNoWait等方法来接收消息。
      如果你想在main方法中运行这些程序,你需要先在Application Server中配置ConnectionFactory和Destination的JNDI,可参考我的上篇文章《Standalone Client Lookup JNDI from the GlassFish》。

      同样,我们可以采用Message Driven Bean(MDB)作为JMS消息的receiver,sender将消息发送到MDB所监听的目的地,EJB容器会调用MDB的onMessage方法去接收消息。以这种方式去实现JMS,应该更J2EE点。
      JMS的实现就是如此的简单,但简单并不代表简陋,JMS还拥有众多的特性,以帮助你在实现中达到更多的目的,同时,还有很多的JMS provider能够更加简化您的JMS应用,比如ActiveMQ,更多的精彩需要你自己的发掘。