Spring Cloud Bus将轻量级消息代理程序链接到分布式系统的节点。 然后可以使用此代理来广播状态更改(例如配置更改)或其他管理指令。 一个关键思想是,总线就像是横向扩展的Spring Boot应用程序的分布式执行器。 但是,它也可以用作应用之间的通信渠道。 目前实现依赖 AMQP broker或者Kafka 。

1.快速开始

如果Spring Cloud Bus在类路径中检测到自身,则通过添加Spring Boot autconfiguration来工作。 要启用总线,请将spring-cloud-starter-bus-amqp或spring-cloud-starter-bus-kafka添加到您的依赖项管理中。 Spring Cloud负责其余的工作。 确保代理(RabbitMQ或Kafka)可用并且已配置。 在本地主机上运行时,您无需执行任何操作。 如果您是远程运行,请使用Spring Cloud Connectors或Spring Boot约定定义代理凭据,如Rabbit的以下示例所示:

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

总线当前支持向所有侦听节点或特定服务的所有节点发送消息(由Eureka定义)。 / bus / *执行器名称空间具有一些HTTP端点。 当前,有两个已实现。 第一个/ bus / env发送键/值对以更新每个节点的Spring Environment。 第二个/ bus / refresh重新加载每个应用程序的配置,就好像它们都已在/ refresh端点上被ping一样。

注:Spring Cloud Bus入门文章涵盖Rabbit和Kafka,因为它们是两个最常见的实现。 但是,Spring Cloud Stream非常灵活,并且绑定程序可与spring-cloud-bus一起使用。

2.Bus Endpoints

Spring Cloud Bus提供了两个端点/ actuator / bus-refresh和/ actuator / bus-env,它们分别对应于Spring Cloud Commons中的各个执行器端点/ actuator / refresh和/ actuator / env。

2.1Bus Refresh Endpoint

/ actuator / bus-refresh端点清除RefreshScope缓存并重新绑定@ConfigurationProperties。 有关更多信息,请参见Refresh Scope文档。

要公开/ actuator / bus-refresh终结点,您需要在应用程序中添加以下配置:

management.endpoints.web.exposure.include=bus-refresh
1
management.endpoints.web.exposure.include=bus-refresh

2.2. Bus Env Endpoint

/ actuator / bus-env端点使用多个实例之间的指定键/值对更新每个实例环境。要公开/ actuator / bus-env端点,您需要向应用程序添加以下配置:

management.endpoints.web.exposure.include=bus-env
1
management.endpoints.web.exposure.include=bus-env
/ actuator / bus-env端点接受具有以下形状的POST请求:
{
"name": "key1",
"value": "value1"
}
{
"name":"key1",
"value":"value1"
}

3.寻址实例

应用程序的每个实例都有一个服务ID,可以使用spring.cloud.bus.id设置其值,并且其值应按冒号分隔的标识符列表(从最小到最具体)排列。 默认值是根据环境构造的,它是spring.application.name和server.port(或spring.application.index,如果设置)的组合。 ID的默认值以app:index:id的形式构造,其中:

app是vcap.application.name(如果存在),或者spring.application.name

index是vcap.application.instance_index(如果存在),spring.application.index,local.server.port,server.port或0(按此顺序)。

id是vcap.application.instance_id(如果存在)或随机值。

HTTP端点接受“目的地”路径参数,例如/ bus-refresh / customers:9000,其中destination是服务ID。 如果该ID由总线上的一个实例拥有,它将处理该消息,而所有其他实例将忽略它。

4.处理服务的所有实例

“目标”参数在Spring PathMatcher中使用(路径分隔符为冒号-:),用于确定实例是否处理消息。 使用前面的示例,/ bus-env / customers:**定位“ customers”服务的所有实例,而与其余服务ID无关。

5.Service ID必须唯一

总线尝试两次以消除对事件的处理-从原始ApplicationEvent一次,从队列一次。 为此,它将对照当前服务ID检查发送Service ID。 如果服务的多个实例具有相同的ID,则不会处理事件。 在本地计算机上运行时,每个服务都在不同的端口上,并且该端口是ID的一部分。 Cloud Foundry提供了一个区分索引。 为了确保ID在Cloud Foundry之外是唯一的,请将spring.application.index设置为每个服务实例唯一的名称。

6.自定义消息代理

