• 白话SpringCloud | 第四章:服务消费者(RestTemple+Ribbon+Feign)


    前言

    上两章节,介绍了下关于注册中心-Eureka的使用及高可用的配置示例,本章节开始,来介绍下服务和服务之间如何进行服务调用的,同时会讲解下几种不同方式的服务调用。

    一点知识

    SpringCloud体系中,我们知道服务之间的调用是通过http协议进行调用的。而注册中心的主要目的就是维护这些服务的服务列表。我们知道,在Spring中,提供了RestTemplateRestTemplateSpring提供的用于访问Rest服务的客户端。而在SpringCloud中也是使用此服务进行服务调用的。

    同时在微服务中,一般上服务都不会进行单点部署的,都会至少部署2台及以上的。现在我们有了注册中心进行服务列表的维护,就需要一个客户端负载均衡来进行动态服务的调用。

    所以开始示例前,我们先来大致了解下关于负载均衡RestTemplate的相关知识点。其实后面实例的RibbonFeign最后的调用都是基于RestTemplate的。使用比较简单~

    何为负载均衡

    负载均衡(Load Balance)是分布式系统架构设计中必须考虑的因素之一,它通常是指,将请求/数据【均匀】分摊到多个操作单元上执行,负载均衡的关键在于【均匀】。

    实现的方式

    实现负载均衡的方式有很多种,这里简单介绍下几种方式,并未过多深入。

    注意:以下部分内容转至几种负载均衡技术的实现

    1.HTTP重定向负载均衡

    根据用户的http请求计算出一个真实的web服务器地址,并将该web服务器地址写入http重定向响应中返回给浏览器,由浏览器重新进行访问

    HTTP重定向

    优缺点:实现起来很简单,而缺点也显而易见了:请求两次才能完成一次访问;性能差;重定向服务器会成为瓶颈

    2.DNS域名解析负载均衡

    在DNS服务器上配置多个域名对应IP的记录。例如一个域名www.baidu.com对应一组web服务器IP地址,域名解析时经过DNS服务器的算法将一个域名请求分配到合适的真实服务器上。

    DNS域名解析

    优缺点:加快访问速度,改善性能。同时由于DNS解析是多级解析,每一级DNS都可能化缓存记录A,当某一服务器下线后,该服务器对应的DNS记录A可能仍然存在,导致分配到该服务器的用户访问失败,而且DNS负载均衡采用的是简单的轮询算法,不能区分服务器之间的差异,不能反映服务器当前运行状态。

    3.反向代理负载均衡

    反向代理处于web服务器这边,反向代理服务器提供负载均衡的功能,同时管理一组web服务器,它根据负载均衡算法将请求的浏览器访问转发到不同的web服务器处理,处理结果经过反向服务器返回给浏览器。

    优缺点:实现简单,可利用反向代理缓存资源(这是最常用的了)及改善网站性能。同时因为是所有请求和响应的中转站,所以反向代理服务器可能成为瓶颈。


    以上仅仅是部分实现方式,还有比如IP负载均衡数据链路层负载均衡等等,这些可能涉及到相关网络方面的知识点了,不是很了解,大家有兴趣可以自行搜索下吧。


    客户端和服务端的负载均衡

    实现负载均衡也又区分客户端和服务端之分,Ribbon就是基于客户端的负载均衡。
    客户端负载均衡:

    客户端负载均衡

    服务端负载均衡:

    服务端负载均衡

    服务端实现负载均衡方式有很多,比如:硬件F5NginxHA Proxy等等,这些应该实施相关人员应该比较熟悉了,本人可能也就对Nginx了解下,⊙﹏⊙‖∣

    RestTemplate简单介绍

    RestTemplateSpring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。

    简单来说,RestTemplate采用了模版设计的设计模式,将过程中与特定实现相关的部分委托给接口,而这个接口的不同实现定义了接口的不同行为,所以可以很容易的使用不同的第三方http服务,如okHttphttpclient等。

    RestTemplate定义了很多的与REST资源交互,这里简单介绍下一些常用的请求方式的使用。

    exchange

    在URL上执行特定的HTTP方法,返回包含对象的ResponseEntity。其他的如GETPOST等方法底层都是基于此方法的。

    exchange

    如:

    • get请求
    RequestEntity requestEntity = RequestEntity.get(new URI(uri)).build();
    ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class);
    
    • post请求
    RequestEntity<User> requestEntity = RequestEntity.post(new URI(uri)).body(user);
    ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class);
    

    GET请求

    get请求可以分为两类:getForEntity()getForObject().

    GET请求

    // 1-getForObject()
    User user1 = this.restTemplate.getForObject(uri, User.class);
    
    // 2-getForEntity()
    ResponseEntity<User> responseEntity1 = this.restTemplate.getForEntity(uri, User.class);
    HttpStatus statusCode = responseEntity1.getStatusCode();
    HttpHeaders header = responseEntity1.getHeaders();
    User user2 = responseEntity1.getBody();
    

    其他的方法都大同小异了,可以根据实际的业务需求进行调用。

    POST请求

    POST请求

    简单示例:

    // 1-postForObject()
    User user1 = this.restTemplate.postForObject(uri, user, User.class);
    
    // 2-postForEntity()
    ResponseEntity<User> responseEntity1 = this.restTemplate.postForEntity(uri, user, User.class);
    
    

    关于postForLocation(),用的比较少,作用是返回新创建资源的URI,前面介绍的两者是返回资源本身,也就是结果集了。


    关于其他的请求类型相关用法,这里就不详细阐述了,都是类似的。可以查看下此文章:详解 RestTemplate 操作,讲的蛮详细了。


    特别说明:系列教程为了方便,github上分别创建了一个单体的Eureka注册中心和高可用的Eureka注册中心,无特殊说明,都是使用单体的Eureka注册中心进行服务注册与发现的,工程名为:spring-cloud-eureka-server,端口号为:1000。服务提供方工程名为:spring-cloud-eureka-client,应用名称为:eureka-client,端口号为:2000,提供了一个接口:http://127.0.0.1:2000/hello

    spring-cloud-eureka-client接口列表

    spring-cloud-eureka-server示例:spring-cloud-eureka-server

    spring-cloud-eureka-client示例:spring-cloud-eureka-client


    LoadBalancerClient实例

    此类是实现客户端负载均衡的关键。本身它是个接口类,位于spring-cloud-commons包下,此包包含了大量的服务治理相关的抽象接口,比如已经介绍过的DiscoveryClientServiceRegistry以及LoadBalancerClient实例等等。

    spring-cloud-common

    首先,我们使用最原生的方式去获取调用服务接口。

    创建个工程:spring-cloud-eureka-consumer

    0.引入pom文件依赖。

    <!-- 客户端依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    

    1.配置文件添加相关注册中心等信息。

    ## 服务名称
    spring.application.name=eureka-consumer
    ## 端口号
    server.port=8008
    
    #指定注册中心地址
    eureka.client.service-url.defaultZone=http://127.0.0.1:1000/eureka
    # 启用ip配置 这样在注册中心列表中看见的是以ip+端口呈现的
    eureka.instance.prefer-ip-address=true
    # 实例名称  最后呈现地址:ip:2000
    eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
    

    2.编写启动类,加入@EnableDiscoveryClient,申明为一个客户端应用,同时申明一个RestTemplate,最后是使用RestTemplate来完成rest服务调用的。

    @SpringBootApplication
    @EnableDiscoveryClient
    @Slf4j
    public class EurekaConsumerApplication {
    
        public static void main(String[] args) throws Exception {
            SpringApplication.run(EurekaConsumerApplication.class, args);
            log.info("spring-cloud-eureka-consumer启动!");
        }
        
        @Bean 
        public RestTemplate restTemplate() { 
            return new RestTemplate(); 
        }     
    }
    

    3.编写一个调用类,调用spring-cloud-eureka-client服务提供者提供的服务。

    /**
     * 访问客户端示例
     * @author oKong
     *
     */
    @RestController
    @Slf4j
    public class DemoController {
    
        @Autowired
        LoadBalancerClient loadBalancerClient;
        
        @Autowired 
        RestTemplate restTemplate;
        
        @GetMapping("/hello") 
        public String hello(String name) {
            ServiceInstance serviceInstance = loadBalancerClient.choose("eureka-client");
            String url = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/hello?name=" + name;
            log.info("url地址为:{}", url);
            return restTemplate.getForObject(url, String.class);
        } 
    }
    

    4.启动应用,访问:http://127.0.0.1:8008/hell0?name=oKong ,可以看见控制台输出了利用LoadBalancerClientchoose方法,获取到了对应eureka-client服务ID的服务地址。

    eureka-client服务实例

    最后通过范围对应的http地址进行服务请求:

    url地址

    最后浏览器上可以看见,进行了正确的访问了:

    hello

    此时,切换到服务提供者spring-cloud-eureka-client控制台,可以看见日志输出:
    spring-cloud-eureka-client控制台

    此时我们已经调用成功了,通过LoadBalancerClient获取到了服务提供者实际服务地址,最后进行调用。

    大家可以创建多个的spring-cloud-eureka-client服务提供者,再去调用下,可以看见会调用不同的服务地址的。

    客户端负载均衡Ribbon实例

    Spring Cloud Ribbon是一个基于Http和TCP的客服端负载均衡工具,它是基于Netflix Ribbon实现的。与Eureka配合使用时,Ribbon可自动从Eureka Server (注册中心)获取服务提供者地址列表,并基于负载均衡算法,通过在客户端中配置ribbonServerList来设置服务端列表去轮询访问以达到均衡负载的作用。

    Ribbon

    上小节,简单的使用LoadBalancerClient进行了服务实例获取最后调用,也说了其实LoadBalancerClient是个接口类。而Ribbon实现了此接口,对应实现类为:RibbonLoadBalancerClient.

    RibbonLoadBalancerClient

    Ribbon实例

    现在我们来看下,使用Ribbon的方式如何进行更加优雅的方式进行服务调用。

    创建一个工程:spring-cloud-eureka-consumer-ribbon
    (其实这个工程和spring-cloud-eureka-consumer是差不多的,只是有些许不同。)

    0.加入pom依赖

    <!-- 客户端依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    

    1.配置文件修改,添加注册中心等相关信息。

    spring.application.name=eureka-consumer-ribbon
    server.port=8018
    
    #指定注册中心地址
    eureka.client.service-url.defaultZone=http://127.0.0.1:1000/eureka
    # 启用ip配置 这样在注册中心列表中看见的是以ip+端口呈现的
    eureka.instance.prefer-ip-address=true
    # 实例名称  最后呈现地址:ip:2000
    eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
    

    2.编写启动类,加入@EnableDiscoveryClient,同时申明一个RestTemplate这里和原先不同,就在于加入了@LoadBalanced注解进行修饰RestTemplate类,稍后会大致讲解下是如何进行实现的。

    @SpringBootApplication
    @EnableDiscoveryClient
    @Slf4j
    public class EurekaConsumerRibbonApplication {
    
        public static void main(String[] args) throws Exception {
            SpringApplication.run(EurekaConsumerRibbonApplication.class, args);
            log.info("spring-cloud-eureka-consumer-ribbon启动!");
        }
        
        //添加 @LoadBalanced 使其具备了使用LoadBalancerClient 进行负载均衡的能力
        @Bean
        @LoadBalanced
        public RestTemplate restTemplage() {
            return new RestTemplate();
        }
    }
    

    3.编写测试类,进行服务调用。

    /**
     * ribbon访问客户端示例
     * @author oKong
     *
     */
    @RestController
    @Slf4j
    public class DemoController {
        
        @Autowired 
        RestTemplate restTemplate;
        
        @GetMapping("/hello") 
        public String hello(String name) {
            //直接使用服务名进行访问
            log.info("请求参数name:{}", name);
            return restTemplate.getForObject("http://eureka-client/hello?name=" + name, String.class);
        } 
    }
    

    可以看见,可以直接注入RestTemplate,通过服务名直接调用.

    4.启动应用,访问:http://127.0.0.1:8018/hello?name=oKong ,可以看见调用成功:

    hello

    控制台输出:

    控制台输出

    简单聊聊LoadBalanced注解

    可以从以上示例中,可以看出,我们就加了一个@LoadBalanced注解修饰RestTemplatebean类,就实现了服务的调用。现在来简单看看具体是如何实现的。

    首先,我们看看此注解的代码说明:

    LoadBalanced

    从注释可以看出,该注解用来给RestTemplate做标记,以使用负载均衡的客户端LoadBalancerClient

    现在来看一眼相同包下的类的情况,可以看到有个LoadBalancerAutoConfiguration,字面意思可以知道这是一个自动配置类,此类就是我们要找的关键类了。

    LoadBalancerAutoConfiguration,此类不长,一百来行,这里就不贴了。

    LoadBalancerAutoConfiguration

    简单说明下:
    首先,此类生效的条件是

    @ConditionalOnClass(RestTemplate.class)
    @ConditionalOnBean(LoadBalancerClient.class)
    
    • RestTemplate类必须存在于当前工程的环境中。
    • 在Spring的Bean工程中有必须有LoadBalancerClient的实现Bean。

    该自动化配置类中,主要做了几件事情:

    • 维护了一个被@LoadBalanced注解修饰的RestTemplate对象列表
    @LoadBalanced
        @Autowired(required = false)
        private List<RestTemplate> restTemplates = Collections.emptyList();
    

    同时为其每个对象通过调用RestTemplateCustomizer添加了一个LoadBalancerInterceptorRetryLoadBalancerInterceptor拦截器(有生效条件),其为ClientHttpRequestInterceptor接口的实现类,ClientHttpRequestInterceptorRestTemplate的请求拦截器

    RetryLoadBalancerInterceptor拦截器

    RetryInterceptorAutoConfiguration

    LoadBalancerInterceptor拦截器

    LoadBalancerInterceptorConfig

    我们主要看下LoadBalancerInterceptor

    LoadBalancerInterceptor

    可以看见,最后是实现了ClientHttpRequestInterceptor接口的实现类执行execute方法进行.

    LoadBalancerClient

    从继承关系里,此实现类就是RibbonLoadBalancerClient类了。

    RibbonLoadBalancerClient

    RibbonLoadBalancerClient类:
    RibbonLoadBalancerClient

    简单来说:最后还是通过loadBalancerClient.choose()获取到服务实例,最通过拼凑http地址来进行最后的服务调用。

    总体来说,就是通过为加入@LoadBalanced注解的RestTemplate添加一个请求拦截器,在请求前通过拦截器获取真正的请求地址,最后进行服务调用。

    里面的细节就不阐述了,毕竟源码分析不是很在行呀,大家可以跟踪进去一探究竟吧。


    友情提醒:若被@LoadBalanced注解的RestTemplate访问正常的服务地址,如http://127.0.0.1:8080/hello时,是会提示无法找到此服务的。

    具体原因:serverid必须是我们访问的服务名称 ,当我们直接输入ip的时候获取的servernull,就会抛出异常。

    此时,若是需要调用非注册中心的服务,可以创建一个不被@LoadBalanced注解的RestTemplate,同时指定bean的名称,使用时,使用@Qualifier指定name注入此RestTemplate

        @Bean("normalRestTemplage")
        public RestTemplate normalRestTemplage() {
            return new RestTemplate();
        }
        
        //使用
        @Autowired
        @Qualifier("normalRestTemplage")
        RestTemplate normalRestTemplate;
        
         @GetMapping("/ip") 
        public String ip(String name) {
            //直接使用服务名进行访问
            log.info("使用ip请求,请求参数name:{}", name);
            return normalRestTemplate.getForObject("http://127.0.0.1:2000/hello?name=" + name, String.class);
        } 
    

    负载均衡器

    目前还未进行过自定义负载均衡,这里就简单的举例下,上次整理ppt时有讲过一些,但未深入了解过⊙﹏⊙‖∣,

    负载均衡器

    可以从继承关系看出,是通过继承IRule来实现的。

    IRule

    可继承ClientConfigEnabledRoundRobinRule,来实现自己负载均衡策略。

    声明式服务Feign实例

    从上一章节,我们知道,当我们要调用一个服务时,需要知道服务名和api地址,这样才能进行服务调用,服务少时,这样写觉得没有什么问题,但当服务一多,接口参数很多时,上面的写法就显得不够优雅了。所以,接下来,来说说一种更好更优雅的调用服务的方式:Feign

    FeignNetflix开发的声明式、模块化的HTTP客户端。Feign可帮助我们更好更快的便捷、优雅地调用HTTP API

    Spring Cloud中,使用Feign非常简单——创建一个接口,并在接口上添加一些注解。Feign支持多种注释,例如Feign自带的注解或者JAX-RS注解等
    Spring Cloud对Feign进行了增强,使Feign支持了Spring MVC注解,并整合了Ribbon和 Eureka,从而让Feign 的使用更加方便。只需要通过创建接口并用注解来配置它既可完成对Web服务接口的绑定。

    Feign实例

    创建个spring-cloud-eureka-consumer-ribbon工程项目。

    0.加入feigin依赖

            <!-- feign -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
            <!-- eureka客户端依赖 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            </dependency>
            <!-- rest api -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    

    1.配置文件

    spring.application.name=eureka-consumer-feign
    server.port=8028
    
    #指定注册中心地址
    eureka.client.service-url.defaultZone=http://127.0.0.1:1000/eureka
    # 启用ip配置 这样在注册中心列表中看见的是以ip+端口呈现的
    eureka.instance.prefer-ip-address=true
    # 实例名称  最后呈现地址:ip:2000
    eureka.instance.instance-id=${spring.cloud.client.ip-address}:${server.port}
    

    2.创建启动类,加入注解@EnableFeignClients,开启feign支持。

    @SpringBootApplication
    @EnableFeignClients
    @Slf4j
    public class EurekaConsumerFeignApplication {
    
        public static void main(String[] args) throws Exception {
            SpringApplication.run(EurekaConsumerFeignApplication.class, args);
            log.info("spring-cloud-eureka-consumer-feign启动");
        }
    
    }
    

    3.创建一个接口类IHelloClient,加入注解@FeignClient来指定这个接口所要调用的服务名称。

    @FeignClient(name="eureka-client")
    public interface IHelloClient {
    
        /**
         * 定义接口
         * @param name
         * @return
         */
        @RequestMapping(value="/hello", method=RequestMethod.GET)
        public String hello(@RequestParam("name") String name);
    }
    

    4.创建一个demo控制层,引入此接口类。

    /**
     * feign 示例
     * @author OKong
     *
     */
    @RestController
    @Slf4j
    public class DemoController {
        
        @Autowired
        IHelloClient helloClient;
        
        @GetMapping("/hello") 
        public String hello(String name) {
            log.info("使用feign调用服务,参数name:{}", name);
            return helloClient.hello(name);
        } 
    }
    

    5.启动应用,访问:http://127.0.0.1:8028/hello?name=oKong-feign

    hello

    是不是很简单,和调用本地服务是一样的了!

    Feign继承特性

    Feign支持继承,但不支持多继承。使用继承,可将一些公共操作分组到一些父类接口中,从而简化Feign的开发。

    所以在实际开发中,调用服务接口时,可直接按接口类和实现类进行编写,调用方引入接口依赖,继承一个本地接口,这样接口方法默认都是定义好的,也少了很多编码量。用起来就更爽了,就是有点依赖性,对方服务修改后需要同步更新下,但这个团队内部约定下问题不大的

    这里简单实例下,创建一个spring-cloud-eureka-client-api工程。

    0.加入依赖,注意此依赖的作用范围:

        <!--api接口依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <scope>provided</scope>
            </dependency>
    

    1.编写一个接口类IHellpApi

    public interface IHelloApi {
        //定义提供者服务名
        public static final String SERVICE_NAME = "eureka-client";
        
        /**
         * 定义接口
         * @param name
         * @return
         */
        @RequestMapping(value="/hello", method=RequestMethod.GET)
        public String hello(@RequestParam("name") String name);
    }
    

    修改spring-cloud-eureka-client工程

    0.引入api依赖

        <!-- 导入接口依赖 -->
        <dependency>
           <groupId>cn.lqdev.learning</groupId>
           <artifactId>spring-cloud-eureka-client-api</artifactId>
           <version>0.0.1-SNAPSHOT</version>
        </dependency>
    

    1.创建一个HelloApiImpl类,实现IHelloApi:

    /**
     * 使用接口方式进行接口编写
     * @author oKong
     *
     */
    @RestController
    @Slf4j
    public class HelloApiImpl implements IHelloApi {
        
        @Override
        public String helloApi(@RequestParam("name") String name) {
            log.info("[spring-cloud-eureka-client]服务[helloApi]被调用,参数name值为:{}", name);
            return name + ",helloApi调用!";
        }
    }
    

    此时,HelloApiImpl是个控制层也是个接口实现类了。

    修改spring-cloud-eureka-consumer-feign工程。
    0.引入api依赖

        <!-- 导入接口依赖 -->
        <dependency>
           <groupId>cn.lqdev.learning</groupId>
           <artifactId>spring-cloud-eureka-client-api</artifactId>
           <version>0.0.1-SNAPSHOT</version>
        </dependency>
    

    1.同样创建一个接口,使其继承IHelloApi:

    /**
     * 直接继承接口
     * @author Okong
     *
     */
    @FeignClient(name = IHelloApi.SERVICE_NAME)
    public interface HelloApi extends IHelloApi{
    
    }
    

    小技巧:可以在IHelloApi定义一个服务名变量,如:SERVICE_NAME,这样让提供者进行变量的赋值,可以避免一些不必要的交流成本的,若有变化,服务调用方也无需关心的。一切都是约定编程!

    2.修改下DemoController类,注入HelloApi

        @Autowired
        HelloApi helloApi;
        
        @GetMapping("hello2")
        public String hello2(String name) {
            log.info("使用feign继承方式调用服务,参数name:{}", name);
            return helloApi.helloApi(name);
        }    
    

    3.分别启动各服务,访问:http://127.0.0.1:8028/hello2?name=oKong-api

    hello2

    使用起来没啥差别的,一样的调用,但对于调用方而言,可以无需去理会具体细节了,照着接口方法去传参就好了。

    这种方式,和原来的dubbo调用的方式是类似的,简单方便。大家可以把接口和实体放入一个包中,调用者和提供者都进行依赖即可。

    注意事项

    在使用Feign时,会碰见一些问题,为了避免不必要的错误,以下这些需要额外注意下。

    • GET请求多个参数时,需要使用@RequestParam
    • GET请求参数为实体时,会自动转换成POST请求
    • POST请求使用@RequestBody注解参数
    • 不建议直接将@RequestMapping注解在类上,直接写在方法上

    参考资料

    1. https://blog.csdn.net/mengdonghui123456/article/details/53981976

    2. https://cloud.spring.io/spring-cloud-static/Finchley.SR1/single/spring-cloud.html#_spring_cloud_openfeign

    总结

    本章节主要讲解了下服务消费者如何利用原生、ribbon、fegin三种方式进行服务调用的,其实每种调用方式都是使用ribbon来进行调用的,只是有些进行了增强,是的使用起来更简单高效而已。对于其原理的实现,本文未进行详细阐述,大家可以谷歌想相关知识,跟踪下源码了解下,本人也尚未深入研究过,还是停留在使用阶段,之后有时间了看一看,有啥心得再来分享吧。此时若服务上线下线,调用者调用可能会出现短暂的调用异常,最常见的就是找不到服务,此时服务容错保护就排上用场了,所以下一章节,就来说说关于服务容错保护相关知识点~

    最后

    目前互联网上大佬都有分享SpringCloud系列教程,内容可能会类似,望多多包涵了。原创不易,码字不易,还希望大家多多支持。若文中有错误之处,还望提出,谢谢。

    老生常谈

    • 个人QQ:499452441
    • 微信公众号:lqdevOps

    公众号

    个人博客:http://blog.lqdev.cn

    源码示例:https://github.com/xie19900123/spring-cloud-learning

    原文地址:http://blog.lqdev.cn/2018/09/21/SpringCloud/chapter-four/

  • 相关阅读:
    HTTP协议中的chunked编码解析
    QP编码详解
    从新手到入门,如何进入协议分析的世界
    构造个人轻量级XSS平台获取管理员cookie并登录
    逆向分析-IDA动态调试WanaCrypt0r的wcry.exe程序
    C# 链接数据库并查询操作
    excel日期格式转换
    SAP的PI日志查看工具
    abap 动态指针理解加深ASSIGN COMPONENT
    ABAP-编程时快速带出关键字与快速注释快捷键设置
  • 原文地址:https://www.cnblogs.com/okong/p/springcloud-four.html
Copyright © 2020-2023  润新知