JMS消息驱动MDB

                                                             JMS消息驱动MDB

Java 消息服务支持两种消息模型:Point-to-Point 消息(P2P)和发布订阅消息(Publish Subscribe messaging,简称Pub/Sub)

 

      发布/订阅模式此模式类似于看电视。很多电视台都在广播自己的信号,而同时又有很多人在观看这些节目。不过,需要区别的是,JMS 中通信是双向的,一般来说接收者同时也可能是一个发布者,因为它收到消息后需要回复。订阅者(收看者)注册自己感兴趣的特
定主题,发布者则创建发布到所有订阅者的消息。这时候有个关键的术语就叫Topic(主题),一般来说对应服务器的某个JNDI 地址,发送者向里面发送信息,接受者则订阅此Topic 即可

 

      点对点方式 此模式类似于语音信箱,可以给此信息发送语音留言,接受者会阅读完毕后删除此信息。这种模式下,一条消息只能被一人接受,而且也只能阅读一次。这可以认为是发布/订阅模式的简化为一个电台一个接收者时候的情形。此时对应的术语叫Queue(队
列),两个人同时连接到同一队列,才能收发消息

 

 

 

JMS 消息由以下部分组成:
• Header(头)- 所有消息都支持相同的头字段集合。头字段包含客户端和提供者用于标识和路由消息的值。
• Property(属性)- 每个消息都包含一个内置工具,用于支持应用程序定义的属性值。属性为支持应用程序定义的消息过滤提供了一种有效的机制。
• Body(正文)- JMS API 定义了几种消息正文类型,涵盖了当前使用的大多数消息传递样式。

 

消息正文

JMS API 定义了五种消息正文类型:
• Stream(流)- StreamMessage 对象的消息正文包含 Java 编程语言原始值流(“Java 基本类型”)。按顺序填充和读取。
• Map(映射)- MapMessage 对象的消息正文包含一组名称-值对,其中名称是 String对象,值是 Java 基本类型。可以根据名称按顺序或随机访问这些条目。条目的顺序是不确定的。
• Text(文本)- TextMessage 对象的消息正文包含 java.lang.String 对象。此消息类型可用于传输纯文本消息和 XML 消息。
• Object(对象)- ObjectMessage 对象的消息正文包含 Serializable Java 对象。

• Byte(字节)- BytesMessage 对象的消息正文包含未解释的字节流。此消息类型可以按字面意义编码正文,以匹配现有的消息格式。在大多数情况下,可以使用更易用的其他正文类型。尽管 JMS API 允许将消息属性用于字节消息,但一般不使用它们,因为包含属性可能会影响格式。

 

消息头
JMSCorrelationID 头字段用于连接一个消息与另一个消息。它通常连接应答消息与请求消息。
JMSCorrelationID 可以保存特定于提供者的消息 ID、特定于应用程序的 String 对象,或者提供者-本机 byte[] 值。

 

消息属性
Message 对象包含一个内置工具,用于支持应用程序定义的属性值。实际上,这提供了一种将特定于应用程序的头字段添加到消息的机制。
属性允许应用程序通过消息选择器让 JMS 提供者使用特定于应用程序的标准为自己选择或过滤消息。

 

 

 

 

JMS 编程模型

JMS 的使用者一共要完成两个任务,一是发送消息,二是接收消息。

一、发送消息

1. 初始化JNDI;
2. 通过 JNDI 查找 ConnectionFactory(连接工厂);
3. 使用 ConnectionFactory 创建 JMS Connection(连接);
4. 使用连接创建会话(Session);
5. 通过 JNDI 查找目的地(主题或者队列,Topic/Queue);
6. 创建消息生产器/队列发送者(TopicPublisher/QueueSender);
7. 创建消息;
8. 给消息设置一些额外属性(可选);
9. 发送消息;
10. 关闭会话。

二、接收消息

1. 初始化JNDI;
2. 通过 JNDI 查找 ConnectionFactory(连接工厂);
3. 使用 ConnectionFactory 创建 JMS Connection(连接);
4. 使用连接创建会话(Session);
5. 通过 JNDI 查找目的地(主题或者队列,Topic/Queue);

6. 创建消息消费者或者主题订阅者(MessageConsumer/TopicSubscriber);
7. 打开连接(connection.start());
8. 接收并处理消息(可以使用消息监听器MessageListener);
9. 关闭会话。

 

 

 