Spring Cloud Bus使用Spring Cloud Stream广播消息。 因此,要使消息流动,您只需要在类路径中包括您选择的活页夹实现即可。 带有AMQP(RabbitMQ)和Kafka(spring-cloud-starter-bus- [amqp | kafka])的总线有方便的启动器。 一般来说,Spring Cloud Stream依赖于Spring Boot自动配置约定来配置中间件。 例如,可以使用spring.rabbitmq。配置属性来更改AMQP代理地址。 Spring Cloud Bus在spring.cloud.bus。中具有少数本机配置属性(例如,spring.cloud.bus.destination是用作外部中间件的主题的名称)。 通常,默认值即可满足。要了解有关如何自定义消息代理设置的更多信息,请参阅Spring Cloud Stream文档。

7.Tracing Bus Events

可以通过设置spring.cloud.bus.trace.enabled = true来跟踪总线事件(RemoteApplicationEvent的子类)。 如果这样做,Spring Boot TraceRepository(如果存在)将显示发送的每个事件以及每个服务实例的所有确认。 以下示例来自/ trace端点:

{
"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": "*:**"
}
}


{
"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":"*:**"
}
}

上面的跟踪显示了RefreshRemoteApplicationEvent是从customers:9000发送的,广播到所有服务,并由customers:9000和stores:8081接收(确认)的。

要自己处理确认信号,您可以为应用程序的AckRemoteApplicationEvent和SentApplicationEvent类型添加一个@EventListener(并启用跟踪)。 或者,您可以进入TraceRepository并从那里挖掘数据。

任何Bus应用程序都可以跟踪acks。 但是,有时,在中央服务中执行此操作很有用,该服务可以对数据进行更复杂的查询,或将其转发给专门的跟踪服务。

8.广播自己的事件

总线可以携带RemoteApplicationEvent类型的任何事件。 默认的传输方式是JSON,解串器需要提前知道将要使用哪些类型。 要注册新类型,必须将其放入org.springframework.cloud.bus.event的子包中。

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

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

8.1在自定义包中注册事件

如果您不能或不想使用org.springframework.cloud.bus.event的子包作为自定义事件,则必须使用@RemoteApplicationEventScan批注指定要扫描哪些包的RemoteApplicationEvent类型的事件。 用@RemoteApplicationEventScan指定的包包括子包。

示例,考虑以下自定义事件,MyEvent:

package com.acme;
public class MyEvent extends RemoteApplicationEvent {
...
packagecom.acme;
publicclassMyEventextendsRemoteApplicationEvent{
...
}

您可以通过以下方式在解串器中注册该事件:

package com.acme;
@Configuration
@RemoteApplicationEventScan
public class BusConfiguration {
...
}


packagecom.acme;
@Configuration
@RemoteApplicationEventScan
publicclassBusConfiguration{
...
}

不指定值,将注册使用@RemoteApplicationEventScan的类的包。 在此示例中,使用BusConfiguration包注册了com.acme。

您还可以通过使用@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 {
...
packagecom.acme;
@Configuration
//@RemoteApplicationEventScan({"com.acme", "foo.bar"})
//@RemoteApplicationEventScan(basePackages = {"com.acme", "foo.bar", "fizz.buzz"})
@RemoteApplicationEventScan(basePackageClasses=BusConfiguration.class)
publicclassBusConfiguration{
...
}

@RemoteApplicationEventScan的所有前述示例都是等效的,因为com.acme软件包是通过在@RemoteApplicationEventScan上显式指定软件包来注册的。

您可以指定多个要扫描的基本软件包。

9.配置属性

可以在application.properties文件内,application.yml文件内或作为命令行开关指定各种属性。 本附录提供了常见的Spring Cloud Bus属性列表以及使用它们的基础类的引用。

属性贡献可能来自类路径上的其他jar文件,因此您不应将其视为详尽的列表。 另外,您可以定义自己的属性。

NameDefaultDescriptionspring.cloud.bus.ack.destination-service要监听确认的服务 。 默认情况下为null(表示所有服务)。

spring.cloud.bus.ack.enabledtrue标记以关闭(默认为打开)。

spring.cloud.bus.destinationspringCloudBus消息的Spring Cloud Stream目标名称。

spring.cloud.bus.enabledtrue指示启用总线的标志。

spring.cloud.bus.env.enabledtrue标记以关闭环境更改事件(默认为打开)。

spring.cloud.bus.idapplication该应用程序实例的标识符。

spring.cloud.bus.refresh.enabledtrue标记以关闭刷新事件(默认为打开)。

spring.cloud.bus.trace.enabledfalse标记以打开跟踪(默认关闭)。