你了解的SpringCloud核心组件有哪些?他们各有什么作用?

SpringCloud
1.什么是 Spring cloud
Spring Cloud 为最常见的分布式系统模式提供了一种简单且易于接受的编程模型,帮助开发人员构建有弹性的、可靠的、协调的应用程序。Spring Cloud 构建于 Spring Boot 之上,使得开发者很容易入手并快速应用于生产中。
以上为官方介绍。
我所理解的Spring Cloud就是微服务系统架构的一站式解决方案,在平时我们构建微服务的过程中需要做如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等操作,而 Spring Cloud 为我们提供了一套简易的编程模型,使我们能在 Spring Boot 的基础上轻松地实现微服务项目的构建。
2.Spring Cloud 的服务发现框架——Eureka([juˈriːkə])
Eureka是基于REST(代表性状态转移)的服务,主要在AWS云中用于定位服务,以实现负载均衡和中间层服务器的故障转移。我们称此服务为Eureka服务器。Eureka还带有一个基于Java的客户端组件Eureka Client,它使与服务的交互变得更加容易。客户端还具有一个内置的负载平衡器,可以执行基本的循环负载平衡。在Netflix,更复杂的负载均衡器将Eureka包装起来,以基于流量,资源使用,错误条件等多种因素提供加权负载均衡,以提供出色的弹性。
类似租房子如下:

但是这个时候还会出现一些问题:
- 房东注册之后如果不想卖房子了怎么办?我们是不是需要让房东定期续约?如果房东不进行续约是不是要将他们从中介那里的注册列表中移除。
- 租客是不是也要进行注册呢?不然合同乙方怎么来呢?
- 中介可不可以做连锁店呢?如果这一个店因为某些不可抗力因素而无法使用,那么我们是否可以换一个连锁店呢?
重构上面模式图如下:

好了,举完这个例子我们就可以来看关于 Eureka 的一些基础概念了,你会发现这东西理解起来怎么这么简单
- 服务发现:其实就是一个“中介”,整个过程中有三个角色:服务提供者(出租房子的)、服务消费者(租客)、服务中介(房屋中介)。
- 服务提供者:就是提供一些自己能够执行的一些服务给外界。
- 服务消费者:就是需要使用一些服务的“用户”。
- 服务中介:其实就是服务提供者和服务消费者之间的“桥梁”,服务提供者可以把自己注册到服务中介那里,而服务消费者如需要消费一些服务(使用一些功能)就可以在服务中介中寻找注册在服务中介的服务提供者。
- 服务注册 Register:官方解释:当 Eureka 客户端向[Eureka] Server注册时,它提供自身的元数据,比如IP地址、端口,运行状况指示符URL,主页等。(结合中介理解:房东 (提供者[Eureka] Client Provider)在中介 (服务器[Eureka] Server) 那里登记房屋的信息,比如面积,价格,地段等等(元数据metaData)。)
- 服务续约 Renew:官方解释:Eureka 客户会每隔30秒(默认情况下)发送一次心跳来续约。通过续约来告知[Eureka] Server该 Eureka 客户仍然存在,没有出现问题。正常情况下,如果[Eureka] Server在90秒没有收到 Eureka 客户的续约,它会将实例从其注册表中删除。(结合中介理解:房东 (提供者[Eureka] Client Provider) 定期告诉中介 (服务器[Eureka] Server) 我的房子还租(续约) ,中介 (服务器[Eureka] Server) 收到之后继续保留房屋的信息。)
- 获取注册列表信息 Fetch Registries:官方解释:Eureka 客户端从服务器获取注册表信息,并将其缓存在本地。客户端会使用该信息查找其他服务,从而进行远程调用。该注册列表信息定期(每30秒钟)更新一次。每次返回注册列表信息可能与 Eureka 客户端的缓存信息不同, Eureka 客户端自动处理。如果由于某种原因导致注册列表信息不能及时匹配,Eureka 客户端则会重新获取整个注册表信息。Eureka 服务器缓存注册列表信息,整个注册表以及每个应用程序的信息进行了压缩,压缩内容和没有压缩的内容完全相同。Eureka 客户端和 Eureka 服务器可以使用JSON / XML格式进行通讯。在默认的情况下 Eureka 客户端使用压缩JSON格式来获取注册列表的信息。(结合中介理解:租客(消费者[Eureka] Client Consumer) 去中介 (服务器[Eureka] Server) 那里获取所有的房屋信息列表 (客户端列表[Eureka] Client List) ,而且租客为了获取最新的信息会定期向中介 (服务器[Eureka] Server) 那里获取并更新本地列表。)
- 服务下线 Cancel:官方解释:Eureka客户端在程序关闭时向Eureka服务器发送取消请求。发送请求后,该客户端实例信息将从服务器的实例注册表中删除。该下线请求不会自动完成,它需要调用以下内容:DiscoveryManager.getInstance().shutdownComponent();(结合中介理解:房东 (提供者[Eureka] Client Provider) 告诉中介 (服务器[Eureka] Server) 我的房子不租了,中介之后就将注册的房屋信息从列表中剔除。)
- 服务剔除 Eviction:官方解释:在默认的情况下,当Eureka客户端连续90秒(3个续约周期)没有向Eureka服务器发送服务续约,即心跳,Eureka服务器会将该服务实例从服务注册列表删除,即服务剔除。(结合中介理解:房东(提供者[Eureka] Client Provider) 会定期联系 中介 (服务器[Eureka] Server) 告诉他我的房子还租(续约),如果中介 (服务器[Eureka] Server) 长时间没收到提供者的信息,那么中介会将他的房屋信息给下架(服务剔除)。)
官方Netflix给出的Eureka架构图如下:

当然,可以充当服务发现的组件有很多:Zookeeper,Consul, Eureka 等。
3.负载均衡之 Ribbon([ˈrɪbən])
3.1 什么是 RestTemplate?
RestTemplate是Spring提供的一个访问Http服务的客户端类,怎么说呢?就是微服务之间的调用是使用的RestTemplate。比如这个时候我们 消费者B 需要调用 提供者A 所提供的服务我们就需要这么写。
@Autowired
private RestTemplate restTemplate;private static final String SERVICE_PROVIDER_A = "http://localhost:8081";@PostMapping("/judge")
public boolean judge(@RequestBody Request request){String url = SERVICE_PROVIDER_A + "/service1";return restTemplate.postForObject(url,request,Boolean.class);
}
如果你对源码感兴趣的话,你会发现上面我们所讲的 Eureka 框架中的注册、续约等,底层都是使用的RestTemplate。
3.2 为什么需要 Ribbon?
Ribbon 是Netflix公司的一个开源的负载均衡 项目,是一个客户端/进程内负载均衡器,运行在消费者端。
我们再举个例子,比如我们设计了一个秒杀系统,但是为了整个系统的高可用,我们需要将这个系统做一个集群,而这个时候我们消费者就可以拥有多个秒杀系统的调用途径了,如下图。

如果这个时候我们没有进行一些均衡操作,如果我们对秒杀系统1进行大量的调用,而另外两个基本不请求,就会导致秒杀系统1崩溃,而另外两个就变成了傀儡,那么我们为什么还要做集群,我们高可用体现的意义又在哪呢?
所以Ribbon出现了,注意我们上面加粗的几个字——运行在消费者端。指的是,Ribbon是运行在消费者端的负载均衡器,如下图。

其工作原理就是Consumer端获取到了所有的服务列表之后,在其内部使用负载均衡算法,进行对多个系统的调用。
3.3 Nginx 和 Ribbon 的对比
提到负载均衡就不得不提到大名鼎鼎的Nignx了,而和Ribbon不同的是,它是一种集中式的负载均衡器。
何为集中式呢?简单理解就是将所有请求都集中起来,然后再进行负载均衡。如下图。

我们可以看到Nginx是接收了所有的请求进行负载均衡的,而对于Ribbon来说它是在消费者端进行的负载均衡。如下图。