TopicConnectionFactory (class: org.jboss.naming.LinkRefPair) -> 此地址为主题连接工厂
ConnectionFactory (class: org.jboss.mq.SpyConnectionFactory) -> 普通连接工厂

 

 

 

 

 

 

 

      JMS 消息选择器允许客户端通过头字段引用和属性引用指定感兴趣的消息。只传送头和属性值匹配选择器的那些消息。这意味着消息是否被传送取决于使用的MessageConsumer(请参考 QueueReceiver 和 TopicSubscriber)。消息选择器不能引用消息正文值。消息的头字段值和属性值替换了消息选择器中对应的标识符后,如果选择器求值为 true,则消息选择器匹配该消息。
      消息选择器是一个 String,其语法是以 SQL92 条件表达式语法子集为基础的。如果消息选择器的值是一个空字符串,则该值视为 null,表示没有任何消息选择器可供消息使用方使用。
消息选择器的求值顺序是按优先级从左到右计算。可以使用括号来更改此顺序。预定义选择器的字面值和操作符名称在这里用大写表示;实际上它们是不区分大小写的。
选择器可以包含:
• 字面值:
o 字符串字面值使用单引号括起,单引号则用两个单引号表示;例如,'literal'和 'literal''s'。这些字面值与 Java 编程语言中的字符串字面值一样,都使用 Unicode 字符编码。
o 一个精确的数字字面值是一个不带小数点的数值,如 57、-957 和 +62;支持 long 型的数值范围。精确的数字字面值使用 Java 编程语言中的整数字面值语法。
o 一 个 近 似 的数字字面值是使用科学计数法表示的数值, 如 7E3 和-57.9E2,或者是带小数点的数值,如 7.、-95.7 和 +6.2;支持 double 型的数值范围。近似的数字字面值使用 Java 编程语言中的浮点字面值语法。
o 布尔字面值为 TRUE 或 FALSE。

 

• 标识符:
o 标识符是一个任意长度的字母数字序列,其首字符必须是字母。字母是对其调用 Character.isJavaLetter 方法可返回 true 的任何字符。这包括 '_' 和'$'。字母或数字是对其调用 Character.isJavaLetterOrDigit 方法可返回true 的任何字符。
o 标识符不能使用名称 NULL、TRUE 和 FALSE。
o 标识符不能是 NOT、AND、OR、BETWEEN、LIKE、IN、IS 或 ESCAPE。
o 标识符是头字段引用或属性引用。消息选择器中属性值的类型对应于设置属性时使用的类型。如果引用了消息中不存在的属性,则其值为 NULL。
o 当属性用于消息选择器表达式时,不可应用适用于属性获取方法的转换。例如,假设将属性设置为一个字符串值,如下所示:

myMessage.setStringProperty("NumberOfOrders", "2");
以下消息选择器中的表达式将求值为 false,因为字符串不能用于算术表达式:

"NumberOfOrders > 1"
o 标识符是区分大小写的。
o 消息头字段引用限于 JMSDeliveryMode、JMSPriority、JMSMessageID、JMSTimestamp 、JMSCorrelationID 和 JMSType 。JMSMessageID 、JMSCorrelationID 和 JMSType 值可以为 null,如果为 null,则按 NULL值处理它们。
o 以 'JMSX' 开头的任何名称是一个 JMS 定义的属性名称。
o 以 'JMS_' 开头的任何名称是一个特定于提供者的属性名称。
o 不以 'JMS' 开头的任何名称是一个特定于应用程序的属性名称。

• 空白字符与 Java 编程语言中的定义相同:空格、水平制表符、换页符和行结束符。
• 表达式:
o 选择器是一个条件表达式;求值为 true,则选择器匹配;求值为 false 或“未知”,则选择器不匹配。
o 算术表达式由其他算术表达式、算术运算、标识符(其值视为数字字面值处理)和数字字面值构成。
o 条件表达式由其他条件表达式、比较运算和逻辑运算构成。

• 支持使用标准括号 () 对表达式的求值顺序进行排序。
• 按优先级从高到低排序的逻辑运算符:NOT、AND、OR

