spring-cloud-bus.md 11.2 KB
Newer Older
茶陵後's avatar
茶陵後 已提交
1
# Spring Cloud 总线
茶陵後's avatar
茶陵後 已提交
2

茶陵後's avatar
茶陵後 已提交
3
Spring Cloud总线将分布式系统的节点与轻量级消息代理连接起来。然后可以使用此代理来广播状态更改(例如配置更改)或其他管理指令。一个关键的想法是,总线就像是 Spring 启动应用程序的分布式执行器,该应用程序是按比例扩展的。然而,它也可以用作应用程序之间的沟通渠道。该项目为 AMQP 代理或 Kafka 提供了作为传输的启动器。
茶陵後's avatar
茶陵後 已提交
4

茶陵後's avatar
茶陵後 已提交
5
|   |Spring Cloud是在非限制性的 Apache2.0 许可下发布的。如果你想对文档的这一部分做出贡献,或者你发现了一个错误,请在[github](https://github.com/spring-cloud/spring-cloud-bus)的项目中找到源代码和问题追踪器。|
茶陵後's avatar
茶陵後 已提交
6 7
|---|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

茶陵後's avatar
茶陵後 已提交
8
## [](#quick-start)[1.快速启动](#quick-start)
茶陵後's avatar
茶陵後 已提交
9

茶陵後's avatar
茶陵後 已提交
10
Spring Cloud总线的工作原理是,如果在 Classpath 上检测到自身,则添加 Spring 引导自动配置。要启用总线,请将`spring-cloud-starter-bus-amqp``spring-cloud-starter-bus-kafka`添加到依赖项管理中。 Spring 剩下的事由云来解决。确保代理(RabbitMQ 或 Kafka)可用并进行了配置。在 LocalHost 上运行时,你不需要做任何事情。如果远程运行,请使用 Spring Cloud Connectors 或 Spring Boot 约定来定义代理凭据,如下面的 Rabbit 示例所示:
茶陵後's avatar
茶陵後 已提交
11 12 13 14 15 16 17 18 19 20 21 22

应用程序.yml

```
spring:
  rabbitmq:
    host: mybroker.com
    port: 5672
    username: user
    password: secret
```

茶陵後's avatar
茶陵後 已提交
23
总线目前支持将消息发送到监听的所有节点或特定服务的所有节点(由 Eureka 定义)。执行器名称空间`/bus/*`具有一些 HTTP 端点。目前,有两个项目已经实施。第一种是`/bus/env`,它发送键/值对来更新每个节点的 Spring 环境。第二种是`/bus/refresh`,重新加载每个应用程序的配置,就好像它们都在其`/refresh`端点上被 pinged 了一样。
茶陵後's avatar
茶陵後 已提交
24

茶陵後's avatar
茶陵後 已提交
25
|   |Spring Cloud总线启动器覆盖 Rabbit 和 Kafka,因为这是两个最<br/>的常见实现。然而, Spring Cloud流是相当灵活的,并且活页夹<br/>`spring-cloud-bus`一起工作。|
茶陵後's avatar
茶陵後 已提交
26 27 28 29
|---|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

## [](#bus-endpoints)[2.总线端点](#bus-endpoints)

茶陵後's avatar
茶陵後 已提交
30
Spring Cloud Bus 提供了两个端点,`/actuator/busrefresh``/actuator/busenv`,它们分别对应于 Spring Cloud Commons 中的单个执行器端点,`/actuator/refresh``/actuator/env`
茶陵後's avatar
茶陵後 已提交
31 32 33

### [](#bus-refresh-endpoint)[2.1.总线刷新端点](#bus-refresh-endpoint)

茶陵後's avatar
茶陵後 已提交
34
`/actuator/busrefresh`端点清除`RefreshScope`缓存并重新绑定`@ConfigurationProperties`。有关更多信息,请参见[刷新范围](#refresh-scope)文档。
茶陵後's avatar
茶陵後 已提交
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

要公开`/actuator/busrefresh`端点,需要向应用程序添加以下配置:

```
management.endpoints.web.exposure.include=busrefresh
```

### [](#bus-env-endpoint)[2.2.总线 ENV 端点](#bus-env-endpoint)

`/actuator/busenv`端点使用跨多个实例的指定键/值对更新每个实例环境。

要公开`/actuator/busenv`端点,需要向应用程序添加以下配置:

```
management.endpoints.web.exposure.include=busenv
```

`/actuator/busenv`端点接受具有以下形状的`POST`请求:

```
{
    "name": "key1",
    "value": "value1"
}
```

## [](#addressing-an-instance)[3.寻址实例](#addressing-an-instance)

茶陵後's avatar
茶陵後 已提交
63
应用程序的每个实例都有一个服务 ID,其值可以用`spring.cloud.bus.id`设置,其值应该是一个以冒号分隔的标识符列表,顺序从最不特定到最特定。默认值是作为`spring.application.name``server.port`(或`spring.application.index`,如果设置)的组合从环境构造的。ID 的默认值以`app:index:id`的形式构造,其中:
茶陵後's avatar
茶陵後 已提交
64 65 66

* `app``vcap.application.name`,如果它存在,或者`spring.application.name`

茶陵後's avatar
茶陵後 已提交
67
* `index``vcap.application.instance_index`,如果存在,`spring.application.index``local.server.port``server.port`,或`0`(按此顺序排列)。
茶陵後's avatar
茶陵後 已提交
68 69 70

* `id``vcap.application.instance_id`,如果它存在,或者是一个随机值。

茶陵後's avatar
茶陵後 已提交
71
HTTP 端点接受一个“destination”路径参数,例如`/busrefresh/customers:9000`,其中`destination`是一个服务 ID。如果 ID 由总线上的一个实例拥有,那么它将处理消息,而所有其他实例将忽略它。
茶陵後's avatar
茶陵後 已提交
72 73 74

## [](#addressing-all-instances-of-a-service)[4.处理服务的所有实例](#addressing-all-instances-of-a-service)

茶陵後's avatar
茶陵後 已提交
75
在 Spring `PathMatcher`(路径分隔符为冒号—`:`)中使用“destination”参数来确定实例是否处理消息。使用前面的示例,`/busenv/customers:**`以“客户”服务的所有实例为目标,而不考虑服务 ID 的其余部分。
茶陵後's avatar
茶陵後 已提交
76 77 78

## [](#service-id-must-be-unique)[5.服务 ID 必须是唯一的](#service-id-must-be-unique)

茶陵後's avatar
茶陵後 已提交
79
总线尝试两次消除处理一个事件——一次来自原始`ApplicationEvent`,一次来自队列。为此,它会根据当前的服务 ID 检查发送服务 ID。如果一个服务的多个实例具有相同的 ID,则不会对事件进行处理。当在本地机器上运行时,每个服务都位于不同的端口上,而该端口是 ID 的一部分。Cloud Foundry 提供了一个用于区分的索引。要确保 ID 在 Cloud Foundry 之外是唯一的,请将`spring.application.index`设置为服务的每个实例都是唯一的。
茶陵後's avatar
茶陵後 已提交
80 81 82

## [](#customizing-the-message-broker)[6.自定义消息代理](#customizing-the-message-broker)

茶陵後's avatar
茶陵後 已提交
83
Spring Cloud总线使用[Spring Cloud Stream](https://cloud.spring.io/spring-cloud-stream)来广播消息。因此,要使消息流起来,你只需要在 Classpath 中包含你选择的绑定器实现。对于具有 AMQP 和 Kafka(`spring-cloud-starter-bus-[amqp|kafka]`)的总线,有方便的启动器。一般来说, Spring Cloud Stream 依赖于 Spring Boot AutoConfiguration 约定来配置中间件。例如,可以使用`spring.rabbitmq.*`配置属性更改 AMQP 代理地址。 Spring Cloud Bus 在`spring.cloud.bus.*`中具有少量的本机配置属性(例如,`spring.cloud.bus.destination`是用作外部中间件的主题的名称)。通常情况下,默认值就足够了。
茶陵後's avatar
茶陵後 已提交
84

茶陵後's avatar
茶陵後 已提交
85
要了解有关如何自定义消息代理设置的更多信息,请参阅 Spring Cloud Stream 文档。
茶陵後's avatar
茶陵後 已提交
86 87 88

## [](#tracing-bus-events)[7.追踪总线事件](#tracing-bus-events)

茶陵後's avatar
茶陵後 已提交
89
总线事件(`RemoteApplicationEvent`的子类)可以通过设置`spring.cloud.bus.trace.enabled=true`来跟踪。如果这样做, Spring boot`TraceRepository`(如果存在)将显示发送的每个事件和来自每个服务实例的所有 ACK。以下示例来自`/trace`端点:
茶陵後's avatar
茶陵後 已提交
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123

```
{
  "timestamp": "2015-11-26T10:24:44.411+0000",
  "info": {
    "signal": "spring.cloud.bus.ack",
    "type": "RefreshRemoteApplicationEvent",
    "id": "c4d374b7-58ea-4928-a312-31984def293b",
    "origin": "stores:8081",
    "destination": "*:**"
  }
  },
  {
  "timestamp": "2015-11-26T10:24:41.864+0000",
  "info": {
    "signal": "spring.cloud.bus.sent",
    "type": "RefreshRemoteApplicationEvent",
    "id": "c4d374b7-58ea-4928-a312-31984def293b",
    "origin": "customers:9000",
    "destination": "*:**"
  }
  },
  {
  "timestamp": "2015-11-26T10:24:41.862+0000",
  "info": {
    "signal": "spring.cloud.bus.ack",
    "type": "RefreshRemoteApplicationEvent",
    "id": "c4d374b7-58ea-4928-a312-31984def293b",
    "origin": "customers:9000",
    "destination": "*:**"
  }
}
```

茶陵後's avatar
茶陵後 已提交
124
前面的跟踪显示,一个`RefreshRemoteApplicationEvent``customers:9000`发送,广播到所有服务,并由`customers:9000``stores:8081`接收。
茶陵後's avatar
茶陵後 已提交
125

茶陵後's avatar
茶陵後 已提交
126
要自己处理 ACK 信号,可以在应用程序中添加`@EventListener``SentApplicationEvent`类型的`@EventListener`(并启用跟踪)。或者,你可以利用`TraceRepository`并从那里挖掘数据。
茶陵後's avatar
茶陵後 已提交
127 128 129 130 131 132

|   |任何总线应用程序都可以跟踪 ACK。然而,有时,在可以对数据执行更复杂的<br/>查询或将其转发给专门的跟踪服务的中心服务中执行此操作是很有用的。|
|---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|

## [](#broadcasting-your-own-events)[8.播放自己的活动](#broadcasting-your-own-events)

茶陵後's avatar
茶陵後 已提交
133
总线可以承载类型`RemoteApplicationEvent`的任何事件。默认传输是 JSON,反序列化器需要提前知道要使用哪些类型。要注册一个新类型,必须将其放入`org.springframework.cloud.bus.event`的子包中。
茶陵後's avatar
茶陵後 已提交
134 135 136 137 138 139 140 141

要自定义事件名,你可以在自定义类上使用`@JsonTypeName`,也可以使用默认策略,即使用类的简单名称。

|   |生产者和消费者都需要访问类定义。|
|---|-----------------------------------------------------------------------|

### [](#registering-events-in-custom-packages)[8.1.在自定义包中注册事件](#registering-events-in-custom-packages)

茶陵後's avatar
茶陵後 已提交
142
如果你不能或不想使用`org.springframework.cloud.bus.event`的子包来表示你的自定义事件,那么你必须指定要使用`RemoteApplicationEvent`注释来扫描类型为`@RemoteApplicationEventScan`的事件的包。用`@RemoteApplicationEventScan`指定的包包括子包。
茶陵後's avatar
茶陵後 已提交
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165

例如,考虑以下自定义事件,称为`MyEvent`:

```
package com.acme;

public class MyEvent extends RemoteApplicationEvent {
    ...
}
```

你可以通过以下方式向反序列化器注册该事件:

```
package com.acme;

@Configuration
@RemoteApplicationEventScan
public class BusConfiguration {
    ...
}
```

茶陵後's avatar
茶陵後 已提交
166
在不指定值的情况下,注册了使用`@RemoteApplicationEventScan`的类的包。在本例中,`com.acme`通过使用`BusConfiguration`的包进行注册。
茶陵後's avatar
茶陵後 已提交
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181

还可以在`@RemoteApplicationEventScan`上使用`value``basePackages``basePackageClasses`属性显式地指定要扫描的包,如以下示例所示:

```
package com.acme;

@Configuration
//@RemoteApplicationEventScan({"com.acme", "foo.bar"})
//@RemoteApplicationEventScan(basePackages = {"com.acme", "foo.bar", "fizz.buzz"})
@RemoteApplicationEventScan(basePackageClasses = BusConfiguration.class)
public class BusConfiguration {
    ...
}
```

茶陵後's avatar
茶陵後 已提交
182
前面的`@RemoteApplicationEventScan`的所有示例都是等效的,因为`com.acme`包是通过在`@RemoteApplicationEventScan`上显式指定包来注册的。
茶陵後's avatar
茶陵後 已提交
183 184 185 186 187 188 189

|   |你可以指定要扫描的多个基包。|
|---|-----------------------------------------------|

## [](#configuration-properties)[9.配置属性](#configuration-properties)

要查看所有与总线相关的配置属性的列表,请检查[附录页](appendix.html)
茶陵後's avatar
茶陵後 已提交
190 191

如果{{{i[’GoogleAnalyticsObject’]=r;i[r]=i[r]|function(){q=i[r].push(参数)},i[r].l=1\*new date();a=s.createElement(o),m=s.getelementsbyName(0);a.parentsName(1);a.A.SRC=g;m.M.analytnode(gua,m.com.com);(google=document=’,’,’’’’’’’’),’documents’,’’.’’’’’’’’’’’,’’’’’’