请注意Request的位置,在Nginx中请求是先进入负载均衡器,而在Ribbon中是先在客户端进行负载均衡才进行请求的。
3.4 Ribbon 的几种负载均衡算法
负载均衡,不管Nginx还是Ribbon都需要其算法的支持,如果我没记错的话Nginx使用的是 轮询和加权轮询算法。而在Ribbon中有更多的负载均衡调度算法,其默认是使用的RoundRobinRule轮询策略。
- Round-Robin Rule:轮询策略。Ribbon默认采用的策略。若经过一轮轮询没有找到可用的provider,其最多轮询 10 轮。若最终还没有找到,则返回 null。
- Random Rule:随机策略,从所有可用的 provider 中随机选择一个。
- Retry Rule:重试策略。先按照 RoundRobinRule 策略获取 provider,若获取失败,则在指定的时限内重试。默认的时限为 500 毫秒。
你最需要知道的是默认轮询算法,并且可以更换默认的负载均衡算法,只需要在配置文件中做出修改就行:
providerName:ribbon:NFLoadBalancerRuleClassName:com.netflix.loadbalancer.RandomRule
当然,在Ribbon中你还可以自定义负载均衡算法,你只需要实现IRule接口,然后修改配置文件或者自定义Java Config类。
4.什么是 Open Feign
有了 Eureka,RestTemplate,Ribbon我们就可以😃愉快地进行服务间的调用了,但是使用RestTemplate还是不方便,我们每次都要进行这样的调用。
@Autowired
private RestTemplate restTemplate;
// 这里是提供者A的ip地址,但是如果使用了 Eureka 那么就应该是提供者A的名称
private static final String SERVICE_PROVIDER_A = "http://localhost:8081";@PostMapping("/judge")
public boolean judge(@RequestBody Request request) {String url = SERVICE_PROVIDER_A + "/service1";// 是不是太麻烦了???每次都要 url、请求、返回类型的return restTemplate.postForObject(url, request, Boolean.class);
}
这样每次都调用RestRemplate的API是否太麻烦,我能不能像调用原来代码一样进行各个服务间的调用呢?
那就用映射呀,就像域名和IP地址的映射。我们可以将被调用的服务代码映射到消费者端,这样我们就可以“无缝开发”啦。
OpenFeign 也是运行在消费者端的,使用 Ribbon 进行负载均衡,所以 OpenFeign 直接内置了 Ribbon。
在导入了Open Feign之后我们就可以进行愉快编写 Consumer端代码了。
// 使用 @FeignClient 注解来指定提供者的名字
@FeignClient(value = "eureka-client-provider")
public interface TestClient {// 这里一定要注意需要使用的是提供者那端的请求相对路径,这里就相当于映射了@RequestMapping(value = "/provider/xxx",method = RequestMethod.POST)CommonResponse<List<Plan>> getPlans(@RequestBody planGetRequest request);
}
然后我们在Controller就可以像原来调用Service层代码一样调用它了。
@RestController
public class TestController {// 这里就相当于原来自动注入的 Service@Autowiredprivate TestClient testClient;// controller 调用 service 层代码@RequestMapping(value = "/test", method = RequestMethod.POST)public CommonResponse<List<Plan>> get(@RequestBody planGetRequest request) {return testClient.getPlans(request);}
}
5.必不可少的 Hystrix([hɪst’rɪks])
5.1 什么是 Hystrix之熔断和降级
在分布式环境中,不可避免地会有许多服务依赖项中的某些失败。Hystrix是一个库,可通过添加等待时间容限和容错逻辑来帮助您控制这些分布式服务之间的交互。Hystrix通过隔离服务之间的访问点,停止服务之间的级联故障并提供后备选项来实现此目的,所有这些都可以提高系统的整体弹性。
总体来说[Hystrix]就是一个能进行熔断和降级的库,通过使用它能提高整个系统的弹性。
那么什么是 熔断和降级 呢?再举个例子,此时我们整个微服务系统是这样的。服务A调用了服务B,服务B再调用了服务C,但是因为某些原因,服务C顶不住了,这个时候大量请求会在服务C阻塞。

服务C阻塞了还好,毕竟只是一个系统崩溃了。但是请注意这个时候因为服务C不能返回响应,那么服务B调用服务C的的请求就会阻塞,同理服务B阻塞了,那么服务A也会阻塞崩溃。
请注意,为什么阻塞会崩溃。因为这些请求会消耗占用系统的线程、IO 等资源,消耗完你这个系统服务器不就崩了么。

