3. JMS API编程模型
一个JMS应用由以下几个模块组成:
3.1. Administered Objects
JMS应用的destinations和connection factories最后是通过管理而不是编程来使用,因为不同的provider使用他们的方法不一样。
JMS 客户应该使用同一的接口得到这些objects,从而使用JMS应用可以运行在不同provider上,而不需要修改或修改很少。通常管理员在JNDI上设置administered objects, 然后JMS clients 在JNDI上look up这些对象。
3.1.1 Connection Factories:
connection factory 是client用来生成与provider的connection的对象。connection factory封装了一套由管理员定义的connection configuration参数。每个connection factory 是一个QueueConnectionFactory 或 TopicConnectionFactory接口的实例。 
在JMS 客户程序中, 通常先执行connection factory 的JNDI API lookup。 如下例:
Context ctx = new InitialContext();
QueueConnectionFactory queueConnectionFactory = 
  (QueueConnectionFactory) ctx.lookup("QueueConnectionFactory");
TopicConnectionFactory topicConnectionFactory = 
  (TopicConnectionFactory) ctx.lookup("TopicConnectionFactory");
如果调用不带参数的InitialContext的lookup方法,就在当前classpath 找jndi.properties文件。
3.1.2 Destinations:
Destination 是一个对象用于定义用户产生的messages 的去向或用户使用的messages 的来源。
在PTP里,destinations被称作queues, 可以用下面的J2EE SDK command来生成它们: 
j2eeadmin -addJmsDestination queue_name queue
在pub/sub里, destinations被称为topics, 可以用下面的J2EE SDK command 来生成它们: 
j2eeadmin -addJmsDestination topic_name topic
一个JMS应用可以同时使用多个queues 和/或topics。
除了lookup connection factory, 也常要lookup destination。例如: 
Topic myTopic = (Topic) ctx.lookup("MyTopic");
Queue myQueue = (Queue) ctx.lookup("MyQueue");3.2. Connections
Connection封装了一个与JMS provider的虚拟连接。Connection表示在client和provider service daemon之间打开的TCP/IP socket。可以用connection 生成一个或多个sessions。
就象connection factories, connections有两种方式:实现QueueConnection或TopicConnection接口。例如, 当有一个QueueConnectionFactory 或TopicConnectionFactory对象, 可以用他们来创造一个connection: 
QueueConnection queueConnection =
  queueConnectionFactory.createQueueConnection();
TopicConnection topicConnection = 
  topicConnectionFactory.createTopicConnection();
当应用程序完成后, 必须关闭你所创建的connections。否则JMS provider 无法释放资源。关闭了connection同时也关闭了sessions和message产生者和message使用者。
queueConnection.close();
topicConnection.close();
在使用messages前, 必须调用connection的start方法。如果要暂时停止传送message而不关闭connection, 可以调用stop方法。connection factory 是client用来生成与provider的connection的对象。connection factory封装了一套由管理员定义的connection configuration参数。每个connection factory 是一个QueueConnectionFactory 或 TopicConnectionFactory接口的实
3.3. Sessions
Session是单线程的context用于产生和使用messages。用sessions创建 message producers, message consumers, and messages。Sessions管理message listeners的执行顺序。
Ssession提供transactional context用于将一系列的sends和receives动作组合在一个工作单元里。 
Sessions, 就象connections, 也有两种方式:实现QueueSession或TopicSession接口。例如: 
TopicSession topicSession = 
  topicConnection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
第一个参数表示sessiong不实现事务处理; 第二个参数表示当session成功收到messages后自动确认。 
相同的,可以用QueueConnection对象创建QueueSession: 
QueueSession queueSession =
  queueConnection.createQueueSession(true, 0);
