spring cloud的client详解:SpringCloudBus使用说明详解
spring cloud的client详解:SpringCloudBus使用说明详解访问Controller接口,查看数据是否更新,分别调用serviceA和serviceB两个接口@Autowired private EnvironmentManager env ; @GetMapping("/index") public Object index() { return "akf = " env.getProperty("akf") ; }调用接口:/mgr/bus-env分别启动serviceA,serviceB,注册中心如下:RabbitMQ会自动创建一个用于消息传递的队列,该队列是排他的,只要有一个服务创建了其它的就不会创建,且是自动删除的,如果服务关闭队列会自动删除。任意调用其中一个服务的/mgr/bus-env接口,以POST的方式传递key/value数据即可。
环境:Springboot2.3.12.RELEASE Spring Cloud Hoxton.SR12 Spring Cloud Alibaba 2.2.5.RELEASE
简介
Spring Cloud Bus通过一个轻量级消息代理将分布式系统的节点连接起来。然后使用该代理来广播状态更改(例如配置更改)或其他管理指令。一个关键的想法是,总线就像一个分布式执行器,用于按比例扩展的Spring Boot应用程序。不过,它也可以用作应用程序之间的通信通道。该项目提供了对应AMQP 或 Kafka 的starter 作为传输的工具。
环境配置新建两个工程serviceA,serviceB
<properties>
<spring-cloud.version>Hoxton.SR12</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
server:
port: 9100
---
spring:
cloud:
nacos:
username: dev
password: 123456
discovery:
enabled: true
serverAddr: localhost:8848
namespace: 7205e694-ac51-4ac1-bbe9-87c28689b88a
---
spring:
application:
name: serviceA
---
spring:
RabbitMQ:
host: localhost
virtual-host: bus
port: 5672
username: xxx
password: xxx
---
management:
server:
port: 8888
endpoint:
health:
show-details: always
shutdown:
enabled: true
endpoints:
web:
basePath: /mgr
exposure:
include: '*' #暴露所有的Endpoint
serviceB的配置修改端口和spring.application.name 其它的都一样。
分别启动serviceA,serviceB,注册中心如下:
RabbitMQ会自动创建一个用于消息传递的队列,该队列是排他的,只要有一个服务创建了其它的就不会创建,且是自动删除的,如果服务关闭队列会自动删除。
Bus Env端点的应用任意调用其中一个服务的/mgr/bus-env接口,以POST的方式传递key/value数据即可。
@Autowired
private EnvironmentManager env ;
@GetMapping("/index")
public Object index() {
return "akf = " env.getProperty("akf") ;
}
调用接口:/mgr/bus-env
访问Controller接口,查看数据是否更新,分别调用serviceA和serviceB两个接口
serviceA
serviceB
实现原理:
public class BusAutoConfiguration implements ApplicationEventPublisherAware {
protected static class BusEnvironmentConfiguration {
// 事件监听器,专门用来处理EnvironmentChangeRemoteApplicationEvent事件
@Bean
@ConditionalOnProperty(value = "spring.cloud.bus.env.enabled" matchIfMissing = true)
public EnvironmentChangeListener environmentChangeListener() {
return new EnvironmentChangeListener();
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Endpoint.class)
protected static class EnvironmentBusEndpointConfiguration {
@Bean
@ConditionalOnAvailableEndpoint
// 注册acutator端点
public EnvironmentBusEndpoint environmentBusEndpoint(ApplicationContext context BusProperties bus) {
return new EnvironmentBusEndpoint(context bus.getId());
}
}
}
}
// bus-env端点定义
@Endpoint(id = "bus-env") // TODO: document
public class EnvironmentBusEndpoint extends AbstractBusEndpoint {
@WriteOperation
public void busEnv(String name String value) { // TODO: document params
Map<String String> params = Collections.singletonMap(name value);
// 当调用/actuator/bus-env接口的时候会执行这里发布事件
publish(new EnvironmentChangeRemoteApplicationEvent(this getInstanceId() null params));
}
}
// 处理EnvironmentChangeRemoteApplicationEvent事件
public class EnvironmentChangeListener implements ApplicationListener<EnvironmentChangeRemoteApplicationEvent> {
@Autowired
private EnvironmentManager env;
@Override
public void onApplicationEvent(EnvironmentChangeRemoteApplicationEvent event) {
Map<String String> values = event.getValues();
// 将数据添加到ENV中
for (Map.Entry<String String> entry : values.entrySet()) {
this.env.setProperty(entry.getKey() entry.getValue());
}
}
}
Bus Refresh 端点的应用
/actuator/busrefresh端点清除RefreshScope缓存并重新绑定@ConfigurationProperties。
在使用Nacos作为配置中心时,对于使用@ConfigurationProperties注解的类是无需手动调用/busrefresh接口进行刷新,系统会自动的刷新配置:
引入依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
建立bootstrap.yml
spring:
cloud:
nacos:
config:
username: dev
password: 123456
enabled: true
serverAddr: localhost:8848
fileExtension: properties #
group: HisGroup
namespace: 7205e694-ac51-4ac1-bbe9-87c28689b88a
timeout: 6000
shared-configs:
- dataId: redis.properties
group: common
refresh: true
nacos新建配置
应用配置类
@Component
@ConfigurationProperties(prefix="redis")
public class RedisConfig {
private String host ;
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
}
}
接口测试
@Resource
private RedisConfig redis ;
@GetMapping("/redis")
public Object redis() {
return "redis = " redis.getHost() ;
}
只要在nacos中修改了配置,这里的信息都会实时的更新。
将上面的RedisConfig修改如下:
@Component
public class RedisConfig {
@Value("${redis.host}")
private String host ;
}
去掉了@ConfigurationProperties注解
这时候在nacos中的配置,发现这个的配置信息不能够实时的更新。
接着做如下修改:
@Component
@RefreshScope
public class RedisConfig {
@Value("${redis.host}")
private String host ;
}
添加了@RefreshScope注解,再次修改nacos配置,信息得到了实时的更新。
关于RefreshScope的实现原理查看《SpringCloud @RefreshScope实现原理原来这么简单?》
Bus Refresh实现原理:
public class BusRefreshAutoConfiguration {
@Bean
@ConditionalOnProperty(value = "spring.cloud.bus.refresh.enabled" matchIfMissing = true)
@ConditionalOnBean(ContextRefresher.class)
public RefreshListener refreshListener(ContextRefresher contextRefresher ServiceMatcher serviceMatcher) {
return new RefreshListener(contextRefresher serviceMatcher);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(name = { "org.springframework.boot.actuate.endpoint.annotation.Endpoint" "org.springframework.cloud.context.scope.refresh.RefreshScope" })
protected static class BusRefreshEndpointConfiguration {
@Bean
@ConditionalOnAvailableEndpoint
// 注册BusRefresh端点
public RefreshBusEndpoint refreshBusEndpoint(ApplicationContext context BusProperties bus) {
return new RefreshBusEndpoint(context bus.getId());
}
}
}
@Endpoint(id = "bus-refresh") // TODO: document new id
public class RefreshBusEndpoint extends AbstractBusEndpoint {
@WriteOperation
// 注册刷新的事件,事件的处理是由上面的RefreshListener监听器处理
public void busRefresh() {
publish(new RefreshRemoteApplicationEvent(this getInstanceId() null));
}
}
在RefreshListener监听器中的核心就是调用ContextRefresher#refresh方法。
这里使用了Nacos后这个Bus就不需要了。
如果还是用于原始的Spring Cloud Config那么这个还是必须的(很久没有使用config了,应该没有变把)。
Bus ID应用每个实例都有一个服务ID,其值可以用spring.cloud.bus.id设置,其值应该是一个以冒号分隔的标识符列表。默认值规则为:app:index:id
- app:如果存在vcap.application.name 取该值,否则 spring.application.name
- index:如果存在vcap.application.instance_index 取该值 否则按照下面的顺序spring.application.index local.server.port server.port。
- id: 如果存在vcap.application.instance_id 否则生成随机值。
该spring.cloud.bus.id 有何用?
当执行:http://xxxx:port/mgr/bus-refresh 端点时会刷新所有的服务。如果执行下面接口:
http://xxxx:port/mgr/bus-refresh/serviceA:9100 那么只会刷新serviceA配置信息。其它的会被忽略。
也可以使用通配符的方式:
http://xxxx:port/mgr/bus-env/serviceA:**
完毕!!!
求个关注
Spring Cloud Sentinel 基础配置
Spring Cloud Sentinel 熔断降级
Spring Cloud Sentinel 流控限流
Spring Cloud Nacos 开启权限验证
Spring Cloud Gateway应用详解1之谓词
在Spring Cloud 中你还在使用Ribbon快来试试Load-Balancer
SpringCloud Nacos 整合feign
SpringCloud Alibaba 之 Nacos 服务
Spring Cloud Sentinel整合Feign
Spring Cloud 中断路器 Circuit Breaker的应用