这就叫服务雪崩。
所谓熔断就是服务雪崩的一种有效解决方案。当指定时间窗内的请求失败率达到设定阈值时,系统将通过断路器直接将此请求链路断开。
也就是我们上面服务B调用服务C在指定时间窗内,调用的失败率到达了一定的值,那么[Hystrix]则会自动将 服务B与C 之间的请求都断了,以免导致服务雪崩现象。
其实这里所讲的熔断就是指的[Hystrix]中的断路器模式,你可以使用简单的@[Hystrix]Command注解来标注某个方法,这样[Hystrix]就会使用断路器来“包装”这个方法,每当调用时间超过指定时间时(默认为1000ms),断路器将会中断对这个方法的调用。
当然你可以对这个注解的很多属性进行设置,比如设置超时时间,像这样。
@HystrixCommand(commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "1200")}
)
public List<Xxx> getXxxx() {// ...省略代码逻辑
}
但是,我查阅了一些博客,发现他们都将熔断和降级的概念混淆了,以我的理解,降级是为了更好的用户体验,当一个方法调用异常时,通过执行另一种代码逻辑来给用户友好的回复。这也就对应着[Hystrix]的后备处理模式。你可以通过设置fallbackMethod来给一个方法设置备用的代码逻辑。比如这个时候有一个热点新闻出现了,我们会推荐给用户查看详情,然后用户会通过id去查询新闻的详情,但是因为这条新闻太火了(比如最近什么*易对吧),大量用户同时访问可能会导致系统崩溃,那么我们就进行服务降级,一些请求会做一些降级处理比如当前人数太多请稍后查看等等。
// 指定了后备方法调用
@HystrixCommand(fallbackMethod = "getHystrixNews")
@GetMapping("/get/news")
public News getNews(@PathVariable("id") int id) {// 调用新闻系统的获取新闻api 代码逻辑省略
}
//
public News getHystrixNews(@PathVariable("id") int id) {// 做服务降级// 返回当前人数太多,请稍后查看
}
6.微服务网关——Zuul
ZUUL 是从设备和 web 站点到 Netflix 流应用后端的所有请求的前门。作为边界服务应用,ZUUL 是为了实现动态路由、监视、弹性和安全性而构建的。它还具有根据情况将请求路由到多个 Amazon Auto Scaling Groups(亚马逊自动缩放组,亚马逊的一种云计算方式) 的能力。
- 动态路由
- 监视
- 弹性
- 安全性
在上面我们学习了 Eureka 之后我们知道了服务提供者是消费者通过[Eureka] Server进行访问的,即[Eureka] Server是服务提供者的统一入口。那么整个应用中存在那么多消费者需要用户进行调用,这个时候用户该怎样访问这些消费者工程呢?当然可以像之前那样直接访问这些工程。但这种方式没有统一的消费者工程调用入口,不便于访问与管理,而 Zuul 就是这样的一个对于消费者的统一入口。
如果学过前端的肯定都知道 Router 吧,比如 Flutter 中的路由,Vue,React中的路由,用了 Zuul 你会发现在路由功能方面和前端配置路由基本是一个理。
大家对网关应该很熟吧,简单来讲网关是系统唯一对外的入口,介于客户端与服务器端之间,用于对请求进行鉴权、限流、路由、监控等功能。
- 鉴权
- 限流
- 路由
- 监控

没错,网关有的功能,Zuul基本都有。而Zuul中最关键的就是路由和过滤器了,在官方文档中Zuul的标题就是
Router and Filter : Zuul
6.1 Zuul 的路由功能
6.1.1 简单配置
比如这个时候我们已经向[Eureka] Server注册了两个Consumer、三个Provicer,这个时候我们再加个Zuul网关应该变成这样子了。