• 比较运算符:=、>、>=、<、<=、<>(不等于)
o 只能比较相同类型的值。有一种例外情况,即比较精确数字字面值和近似数字字面值是有效的;所需的类型转换由 Java 编程语言中的数值提升(numeric promotion) 规则定义。如果尝试比较不同类型的值,运算的值为false。如果两个类型值求值都为 NULL,则表达式的值知。
o 字符串和布尔值的比较只能使用 = 和 <>。当且仅当两个字符串具有相同字符序列时它们才相等。

• 按优先级从高到低排序的算术运算符:
o +、-(一元)
o *、/(乘和除)
o +、-(加和减)

o 算术运算必须使用 Java 编程语言中的数值提升。

• arithmetic-expr1 [NOT] BETWEEN arithmetic-expr2 AND arithmetic-expr3(比较运
算符)
o "age BETWEEN 15 AND 19" 等于 "age >= 15 AND age <= 19"
o "age NOT BETWEEN 15 AND 19" 等于 "age < 15 OR age > 19"
• identifier [NOT] IN (string-literal1, string-literal2,...)(比较运算符,其中identifier 具有 String 或 NULL 值)
o "Country IN (' UK', 'US', 'France')" 对于 'UK' 为 true, 对于 'Peru' 为false ; 它等效于表达式"(Country = ' UK') OR (Country = 'US') OR (Country = ' France')"
o "Country NOT IN (' UK', 'US', 'France')" 对于 'UK' 为 false,对于 'Peru'为 true ; 它等效于表达式"NOT ((Country = ' UK') OR (Country = ' US') OR (Country = ' France'))"
o 如果 IN 或 NOT IN 运算的标识符为 NULL,则运算的值未知。

• identifier [NOT] LIKE pattern-value [ESCAPE escape-character](比较运算符,其中identifier 具有 String 值。pattern-value 是一个字符串字面值,其中 '_' 表示任何单个字符,'%' 表示任何字符序列,包括空序列,所有其他字符都表示自身。可选的escape-character 是 一 个 单 字 符 字 符 串 字 面 值 , 其 字 符 用 于 转 义pattern-value 中 '_' 和 '%' 的特殊含义。)
o "phone LIKE '12%3'" 对于 '123' 或 '12993' 为 true,对于 '1234' 为false。
o "word LIKE 'l_se'" 对于 'lose' 为 true,对于 'loose' 为 false。
o "underscored LIKE '/_%' ESCAPE '/'" 对于 '_foo' 为 true,对于 'bar' 为false。
o "phone NOT LIKE '12%3'" 对于 '123' 或 '12993' 为 false,对于 '1234'为 true。
o 如果 LIKE 或 NOT LIKE 运算的identifier 为 NULL,则运算的值未知。

• identifier IS NULL(比较运算符,测试 null 头字段值或缺失的属性值)
o "prop_name IS NULL"
• identifier IS NOT NULL(比较运算符,测试非 null 头字段值或属性值是否存在)
o "prop_name IS NOT NULL"

     JMS 提供者必须在出现消息选择器时验证其语法的正确性。提供语法不正确的选择器的方法必定导致抛出 JMSException。JMS 提供者还可以在出现选择器时有选择地提供一些语义检查。并非所有语义检查都可以在出现消息选择器时执行,因为属性类型是未知的。以下消息选择器选择消息类型为 car、颜色为 blue、重量超过 2500 磅的消息:
"JMSType = 'car' AND color = 'blue' AND weight > 2500"

 

 

MDB 简介及MDB 编程

     如前所述,虽然JMS 的消息发送相对比较容易,然而,如何接收并处理Message,则相对显得要复杂的多。为此,EJB 推出了消息驱动Bean(Message Driven Bean,简称MDB)。MDB 不绑定到JNDI 地址,也不能被别的Bean 调用,也不能被客户端调用执行。它的功能,就是在收到消息后自动调用处理方法,简单的说就是一个服务器自动管理消息接收的MessageListener,其代码结构如下所示:

@MessageDriven
public class MDBImpl implements MessageListener {
   public void onMessage(Message message) {
        System.out.println("A message arrived!");
   }
}

。除此之外不需要别的内容。
MDB 的生命周期和无状态会话Bean 非常相似,其生命周期如图16.33 所示。其生命周期除了依赖注入外,就是等待接收消息并处理了。右图可以看到MDB 也支持@PostConstruct,@PreDestroy 这样的标注。

猜你喜欢

转载自goahead2010.iteye.com/blog/1907372