> For the complete documentation index, see [llms.txt](https://potoyang.gitbook.io/spring-in-action-v4/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://potoyang.gitbook.io/spring-in-action-v4/untitled-10/untitled-3/untitled.md).

# 17.1.2　评估异步消息的优点

虽然同步通信比较容易理解，建立起来也很简单，但是采用同步通信机制访问远程服务的客户端存在几个限制，最主要的是：

* 同步通信意味着等待。当客户端调用远程服务的方法时，它必须等待远程方法结束后才能继续执行。如果客户端与远程服务频繁通信，或者远程服务响应很慢，就会对客户端应用的性能带来负面影响。
* 客户端通过服务接口与远程服务相耦合。如果服务的接口发生变化，此服务的所有客户端都需要做相应的改变。
* 客户端与远程服务的位置耦合。客户端必须配置服务的网络位置，这样它才知道如何与远程服务进行交互。如果网络拓扑进行调整，客户端也需要重新配置新的网络位置。
* 客户端与服务的可用性相耦合。如果远程服务不可用，客户端实际上也无法正常运行。

虽然同步通信仍然有它的适用场景，但是在决定应用程序更适合哪种通信机制时，我们必须考量以上的这些缺点。如果这些限制正是你所担心的，那你可能很想知道异步通信是如何解决这些问题的。

**无需等待**

当使用 JMS 发送消息时，客户端不必等待消息被处理，甚至是被投递。客户端只需要将消息发送给消息代理，就可以确信消息会被投递给相应的目的地。 因为不需要等待，所以客户端可以继续执行其他任务。这种方式可以有效地节省时间，所以客户端的性能能够极大的提高。

**面向消息和解耦**

与面向方法调用的 RPC 通信不同，发送异步消息是以数据为中心的。这意味着客户端并没有与特定的方法签名绑定。任何可以处理数据的队列或主题订阅者都可以处理由客户端发送的消息，而客户端不必了解远程服务的任何规范。

**位置独立**

同步 RPC 服务通常需要网络地址来定位。这意味着客户端无法灵活地适应网络拓扑的改变。如果服务的 IP 地址改变了，或者服务被配置为监听其他端口，客户端必须进行相应的调整，否则无法访问服务。

与之相反，消息客户端不必知道谁会处理它们的消息，或者服务的位置在哪里。客户端只需要了解需要通过哪个队列或主题来发送消息。因此，只要服务能够从队列或主题中获取消息即可，消息客户端根本 不需要关注服务来自哪里。

在点对点模型中，可以利用这种位置的独立性来创建服务的集群。如果客户端不知道服务的位置，并且服务的唯一要求就是可以访问消息代理，那么我们就可以配置多个服务从同一个队列中接收消息。如果服务过载，处理能力不足，我们只需要添加一些新的服务实例来监听相同的队列就可以了。

在发布-订阅模型中，位置独立性会产生另一种有趣的效应。多个服务可以订阅同一个主题，接收相同消息的副本。但是每一个服务对消息的处理逻辑却可能有所不同。例如，假设我们有一组服务可以共同处理描述新员工信息的消息。一个服务可能会在工资系统中增加该员工，另一个服务则会将新员工增加到 HR 门户中，同时还有一个服务 为新员工分配可访问系统的权限。每一个服务都基于相同的数据（都 是从同一个主题接收的），但各自进行独立的处理。

**确保投递**

为了使客户端可以与同步服务通信，服务必须监听指定的 IP 地址和端口。如果服务崩溃了，或者由于某种原因无法使用了，客户端将不能继续处理。

但是，当发送异步消息时，客户端完全可以相信消息会被投递。即使在消息发送时，服务无法使用，消息也会被存储起来，直到服务重新可以使用为止。

现在，我们已经对异步消息的基础知识有所了解，接下来看一下如何将其付诸实施。首先，我们会使用 JMS 来发送和接收消息。
