• 1. Java Message Service2010-09-27
  • 2. JMS基础知识2JMS消息类型点对点类型:消息生产者将生产的消息放入一个队列中,消费者从消息队列中取走消息。消息一旦被一个消费者取走,该消息就从消息队列中删除。也就是说,一条消息仅能被一个消费者消费一次。 发布/订阅类型:这种类型的JMS与点对点类型的最大不同是,发布者发布的一条消息可以被该消息的所有订阅者消费一次,即每个订阅者都有一次消息该消息的机会。 JMS主要有两个版本:JMS 1.0.2和JMS 1.1。两者主要区别在于JMS 1.0.2严格区分点对点类型和发布/订阅类型并为它们定义了对应高级接口的子接口。而JMS1.1将两种消息域统一在一起,通过高级接口就可以透明地操作两种消息域,并且JMS1.1为向下兼容也提供了特定于消息域的子接口。
  • 3. JMS基础知识3JMS高级接口及特定域的子接口高级接口点对点域子接口发布/订阅域子接口ConnectionFactoryQueueConnectionFactoryTopicConnectionFactoryConnectionQueueConnectionTopicConnectionDestinationQueueTopicSessionQueueSessionTopicSessionMessageProducerQueueSenderTopicPublisherMessageConsumerQueueReceiver/QueueBrowserTopicSubscriber注意,MessageConsumer有两个子接口,QueueReceiver从队列中获取消息后,该消息将从队列中删除,而QueueBrowser只是查看队列中的消息,消息并不会从队列中删除。其实QueueBrowser并不是MessageConsumer的子接口,它是独立的接口。
  • 4. JMS基础知识4创建JMS消息的初始化步骤一个典型的JMS程序要经过一下步骤才能开始创建和使用消息: 通过JNDI查询ConnectionFactory; 用ConnectionFactory创建一个Connection; 用Connection创建一个或者多个Session; 通过JNDI查询一个或者多个Destination; 用Session和Destination创建对应的MessageProducer和MessageConsumer; 经过以上步骤后才能从MOM发送消息。 启动Connection。 经过以上步骤后才能从MOM接收消息。
  • 5. JMS Message的结构5HeaderHeader:Header是一组标准键值字段,客户端和提供者都用它来标识和路由消息。Message接口为获取和设置Header字段提供了相关方法,如getJMSPriority()、setJMSMessageID(String id)等。
  • 6. JMS Message的结构6Header字段类型说明JMSMessageIDString惟一标识提供者发送的每一条消息。这个字段是在发送过程中由提供者设置的,客户端只能在消息发送后才能确定消息的 JMSMessageID。JMSDestinationDestination消息发送的 Destination,在发送过程中由提供者设置。JMSDeliveryModeint包含DeliveryMode.PERSISTENT 或 DeliveryMode.NON_PERSISTENT。持久性消息被传输并且只被传输一次,非持久性消息最多被传输一次。非持久性消息在应用程序或者系统出故障时被提供者弄丢。这比开销通常被认为是发送持久性消息方面的开销,在决定消息的发送模式时,必须仔细考虑,在可靠性和性能之间进行权衡。JMSTimestamplong提供者发送消息的时间,由提供者在发送过程中设置。JMSExpirationlong消息被成功发送以后,该属性持有该消息的过期时间。该值是客户设置的消息生存时间和当前时间的和。当设置的消息生存时间为0,则表示消息永不过期。当一个消息到达过期时间,MOM应该丢弃它。但是JMS API并没有定义任何形式消息过期的通知方法。客户端不应该接收过期的消息,但是JMS API不保证一定会这么做。JMSPriorityint消息的优先级,由提供者在发送过程中设置。优先级 0 的优先级最低,优先级 9 的优先级最高。JMSCorrelationIDString通常用来链接响应消息与请求消息,由发送消息的 JMS 程序设置。响应来自另一个 JMS 程序的消息的 JMS 程序将正响应消息的 JMSMessageID 拷贝到这个字段中,这样,正作出响应的程序就可以与它所发出的特定请求的响应相 关联。JMSReplyToDestination请求程序用它来指出回复消息应发送的地方,由发送消息的 JMS 程序设置。JMSTypeStringJMS 程序用它来指出消息的类型。一些提供者维护着一个消息类型仓库,并用该字段引用仓库中的定义类型,在这里,JMS 程序不应该使用这个字段。JMSRedeliveredboolean指出消息被过早地发送给了 JMS 程序,程序不知道消息的接收者是谁;由提供者在接收过程中设置。
  • 7. JMS Message的结构7PropertiesProperties:如果用户觉得JMS标准Header中的属性不够,那么可以设置其他属性。Message提供了Setter和Getter方法来设置和获取各种Java类型的属性,如getStringProperty("username")等。虽然开发者可以自定义任意的属性名,但JMS也规定了JMS提供者可以有选择实现的一组标准属性。在定义属性名时有一个规则:以JMSX为前缀的属性是JMS专用,以JMSX_为前缀的属性是JMS提供者专用。
  • 8. JMS Message的结构8Properties – 选择提供的标准属性字段名类型说明JMSXUserIDString发送消息的用户的身份。JMSXApplIDString发送消息的应用程序的身份。JMSXDeliveryCountint已经尝试发送消息的次数。JMSXGroupIDString该消息所属的消息组的身份。JMSXGroupSeqint该消息在消息组中的序号。JMSXProducerTXIDString生成该消息的事务的身份。JMSXConsumerTXIDString使用该消息的事务的身份。JMSXRcvTimestamplongJMS 将消息发送给客户的时间。JMSXStateint提供者用其维护消息仓库,它与 JMS 生产者和客户关系不大。
  • 9. JMS Message的结构9BodyBody:消息正文包含了发送给其他程序的消息内容,根据消息体类型的不同,JMS拥有5个消息类型,并分别通过Message的5个子类接口来描述。
  • 10. JMS Message的结构10Body – 五种消息类型消息类型说明TextMessage消息是一个字符串。ObjectMessage消息是一个实现了Serializable接口的Java对象。BytesMessage消息是一个byte[]类型的对象。MapMessage包含一组键值对,其中键是String类型,值是任意的 Java对象。StreamMessage包含一组 Java 原始类型,这些值通过标准流操作按顺序进行填充和读取。
  • 11. 消息的确认11消息确认的概念消息确认是接收者在成功接收(针对接收消息而言)到消息后,将一个回执发送给MOM,告知已经成功接收的一种通知机制,消息确认类型在通过Connection创建Session时,作为createSession()方法的参数。如果使用了事务的方式,则该确认方式会被忽略。
  • 12. 消息的确认12消息确认的类型Session.AUTO_ACKNOWLEDGE:自动确认模式。一旦接收方应用程序的方法调用从处理消息处返回(包括直接接收和通过MessageListener接收),Session自动发送一个确认回执。 Session.CLIENT_ACKNOWLEDGE:客户端确认模式。会话对象依赖于应用程序对被接收的消息调用一个acknowledge()方法。一旦这个方法被调用,会话会确认最后一次确认之后所有接收到的消息。这种模式允许应用程序以一个调用来接收,处理并确认一批消息。 Session. DUPS_OK_ACKNOWLEDGE:延迟确认模式。让Session延迟发送确认回执,以提高消息接收的性能,不过这种确认方式可能造成消息重复接收的问题,因为如果已经成功接收消息,单确认回执在延迟情况下未及时发给MOM时,如果这时MOM因故障停机重启后,则会将这些消息重新发送给客户端。 SESSION_TRANSACTED:当创建Session时开启了事务功能,则消息通知方式一定为该值。通过createSession()设置的任何模式都被忽略。
  • 13. 消息选择器13消息选择器的概念消息选择器是一个包含选择表达式的字符串语句,该表达式的语法是基于SQL92的子集,对应WHERE部分的过滤表达式。在尝试接收消息时,消息选择器对目标消息进行过滤,只有匹配选择器过滤条件的消息才会被接收。
  • 14. 消息选择器14消息选择器的使用选择条件通过Header字段和Properties属性进行匹配度设置,Body内的值不能用于选择条件。另外,Header中的字段只能限定在以下字段中:JMSDeliveryMode、JMSPriority、JMSMessageID、JMSTimestamp、JMSCorrelationID、JMSType。 消息选择器在通过Session创建接收者(或QueueBrowser)时指定,格式如下: MessageConsumer consumer = session.createConsumer(dest, "JMSType= 'person ' ");
  • 15. 消息的发送15典型示例public void send(String msg)throws Exception{ InitialContext ctx = new InitialContext(); ConnectionFactory factory = (ConnectionFactory)ctx.lookup(“jndi/jmsConn”); Destination dest = (Destination)ctx.lookup(“jndi/dest”) ctx.close(); Connection conn = factory.createConnection(); Session session = conn.createSession(false,Session.AUTO_ACKNOWLEDGE); MessageProducer sender = session.createProducer(dest); TextMessage message = session.createTextMessage(msg); sender.send(message); session.close(); conn.close(); } JMS规范要求ConnectionFactory和Destination必须从JNDI中获取,因此在一般情况下,JMS客户端程序必须绑定在应用服务器上。
  • 16. 消息的接收16典型示例public void receive()throws Exception{ InitialContext ctx = new InitialContext(); ConnectionFactory factory = (ConnectionFactory)ctx.lookup(“jndi/jmsConn”); Destination dest = (Destination)ctx.lookup(“jndi/dest”) ctx.close(); Connection conn = factory.createConnection(); Session session = conn.createSession(false,Session.AUTO_ACKNOWLEDGE); MessageConsumer receiver = session.createConsumer(dest); Conn.start(); TextMessage message = (TextMessage)receiver.receive(); System.out.println(message.getText()); Session.close(); conn.close(); }
  • 17. 消息的接收17同步和异步接收JMS有两种接收消息的方式:同步接收和异步接收。使用MessageConsumer.receive()方法是使用同步接收机制。当目标地址中没有消息到达时,主程序一直阻塞等待。如果希望等待一段时间后返回,可以通过receive(long timeout)设定超时时间,当时间过期还没有消息到达,则返回null,如果该参数设置为0表示永不超时。此外,可以通过receiveNoWait()获取消息,该方法在有消息时返回消息,否则返回null,不阻塞等待。 可以通过向MessageConsumer注册一个MessageListener实现异步消息,MessageListener接口定义了一个方法:void onMessage(Message msg)。当消息到达时,JMS会自动通知消息接收者的消息监听器,可以通过MessageConsumer.setMessageListener(MessageListener listener)方法设置一个消息监听器。但如果客户端希望持续监听某一地址的消息,必须维护MessageConsumer的生存环境,保持Session、Connection等实例的生命周期。
  • 18. 关于Session对象18注意事项客观的说,Session对象是轻量级的,并且是线程不安全的。 一个Session对象可以服务于多个生产者和消费者。 如果创建Session是指定需要使用事务,那么该Session将一直运行在事务状态下。这也是为什么Session对象没有begin()方法,但却有commit()和rollback()方法的原因。每当调用这两个方法,则当前事务结束,同时自动开始一个新的事务。
  • 19. 关于Connection对象19注意事项Connection的主要作用包括: 它封装了一个和消息服务器之间的连接,通常是一个Socket连接。 客户端认证在创建Connection对象的时候执行。 它用于标识一个唯一的客户端标识符。 它提供了一个ConnectionMetaData对象。 它提供了一个可选的ExceptionListener对象。 Connection对象是线程安全的,是重量级的对象,因此通常一个客户端只需要一个该对象。 当Connection创建完成,它默认处于关闭状态。通常我们一直保持Connection对象关闭,直到创建完所有的生产者和消费者。此时,我们可以调用Connection.start()开始消费消息。这样做的原因是,如果一开始就打开Connection对象,在还没有完全创建好消费者的时候,有消息过来,此时就会出现状态不一致问题。 消息生产者能够在Connection关闭的情况下发送消息。
  • 20. JMS事务处理20注意事项JMS事务将一组产生或消费消息的操作组成一组原子操作。 JMS使用Session对象控制事务,如果创建Session时将它标注为需要事务支持,则使用该Session进行的消息操作将工作在事务环境下。Session拥有支持事务语意的两个方法,通过这些方法提交和回滚一个事务,这两个方法分别是commit()和rollback()。此外,还可以通过JTA XAResource API支持分布式事务,但JMS规范并未对提供者作强制的要求。
  • 21. Thank You!