一、消息传送机制基础
1、消息传送机制的优点
①异构集成:在完全不同的平台上实现应用程序和系统请求调用服务。消息传送机制提供跨应用程序和子系统共享数据和功能的去耦方案。
②缓解系统瓶颈:与一个同步组件处理众多请求时,众多请求一个接一个地积聚阻塞不同,这时候请求会发送到一个消息传送系统,该系统将该请求分发给多个消息侦听器组件(增加漏斗)。如此一来,就缓解了单独采用点对点同步连接带来的系统瓶颈。
③提高可伸缩性:通过引入能够并发处理不同消息的多个消息接收者(消息侦听器),消息传送系统的可伸缩性得以实现。
④提高最终用户生产率:通过使用异步消息传送机制,用户可以在向系统发出请求后,继续做其他事情。
⑤ 体系结构灵活性和敏捷性:消息传送机制抽象和去耦组件,能快速地响应软硬件和业务的变化。使用消息传送机制方式,消息生产者或是客户端组件都不会知道接收 组件使用的是哪种编程语言或平台,组件或服务位于何处,组件或服务实现的名称是什么,甚至用于访问该组件或服务的是哪种协议。
2、企业消息传送
消息是通过网络从一个系统异步传送给其他系统的。在异步消息传送机制中,应用程序使用一个简单的API来构建一条消息,然后再将该消息转发给面向消息的中间件,以便传送给一个或多个的预定接收者。一条消息就是一个业务数据包,它通过网络从一个应用程序发送给其他应用程序。消息应该是自描述的,因为它包含所有必要的上下文,以便允许接收者独立地完成它们的工作。
消息传送系统由消息传送客户端和几种消息传送中间件服务器所组成。客户端向消息传送服务器发送消息,该服务器随后再将那些消息分发给其他客户端。客户端是使用消息传送API的一个业务应用程序或组件(JMS)。
① 集中式体系结构
依赖于一台消息服务器(也称消息路由器或代理),它负责从一个消息传送客户端(JMS)向其他消息传送客户端(JMS)传送信息,实现一个发送客户端和其他接收客户端之间的解耦。客户端仅仅看到消息传送服务器,而不会看到其他客户端,这将允许在不会影响系统整体的情况下添加和删除客户端。通常,集中式体系结构使用的是星型的拓扑结构。
② 分布式体系结构
使用网络层IP组播,没有集中服务器,一些服务器功能(持久性、事务和安全性)作为一个客户端的本地部分嵌入进来,而此时消息路由则利用IP组播协议委托给网络层。
3、消息传送模型
JMS支持两类消息传送模型(消息传送域):点对点模型(P2P)和发布/订阅(Pub/Sub)模型。点对点模型设计用于一对一消息传送,发布/订阅模型设计用于一对多消息广播。
① 点对点模型:JMS客户端通过队列(queue)这个虚拟通道来同步和异步发送、接收消息,基于拉取(Pull)或者基于轮询(Polling)的消息传送模型,这种模型从队列中请求消息,而不是自动地将消息推送给客户端。耦合性比Pub/Sub模型更强。
② 发布/订阅模型:消息会被发布到一个名为主题(topic)的虚拟通道中,基于推送(Push)的模型,消息自动地向消费者广播,它们无须请求或轮询主题来获得新消息,每个订阅者都会接受到发布者所发送的消息的一个副本。去耦能力比P2P模型更强。
4、JMS API
JMS本身并不是一种消息传送系统,它是消息传送客户端和消息传送系统通信时所需接口和类的一个抽象。JMS抽象可以访问消息提供者。使用JMS,应用程序的消息传送客户端可以实现跨消息服务器产品的移植。
JMS API分为3个主要部分:公共API、点对点API和发布/订阅API。公共API被用于向一个队列或一个主题发送和接收消息,点对点API专门用于队列,发布/订阅API则专门用于主题。
在JMS公共API内部,和发送与接收JMS消息有关的JMS API接口主要有7个:ConnectionFactory、Destination、Connection、Session、Message、MessageProducer、MessageConsumer。
在这些公共接口中,ConnectionFactory、Destination必须使用JNDI从提供者处获得。其他接口则可以通过工厂方法在不同的API接口中创建。
① 点对点API
向一个队列发送和接收消息的接口:QueueConnectionFactory、Queue、QueueConnection、QueueSession、Message、QueueSender、QueueReceiver。
② 发布/订阅API
内部接口:TopicConnectionFactory、Topic、TopicConnection、TopicSession、Message、TopicPublisher、TopicSubscriber。
5、RPC和异步消息传送
①紧密耦合的RPC
紧密耦合的RPC模型最为成功的一个领域就是构建3层或n层应用程序。在这个模型中,表示层(第1层)使用RPC和中间层(第2层)的业务逻辑进行通信,访问位于后端(第3层)的数据。
在调用一个远程过程时,调用者将被阻塞,直到该过程完成并将控制权返回给调用者。从开发者的角度看,这种同步模型使得该系统就好像运行在一个进程当中。这些工作会依次完成,同时确保以预定顺序完成。RPC同步的本质特性,将客户端(进行调用的软件)和服务器(为该调用服务的软件)两种紧密耦合在一起。导致出现相互高度依赖的系统,其中一个系统的失效会对其他系统产生立竿见影的影响。
②企业消息传送
JMS提供一个松散耦合的环境,其中,系统组件的局部故障并不会妨碍系统的整体可用性。
JMS提供了保证传送的方式,基于“保存并转发”的机制,如果预定消费者当前不可用,底层消息服务器会将输入的消息写到一个持久存储器中。随后,当该应用程序变为可用时,“保存并转发”机制会把这些消息都传送给它们。
通过异步处理、“保存并转发”以及“保证传送”机制,JMS为保存业务应用程序连续运行并实现不间断服务提供了很高的可用性。还通过Pub/Sub和P2P功能,提供了集成灵活性。通过位置透明和管理控制,提供了一种健壮的、基于服务的体系结构。
二、编写一个简单的示例
1、使用JMS发布/订阅API来构建一个简单的聊天应用程序。
2、解读JNDI
JNDI是一个标准的Java扩展,它提供了一个统一的API,用于访问多种目录和命名服务。在JMS中,JNDI主要用于命名服务来定位受管对象。受管对象就是由系统管理员创建和配置的JMS对象。包括JMS ConnectionFactory和Destination对象,比如主题和队列等。
受管对象和命名服务中的一个名称相互绑定在一起。一个命名服务将名称和分布式对象、文件和设施关联起来,以便它们可以使用简单的名称而不是密码似的网络地址实现在网络上的定位。
JNDI提供一个隐藏了命名服务细节的抽象,使得客户端应用程序的可移植性更高。使用JNDI,JMS客户端能够浏览一个命名服务,并在不知道命名服务细节或它如何实现的情况下,引用受管对象。JNDI既是虚拟的,又是动态的。
一个InitialContext就是所有JNDI查找的起始点,它和文件系统根目录的概念很相似。InitialContext提供了一个到目录服务的网络连接,这个目录服务就发挥访问JMS受管对象的根目录作用。
InitialContext ctx = new InitialContext(); //使用jndi.properties文件获得一个JNDI连接
3、TopicConnectionFactory
一旦实例化一个JNDI InitialContext对象,就可以使用它在消息传送服务器的命名服务中查找TopicConnectionFactory。
TopicConnectionFactory用于创建到一个消息服务器的连接。一个TopicConnectionFactory就是一类受管对象,这就意味着它的属性和行为要由负责消息传送服务器的系统管理员来配置。
4、TopicConnection
TopicConnection表示和消息服务器的一个连接。从TopicConnectionFactory中创建的每个TopicConnection就是和该服务的唯一连接。
//查找一个JMS连接工厂并创建连接
TopicConnectionFactory conFactory =(TopicConnectionFactory)ctx.lookup(topicFactory);
TopicConnection connection = conFactory.createTopicConnection();
5、TopicSession
TopicSession对象是用于创建Message、TopicPublisher和TopicSubscriber对象的工厂。它还用作JMS内部的事务性工作单元。一个客户端可以创建多个TopicSession对象,对发布者、订阅者以及其相关事务提供粒度更细的控制。
//创建两个JMS会话对象
TopicSession pubSession = connection.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);
TopicSession subSession = connection.createTopicSession(false,Session.AUTO_ACKNOWLEDGE);
6、Topic
JNDI用于定位一个Topic对象,它是类似于TopicConnectionFactory的一个受管对象:Topic chatTopic =(Topic)ctx.lookup(topicName); //查找一个JMS主题
Topic对象是消息传送服务器上一个实际主题的句柄或者标识符,该主题称为物理主题。一个物理主题就是多个客户端订阅和发布消息的一条电子通道。
7、TopicPublisher
TopicPublisher用于将消息传送给一个消息服务器上的特定主题。在createPublisher()方法中使用的Topic对象,确定了将从TopicPublisher接收消息。
TopicPublisher将消息异步传送给该主题。异步传送和消费消息是面向消息中间件的一个关键特性;TopicPublisher不会一直阻塞或等到所有订阅者都接收到该消息为止,而是只要消息服务器一接收到消息,就会从publish()方法返回。
//创建一个JMS发布者和订阅者。createSubscriber中附加的参数是一个消息选择器(null)和noLocal标记的一个真值,它表明这个发布者生产的消息不应被它自己所消费。
TopicPublisher publisher = pubSession.createPublisher(chatTopic);
TopicSubscriber subscriber =subSession.createSubscriber(chatTopic,null,true);
8、TopicSubscriber
TopicSubscriber从特定的主题接收消息。消息服务器将这些消息异步推送给TopicSubscriber,TopicSubscriber不必轮询消息服务器。
JMS中的发布/订阅消息传送模型包括了一个用于处理输入消息的进程内Java事件模型。一个对象实现了侦听器接口(MessageListener),然后使用TopicSubscriber进行注册。一个TopicSubscriber只能有一个MessageListener对象。
当TopicSubscriber从它的主题接收一条消息时,调用了它的MessageListener对象的OnMessage()方法。
subscriber.setMessageListener(this); //设置一个JMS消息侦听器
9、Message
TextMessage类用于封装我们发送和接收的消息。TextMessage包含一个java.lang.String作为它的消息体。
消息类型之间的区别在很大程度上取决于它们的有效负载(即该消息包含的应用程序数据类型)。
10、会话与线程
JMS规范规定,一个会话不能同时在一个以上的的线程中运行。
三、深入剖析一条JMS消息
Message消息是整个JMS规范最为重要的部分。一个JMS应用程序中的所有数据和事件都是使用消息进行通信的,同时JMS其余部分也都在为消息传输服务。
一条JMS消息携带有应用程序数据,并能够提供事件通知。对于分布式计算来说,它的作用是独一无二的。在基于RPC的系统中,一条消息就是执行一个方法或者过程的一个命令,它将阻塞发送者知道一个应答已被接收为止。一个JMS消息并不是一个命令,它传输数据并告诉接收者有一些事情已经发生。一条消息并不指示接收者应该做什么,而且发送者也不会等待响应。这样就实现了发送者和接收者的去耦,从而使得消息传送系统和它们的消息比请求/应答范例的动态性和灵活性更强。
一个Message对象有3个部分:消息头、消息属性和消息数据自身(也称有效负载或消息体)。消息具有不同的类型,这些类型由它们的有效负载所定义。
四、点对点消息传送模型
1、P2P模型概览
P2P模型的特性:消息通过队列进行交换、每条消息仅会传送给一个接收者、消息存在先后顺序。
P2P模型会保证只有一个消费者来处理一条指定的消息。在消息要依次分别接收处理时,要在多个JMS客户端之间均衡消息处理负载。
它提供的QueueBrower允许JMS客户端对队列进行快照,以查看正在等待被消费的消息。
P2P另一个用例是:在需要在组件之间进行同步通信,而那些组件却是用不同的编程语言编写的,或者是在不同的技术平台(如J2EE或.NET)上实现的。
使用基于消息的负载均衡,可以让服务器端的组件实现更大的吞吐量,特别对于同构组件(即Java到Java)来所更是如此。
2、QBorrower和QLender应用程序
模拟一个基于P2P请求/应答模型的贷款申请场景
3、消息关联
多个请求者同时发出请求,这就意味着发送者会向响应队列发送多条消息(接收到的信息和发送的信息可以是不同类型),既然响应队列可以包含多条消息,那么如何将接收的响应同原始消息相互关联呢?最常用的消息关联方法是将JMSCorrelationID消息头属性和JMSMessageID消息头属性结合在一起使用。
4、分析一个队列
QueueBrowser是一个专用对象,用来提前浏览Queue上的排队消息,而实际上并没有真正消费这些消息。
从QueueBrowser获得的消息是该队列中消息的副本,而且并未认为会被消费,它们仅仅是用于浏览而已。而且,QueueBrowser不能保证提供的是队列中消息的准确清单,包含的仅仅是创建QueueBrowser时队列的一个快照,或副本。
五、发布/订阅消息传送模型
1、Pub/Sub模型概览
Pub/Sub模型的特性:
① 信息通过一个称为主题的虚拟通道进行交换
② 每条信息都会传送给订阅者的多个消息消费者
③ 发布者通常不知道哪个订阅者正在接收主题消息
④ 消息被推送给消费者,消息会传送给消费者,而无须请求
⑤ 生产者和消费者没有耦合
⑥ 订阅一个主题的每个客户端都会接收到发布该主题的消息副本
发布者不会关心,或者无须担心信息将被如何使用,它只需将该信息发布给一个主题即可。
2、TBorrower和TLender应用程序
一个抵押信贷提供方发布抵押利率,而一个对最新利率感兴趣的借方则订阅了这个主题。
3、持久订阅者和非持久订阅者
只有非持久订阅者在主动侦听一个主题时(即活动的,程序处于运行状态),才会接收到消息。否则,它们就会错过这些消息。当JMS提供者接收一条消息时,提供者将为每个订阅者制作该消息的一个副本。如果订阅者不是活动的,它就不会接收该消息的副本。
持久订阅者会接收发送到该主题的所有消息,无论该订阅者活动与否。这称为“保存并转发”消息传送,类似于电子邮件系统。
持久订阅者是通过在JMS提供者中指定订阅者名称(通过配置)并使用createDurableSubscriber方法来创建的,它接受订阅名称作为参数之一:TopicSubscriber subscriber=tSession.createDurableSubscriber(topic,“Borrower1”);
六、消息过滤
1、消息选择器
①使用消息选择器,可以从一个队列或主题中过滤出特定的消息。
②消息选择器是基于SQL-92条件表达式语法的一个子集。
③它使用消息属性和消息头作为条件表达式的准则。消息选择器无法参考消息体内的数据,它只能使用消息头和消息属性。
④消息选择器由三个元素组成:标识符、常量和比较运算符。
2、消息选择器示例
在创建QueueReceiver、QueueBrowser或TopicSubscriber时,可以将消息选择器应用于消息消费者。
String selector=”CustomerType=’GOLD’OR JMSPriority BETWEEN 5 AND 9”;
QueueReceiver receiver = session.createReceiver(queue,selector);
3、两种消息过滤方式
原文地址:http://blog.163.com/nonoliuhao@126/blog/static/1716520942010112871551159/