像RMI、Hessian、Burlap、HTTP invoker和Web这些服务,在应用程序之间进行通信的机制都是同步的,客户端应用程序直接与远程服务相交互,并且一直等到远程过程完成后才能继续执行。同步通信有它自己适应的场景。
这种通信方式(同步)不是应用程序之间进行交互的唯一方式,异步消息是一个应用程序向另一个应用程序间接发送消息的一种方式,这种方式无需等待对方的响应。
若远程调用机制为同步的,当客户端调用远程方法时,客户端必须等到远程方法完成后,才能继续执行。即远程方法不向客户端返回任何信息,客户端也要被阻塞直到服务完成。
若远程调用机制为异步的,客户端不需要等待服务处理消息,甚至不需要等待消息投递完成。客户端发送消息,然后继续执行,这是因为客户端假定服务最终可以收到并处理这条信息。
1、异步消息简介
在异步消息中有两个主要的概念:消息代理(message broker)和目的地(destination)。当一个应用发送消息时,会将消息交给一个消息代理。消息代理类似于一个邮局。消息代理可以确保消息被投递到指定的目的地,同时解放发送者,使其能够继续进行其他的业务。
当我们通过邮局邮递信件时,最重要的是写上地址,这样邮局就可以知道这封信应该被投递到哪里。与此类似,每条异步信息都带有一个目的地,目的地就好像一个邮箱,可以将消息放入这个邮箱,直到有人将他们取走。
但是,并不像信件地址那样必须标识特定的收件人或街道地址,消息的目的地相对来说并不那么具体。目的地只关注消息应该从哪里获得----而不关心是由谁取走消息的。这种情况下,目的地就如同信件的地址为“本地居民”。
尽管不同的消息系统会提供不同的消息路由模式,但是有两种通用的目的地:队列(queue)和主题(topic)。每种主题都与特定的消息模型相关联,分别是点对点模型(队列) 和发布/订阅模型(主题)。
点对点消息模型
在点对点模型中,每一条消息都有一个发送者和接收者,如图所示。当消息代理得到消息时,他将消息放入一个队列中。当接收者请求队列中的下一条消息时,消息会从队列中取出,并投递给接收者。因为该消息被投递后会从队列中删除,这样就可以保证消息只能投递给一个接受者。
尽管消息队列中的每一条消息只被投递给一个接收者,但是它并不意味着只能使用一个接收者从队列中获取消息。事实上,通常可以使用几个接收者来处理队列中的消息。不过,每个接收者都会处理自己所接收到的消息。
如果有多个接收者监听队列,我们也无法知道某条特定的消息会由哪一个接收者处理。这种不确定性实际上有很多好处,因为我们只需要简单地为队列添加新的监听器就能提高应用的消息处理能力。
发布----订阅消息模型
在发布----订阅消息模型中,消息会发送给一个主题。与队列相似,多个接收者都可以监听一个主题。但是,与队列不同的是,消息不再是只传递给一个接收者,而是主题的所有订阅者都会接收到此消息的副本,如图所示:
2、评估异步消息的优点
无需等待:当使用JMS发送消息时,客户端不必等待消息被处理,甚至被投递。客户端只需要将消息发送给消息代理,就可以确信消息被投递给相应的目的地。
面向消息和解耦:发送异步信息是以数据为中心的,这就意味着客户端并没有与特定的方法签名绑定。任何可以处理数据的队列或主题订阅者都可以处理由客户端发送的信息,而客户端不必了解远程服务的任何规范。
位置独立:消息客户端不必知道谁会处理它们的消息,或者服务的位置在哪。客户端只需要了解需要通过那个队列或主题来发送消息。因此,只要服务能够从队列或主题中获取消息即可,消息客户端根本不需要关注服务来自哪里。
确保投递:为了使客户端可以与同步服务通信,服务必须监听指定的IP地址和端口号。如果服务崩了,或者由于某种原因无法使用了,客户端将不再继续处理。但是,当发送异步消息时,客户端可以完全相信信息被投递,即使在消息发送时,服务无法使用,消息也会被存储起来,直到服务重新可以使用为止。
3、使用JMS发送消息
Java消息服务(Java Message Service)是一个Java标准,定义了使用消息代理的通用API。在JMS出现之前,每个消息代理都有私有的API,这就使得不同代理之间的消息代码很难通用。
Spring通过基于模板的抽象为JMS功能提供了支持,这个模板就是JmsTemplate。使用JmsTemplate,能够非常容易地在消息生产方发送队列和主题消息,在消费消息的那一方,也能够非常容易地接收这些消息。Spring还提供了了消息驱动POJO的理念:这是 一个简单的Java对象,它能够以异步的方式响应队列或主题上到达的消息。