首先,Zuul需要向 Eureka 进行注册,注册有啥好处呢?
Consumer都向[Eureka] Server进行注册了,我网关是不是只要注册就能拿到所有Consumer的信息了?
拿到信息有什么好处呢?
我拿到信息我是不是可以获取所有的Consumer的元数据(名称,ip,端口)?
拿到这些元数据有什么好处呢?拿到了我们是不是直接可以做路由映射?比如原来用户调用Consumer1的接口localhost:8001/studentInfo/update这个请求,我们是不是可以这样进行调用了呢?localhost:9000/consumer1/studentInfo/update呢?你这样是不是恍然大悟了?
上面的你理解了,那么就能理解关于Zuul最基本的配置了,看下面。
server:port: 9000
eureka:client:service-url:# 这里只要注册 Eureka 就行了defaultZone: http://localhost:9997/eureka
然后在启动类上加入@EnableZuulProxy注解就行了。没错,就是那么简单
6.1.2 统一前缀
这个很简单,就是我们可以在前面加一个统一的前缀,比如我们刚刚调用的是localhost:9000/consumer1/studentInfo/update,这个时候我们在yaml配置文件中添加如下。
zuul:prefix: /zuul
这样我们就需要通过localhost:9000/zuul/consumer1/studentInfo/update来进行访问了。
6.1.3 路由策略配置
你会发现前面的访问方式(直接使用服务名),需要将微服务名称暴露给用户,会存在安全性问题。所以,可以自定义路径来替代微服务名称,即自定义路由策略。
zuul:routes:consumer1: /FrancisQ1/**consumer2: /FrancisQ2/**
这个时候你就可以使用localhost:9000/zuul/FrancisQ1/studentInfo/update进行访问了。
6.1.4 服务名屏蔽
这个时候你别以为你好了,你可以试试,在你配置完路由策略之后使用微服务名称还是可以访问的,这个时候你需要将服务名屏蔽。
zuul:ignore-services: "*"
6.1.5 路径屏蔽
Zuul还可以指定屏蔽掉的路径 URI,即只要用户请求中包含指定的 URI 路径,那么该请求将无法访问到指定的服务。通过该方式可以限制用户的权限。
zuul:ignore-patterns: **/auto/**
这样关于 auto 的请求我们就可以过滤掉了。
** 代表匹配多级任意路径
*代表匹配一级任意路径
6.1.6 敏感请求头屏蔽
默认情况下,像 Cookie、Set-Cookie 等敏感请求头信息会被 zuul 屏蔽掉,我们可以将这些默认屏蔽去掉,当然,也可以添加要屏蔽的请求头。
6.2 Zuul 的过滤功能
如果说,路由功能是Zuul的基操的话,那么过滤器就是Zuul的利器了。毕竟所有请求都经过网关(Zuul),那么我们可以进行各种过滤,这样我们就能实现限流,灰度发布,权限控制等等。
6.2.1 简单实现一个请求时间日志打印
要实现自己定义的Filter我们只需要继承ZuulFilter然后将这个过滤器类以@Component注解加入 Spring 容器中就行了。
在给你们看代码之前我先给你们解释一下关于过滤器的一些注意点。

过滤器类型:
- Pre:前置Pre就是在请求之前进行过滤。
- Routing:Routing路由过滤器就是我们上面所讲的路由策略。
- Post:而Post后置过滤器就是在Response之前进行过滤的过滤器。
// 加入Spring容器
@Component
public class PreRequestFilter extends ZuulFilter {// 返回过滤器类型 这里是前置过滤器@Overridepublic String filterType() {return FilterConstants.PRE_TYPE;}// 指定过滤顺序 越小越先执行,这里第一个执行// 当然不是只真正第一个 在Zuul内置中有其他过滤器会先执行// 那是写死的 比如 SERVLET_DETECTION_FILTER_ORDER = -3@Overridepublic int filterOrder() {return 0;}// 什么时候该进行过滤// 这里我们可以进行一些判断,这样我们就可以过滤掉一些不符合规定的请求等等@Overridepublic boolean shouldFilter() {return true;}// 如果过滤器允许通过则怎么进行处理@Overridepublic Object run() throws ZuulException {// 这里我设置了全局的RequestContext并记录了请求开始时间RequestContext ctx = RequestContext.getCurrentContext();ctx.set("startTime", System.currentTimeMillis());return null;}
}// lombok的日志
@Slf4j
// 加入 Spring 容器
@Component
public class AccessLogFilter extends ZuulFilter {// 指定该过滤器的过滤类型// 此时是后置过滤器@Overridepublic String filterType() {return FilterConstants.POST_TYPE;}// SEND_RESPONSE_FILTER_ORDER 是最后一个过滤器// 我们此过滤器在它之前执行@Overridepublic int filterOrder() {return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 1;}@Overridepublic boolean shouldFilter() {return true;}// 过滤时执行的策略@Overridepublic Object run() throws ZuulException {RequestContext context = RequestContext.getCurrentContext();HttpServletRequest request = context.getRequest();// 从RequestContext获取原先的开始时间 并通过它计算整个时间间隔Long startTime = (Long) context.get("startTime");// 这里我可以获取HttpServletRequest来获取URI并且打印出来String uri = request.getRequestURI();long duration = System.currentTimeMillis() - startTime;log.info("uri: " + uri + ", duration: " + duration / 100 + "ms");return null;}
}
上面就简单实现了请求时间日志打印功能,你有没有感受到Zuul过滤功能的强大了呢?
6.2.2 令牌桶限流
当然不仅仅是令牌桶限流方式,Zuul只要是限流的活它都能干,这里我只是简单举个例子。

我先来解释一下什么是令牌桶限流吧。
首先我们会有个桶,如果里面没有满那么就会以一定固定的速率会往里面放令牌,一个请求过来首先要从桶中获取令牌,如果没有获取到,那么这个请求就拒绝,如果获取到那么就放行。
下面我们就通过Zuul的前置过滤器来实现一下令牌桶限流。
@Component
@Slf4j
public class RouteFilter extends ZuulFilter {// 定义一个令牌桶,每秒产生2个令牌,即每秒最多处理2个请求private static final RateLimiter RATE_LIMITER = RateLimiter.create(2);@Overridepublic String filterType() {return FilterConstants.PRE_TYPE;}@Overridepublic int filterOrder() {return -5;}@Overridepublic Object run() throws ZuulException {log.info("放行");return null;}@Overridepublic boolean shouldFilter() {RequestContext context = RequestContext.getCurrentContext();if(!RATE_LIMITER.tryAcquire()) {log.warn("访问量超载");// 指定当前请求未通过过滤context.setSendZuulResponse(false);// 向客户端返回响应码429,请求数量过多context.setResponseStatusCode(429);return false;}return true;}
}
这样我们就能将请求数量控制在一秒两个,有没有觉得很酷?
6.2.3 关于 Zuul的其他
Zuul的过滤器的功能肯定不止上面我所实现的两种,它还可以实现权限校验,包括我上面提到的灰度发布等等。
当然,Zuul作为网关肯定也存在单点问题,如果我们要保证Zuul的高可用,我们就需要进行Zuul的集群配置,这个时候可以借助额外的一些负载均衡器比如Nginx。
7.Spring Cloud配置管理——Config
7.1 为什么要使用进行配置管理?
当我们的微服务系统开始慢慢地庞大起来,那么多Consumer、Provider、[Eureka] Server、Zuul系统都会持有自己的配置,这个时候我们在项目运行的时候可能需要更改某些应用的配置,如果我们不进行配置的统一管理,我们只能去每个应用下一个一个寻找配置文件然后修改配置文件再重启应用。
首先对于分布式系统而言我们就不应该去每个应用下去分别修改配置文件,再者对于重启应用来说,服务无法访问所以直接抛弃了可用性,这是我们更不愿见到的。
那么有没有一种方法既能对配置文件统一地进行管理,又能在项目运行时动态修改配置文件呢?
那就是我今天所要介绍的Spring Cloud Config。
能进行配置管理的框架不止Spring Cloud Config一种,大家可以根据需求自己选择(disconf,阿波罗等等)。而且对于Config来说有些地方实现的不是那么尽人意。
7.2 Config 是什么
Spring Cloud Config为分布式系统中的外部化配置提供服务器和客户端支持。使用Config服务器,可以在中心位置管理所有环境中应用程序的外部属性。
简单来说,Spring Cloud Config就是能将各个 应用/系统/模块 的配置文件存放到统一的地方然后进行管理(Git 或者 SVN)。
你想一下,我们的应用是不是只有启动的时候才会进行配置文件的加载,那么我们的Spring Cloud Config就暴露出一个接口给启动应用来获取它所想要的配置文件,应用获取到配置文件然后再进行它的初始化工作。就如下图。

一般我们会使用Bus消息总线 +Spring Cloud Config进行配置的动态刷新。
7.3 引出 Spring Cloud Bus
用于将服务和服务实例与分布式消息系统链接在一起的事件总线。在集群中传播状态更改很有用(例如配置更改事件)。
你可以简单理解为Spring Cloud Bus的作用就是管理和广播分布式系统中的消息,也就是消息引擎系统中的广播模式。当然作为消息总线的Spring Cloud Bus可以做很多事而不仅仅是客户端的配置刷新功能。
而拥有了Spring Cloud Bus之后,我们只需要创建一个简单的请求,并且加上@ResfreshScope注解就能进行配置的动态修改了,下面我画了张图供你理解。

8.总结
Spring Cloud的各个组件:
- Eureka 服务发现框架
- Ribbon 进程内负载均衡器
- Open Feign 服务调用映射
- Hystrix 服务降级熔断器
- Zuul 微服务网关
- Config 微服务统一配置中心
- Bus 消息总线
相关文章:
你了解的SpringCloud核心组件有哪些?他们各有什么作用?
SpringCloud 1.什么是 Spring cloud Spring Cloud 为最常见的分布式系统模式提供了一种简单且易于接受的编程模型,帮助开发人员构建有弹性的、可靠的、协调的应用程序。Spring Cloud 构建于 Spring Boot 之上,使得开发者很容易入手并快速应用于生产中。…...
【Gradle-10】不可忽视的构建分析
1、前言 构建性能对于生产力至关重要。 随着项目越来越复杂,花费在构建上的时间就越长,开发效率就越低。 通过分析构建过程,可以了解项目构建的时间都花在哪,以及项目存在哪些潜在的问题,找到构建瓶颈,解…...
2034. 股票价格波动
给你一支股票价格的数据流。数据流中每一条记录包含一个 时间戳 和该时间点股票对应的 价格 。 不巧的是,由于股票市场内在的波动性,股票价格记录可能不是按时间顺序到来的。某些情况下,有的记录可能是错的。如果两个有相同时间戳的记录出现…...
JavaScript 事件详解细节
JavaScript 事件详解细节 JavaScript 中的事件是前端开发中非常重要的一个概念。通过事件,我们可以捕捉和响应用户与网页的交互,比如点击按钮、输入文字等。这篇博客文章将详细介绍 JavaScript 中的事件,希望能帮助你更好地理解和使用这一功…...
【MySQL】事务管理
目录 MySQL事务管理 事务的概念 事务的版本支持 事务的提交方式 事务的相关演示 事务的隔离级别 查看与设置隔离级别 读未提交(Read Uncommitted) 读提交(Read Committed) 可重复读(Repeatable Read…...
Git 学习笔记 | Git 基本操作命令
Git 学习笔记 | Git 基本操作命令 Git 学习笔记 | Git 基本操作命令文件的四种状态查看文件状态忽略文件 Git 学习笔记 | Git 基本操作命令 文件的四种状态 版本控制就是对文件的版本控制,要对文件进行修改、提交等操作,首先要知道文件当前在什么状态&…...
第五章:最新版零基础学习 PYTHON 教程—Python 字符串操作指南(第七节 - Python 中的字符串模板类)
在字符串模块中,模板类允许我们为输出规范创建简化的语法。该格式使用由 $ 和有效 Python 标识符(字母数字字符和下划线)组成的占位符名称。用大括号将占位符括起来,使其后面可以跟更多的字母数字字母,且中间不留空格。写入 $$ 会创建一个转义的 $。 Python 字符串模板:…...
第八章 排序 十四、最佳归并树
目录 一、定义 二、多路最佳归并树 三、多路最佳归并树少了一个归并段 四、总结 一、定义 最佳归并树是指将若干个有序序列合并成一个有序序列的一种方式,使得所有合并操作的总代价最小的一棵二叉树。其中,代价通常指合并两个有序序列的操作次数或比…...
Python 中,类的方法的标准注释模板
在 Python 中,类的标准注释通常遵循以下格式: class 类名:"""类的简要描述属性:- 属性1 (类型): 属性1的描述- 属性2 (类型): 属性2的描述方法:- 方法1(): 方法1的描述- 方法2(): 方法2的描述示例:>>> 对象 类名()>>>…...
IPSG技术和IP组播
1,IPSG技术概述 实验: DHCP snooping IPSG 拓扑: 需求: 1,实现PC1 和PC2 动态获取IP地址 2, 在SW2 配置DHCP snooping 实现DHCP 服务器的安全 3, 在 连接PC 1 和 PC2 的 接口上 做IPSG ,防止终端…...
【大数据】Apache NiFi 助力数据处理及分发
Apache NiFi 助力数据处理及分发 1.什么是 NiFi ?2.NiFi 的核心概念3.NiFi 的架构4.NiFi 的性能预期和特点5.NiFi 关键特性的高级概览 1.什么是 NiFi ? 简单的说,NiFi 就是为了解决不同系统间数据自动流通问题而建立的。虽然 dataflow 这个术…...
什么是 SRE?一文详解 SRE 运维体系
目录 可观测性系统 故障响应 故障复盘 测试与发布 容量规划 自动化工具开发 用户体验 可观测性系统 在任何有一定规模的企业内部,一旦推行起来整个SRE的运维模式,那么对于可观测性系统的建设将变得尤为重要,而在整个可观测性系统中&a…...
【Docker】初识 Docker,Docker 基本命令的使用,Dockerfile 自定义镜像的创建
文章目录 前言:项目部署的挑战一、初识 Docker1.1 什么是 Docker1.2 Docker 与 虚拟机的区别1.3 镜像和容器以及镜像托管平台1.4 Docker的架构解析1.5 Docker 在 CentOS 中的安装 二、Docker 的基本操作2.1 操作 Docker 镜像命令2.1.1 镜像操作相关命令2.1.2 示例一…...
【Docker】简易版harbor部署
文章目录 依赖于docker-compose下载添加执行权限测试 安装harbor下载解压修改配置文件部署配置开机自启动登录验证 使用harbor登录打标签上传下载 常见问题 依赖于docker-compose 下载 curl -L “https://github.com/docker/compose/releases/download/2.22.0/docker-compose-…...
Zookeeper经典应用场景实战(一)
文章目录 1、Zookeeper Java客户端实战1.1、 Zookeeper 原生Java客户端使用1.2、 Curator开源客户端使用 2、 Zookeeper在分布式命名服务中的实战2.1、 分布式API目录2.2、 分布式节点的命名2.3、 分布式的ID生成器 3、Zookeeper实现分布式队列3.1、 设计思路3.2、 使用Apache …...
Chrome报错:Unchecked runtime.lastError
项目背景、安装了 Express 框架,目的是为了快速创建一个web服务器。创建成功后,控制台出现了报错,而在这之前没有出现过这个错误,所以一直在纠结是不是框架本身的问题。 错误原因:这个错误一般是浏览器与扩展或者插件…...
【算法】算法设计与分析 课程笔记 第三章 动态规划
1.1 动态规划简介 1.1.1 引例 动态规划算法和分治法类似,基本思想也是将待求解问题分解成若干个子问题,子问题可以以继续拆分,直到问题规模达到临界条件即可。多说无益,举个例子来解释一下: 这其实是一个多阶段图求最…...
贪心找性质+dp表示+矩阵表示+线段树维护:CF573D
比较套路的题目 首先肯定贪心一波,两个都排序后尽量相连。我一开始猜最多跨1,但其实最多跨2,考虑3个人的情况: 我们发现第3个人没了,所以可以出现跨2的情况 然后直接上dp,由 i − 1 , i − 2 , i − 3 i…...
小谈设计模式(17)—状态模式
小谈设计模式(17)—状态模式 专栏介绍专栏地址专栏介绍 状态模式关键角色上下文(Context)抽象状态(State)具体状态(Concrete State) 核心思想Java程序实现首先,我们定义一个抽象状态类 State,其中包含一个处理请求的方法 handleRe…...
Arm64体系架构-MPIDR_EL1寄存器
背景 在Arm64多核处理器中, 各核间的关系可能不同. 比如1个16 core的cpu, 每4个core划分为1个cluster,共享L2 cache. 当我们需要从core 0将任务调度出来时,如果优先选择core 1~3, 那么性能明显时优于其他core的. 那么操作系统怎么知道core之间这样的拓扑信息呢? Arm提供了MPID…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
Mac下Android Studio扫描根目录卡死问题记录
环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?
在工业自动化持续演进的今天,通信网络的角色正变得愈发关键。 2025年6月6日,为期三天的华南国际工业博览会在深圳国际会展中心(宝安)圆满落幕。作为国内工业通信领域的技术型企业,光路科技(Fiberroad&…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
命令行关闭Windows防火墙
命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)方法二:CMD命令…...