这里, 第一个参数表示session实现事务处理; 第二个参数表示当session成功收到messages后不自动确认。 
3.4. Message Producers
message producer是由session创建和一个object,用于将messages传递到destination. PTP方式的message producer实现QueueSender接口。 pub/sub方式的message producer实现TopicPublisher接口。 
例如:: 
QueueSender queueSender = queueSession.createSender(myQueue);
TopicPublisher topicPublisher = topicSession.createPublisher(myTopic);
用null作为createSender或createPublisher的参数,可以创建一个不确定的producer。用不确定的producer, 可以等到真正send或publish message的时候才指定destination 
当创建了一个message producer, 就可以用它来发送messages. (You have to create the messages first; see Section 3.6, "Messages.") Wi。例如: 
queueSender.send(message);
topicPublisher.publish(message);

解决方案 »

  1.   

    例子请参考weblogic里带的例子
      

  2.   

    在j2ee中JMS并不难。
    练习时我是什么都用上了,但设计时的取舍比较难办,
    有项目经验的说说
      

  3.   

    我现在帮别人做的二crm系统,就没有用到jms。真不知道什么时候该用jms
      

  4.   

    3.5. Message Consumer
    message consumer也中由session创建和一个object,用于接收发送到destination 的message 。message consumer允许JMS client到JMS provider注册感兴趣的destination。JMS provider管理messages从destination到注册了这个destination的consumers之间的传送。
    PTP方式的message consumer实现QueueReceiver接口。pub/sub方式的message consumer实现TopicSubscriber接口。
    例如: 
    QueueReceiver queueReceiver = queueSession.createReceiver(myQueue);
    TopicSubscriber topicSubscriber = topicSession.createSubscriber(myTopic);
    可以用TopicSession.createDurableSubscriber方法创建一个durable topic subscriber。 
    当创建了一个message consumer, 它就是活动的,就可以用它接收messages。可以用QueueReceiver 或TopicSubscriber的close方法把message consumer变成不活动的。Message的传送在调用了connection的start方法后才开始。
    不论是QueueReceiver或TopicSubscriber, 都可以用receive方法来同步consume message。 你可以在调用start方法后的任何时间调用它: 
    queueConnection.start();
    Message m = queueReceiver.receive();
    topicConnection.start();
    Message m = topicSubscriber.receive(1000); // time out after a second
    异步consume message, 可以使用message listener。 
    3.5.1   Message Listeners 
    message listener是一个对象,用作充当messages的异步事件处理器。它实现了MessageListener接口, 它只有一个方法:onMessage. 在onMessage方法内, 可以定义当收到一个message后做的事情。
    用setMessageListener方法在某个QueueReceiver 或TopicSubscriber里注册message listener。例如:
    TopicListener topicListener = new TopicListener();
    topicSubscriber.setMessageListener(topicListener);
    当注册了message listener, 调用QueueConnection或TopicConnection的方法来开始传送message。
    当message开始传送, 当有message送来,message consumer自动调用message listener的 onMessage方法。onMessage方法只有一个Message类型的参数。
    message listener并不对应特定的destination类型. 相同的listener可以从queue或topic上得到message, 这由listener是由QueueReceiver还是 TopicSubscriber对象设置的。然而message listener通常对应某一个message类型或格式, 如果要回应messages, message listener必须创建一个message producer。
    onMessage方法应该处理所有的exceptions。
    Session负责管理message listeners的执行顺序。任何时候,只有一个message listeners在运行。
    在J2EE 1.3中, message-driven bean是一个特殊的message listener。
     3.5.2  Message Selectors 
    如果你的消息应用程序需要过滤收到的messages, 可以用JMS API中的message selector来让message consumer定义它所感兴趣的messages。Message selectors负责过滤到JMS provider的message,而不是到应用程序的。
    message selector是一个含有表达式的字符串。表达式的语法是SQL92 conditional expression syntax的一个子集。当创建message consumer时, createReceiver, createSubscriber, 和createDurableSubscriber方法都可以让你定义某个message selector作为参数。 
    message consumer只接收headers和properties与selector匹配的messages。message selector不能根据message body的内容进行选择。 
    3.6   Messages 
    JMS application的最终目的是为了与其它应用程序分享messages。JMS messages有一个基本的格式,这种格式既简单又灵活,可以上你生成在其它平台上非JMS applications可以使用的格式。
    JMS message有三个部分: 
    1. header 
    2. Properties (可选) 
    3. body (可选) 
    3.6.1   Message Headers 
    JMS message header包含几具预定义的fields,它的值可以被clients和providers用来识别和发送messages. (Table 3.1 例出了JMS message header和fields和如何set它们的值。) 例如, 每一个message都有唯一个的标识符, 表示在JMSMessageID里。JMSDestination表示message发送到的queue或topic。 其它fields包括timestamp和优先级。 
    每一个header field都有对应的setter和getter方法。某些header fields是由客户set的, 但有些是自动在send或publish方法中set的, 这有可能覆盖一一些客户set的值: 
    Table 3.1:    如何设置JMS Message Header Field的值
    Header Field Set By
    JMSDestination send or publish method
    JMSDeliveryMode send or publish method
    JMSExpiration send or publish method
    JMSPriority send or publish method
    JMSMessageID send or publish method
    JMSTimestamp send or publish method
    JMSCorrelationID Client
    JMSReplyTo Client
    JMSType Client
    JMSRedelivered JMS provider3.6.2   Message Properties 
    你可以创建和设置messages properties以补充header fields的不足。可以通过使用properties来达到与其它消息系统的兼容, 或者用它们来做message selectors。
    3.6.3   Message Bodies 
    JMS API定义了5种message body格式, 让你可以用不同的格式send和receive数据,并与现有的message格式兼容。Table 3.2描述了各种消息格式。
    Table 3.2:    JMS Message格式
    Message Type Body Contains
    TextMessage A java.lang.String object (for example, the contents of an Extensible Markup Language file).
    MapMessage A set of name/value pairs, with names as String objects and values as primitive types in the Java programming language. The entries can be accessed sequentially by enumerator or randomly by name. The order of the entries is undefined.
    BytesMessage A stream of uninterpreted bytes. This message type is for literally encoding a body to match an existing message format.
    StreamMessage A stream of primitive values in the Java programming language, filled and read sequentially.
    ObjectMessage A Serializable object in the Java programming language.
    Message Nothing. Composed of header fields and properties only. This message type is useful when a message body is not required.
    JMS API为每一种messages都提供了一种create方法。例如:
    TextMessage message = queueSession.createTextMessage();
    message.setText(msg_text);     // msg_text is a String
    queueSender.send(message);
    在使用者一端, 必须将收到的Message cast成适当的message类型。 例如: 
    Message m = queueReceiver.receive();
    if (m instanceof TextMessage) {
        TextMessage message = (TextMessage) m;
        System.out.println("Reading message: " + message.getText());
    } else {
        // Handle error
    }
    3.7   Exception Handling 
    JMS API的方法的Exception的根类是JMSException。JMSException类包括如下子类: 
    IllegalStateException 
    InvalidClientIDException 
    InvalidDestinationException 
    InvalidSelectorException 
    JMSSecurityException 
    MessageEOFException 
    MessageFormatException 
    MessageNotReadableException 
    MessageNotWriteableException 
    ResourceAllocationException 
    TransactionInProgressException 
    TransactionRolledBackException 
      

  5.   

    真不知道什么时候该用jms!!
    同感
      

  6.   

    一般用在大型BtoB,去亚马逊看看吧.
      

  7.   

    请问jms在网络断开时会否把消息缓存,在网络连接时再自动继续发送?
    我是说在两台server的情况下,server1向server2发送消息
      

  8.   

    jms是有序列化的,所以smilelee的问题应该是可以的。
      

  9.   

    刚开始看,我晕,MD,真不知道啥时候能理解,MD
      

  10.   

    liuyu9806(羽翔):
    1.publisher是发出消息的,他发完消息后可以close, 消息是一直保存在消息服务器(MOM)上的,直到所有的subscriber拿到消息后,这条消息就消失了。非持久性订阅是指,如果subscriber断了连接,那在这期间别人发出的消息他是收不到的,而持久性的订阅则仍可收到。
    2.这是指publisher和subscriber不需要身分认证。我也在深入学习,大家可以多交流