Ribbon

1.Ribbon简介

Spring Cloud Ribbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。Spring Cloud Ribbon虽然只是一个工具类框架,它不像服务注册中心、配置中心、API网关那样需要独立部署,但是它几乎存在于每一个Spring Cloud构建的微服务和基础设施中。因为微服务间的调用,API网关的请求转发等内容,实际上都是通过Ribbon来实现的,包括后续我们将要介绍的Feign,它也是基于Ribbon实现的工具。所以,对Spring Cloud Ribbon的理解和使用,对于我们使用Spring Cloud来构建微服务非常重要

2.客户端负载均衡

负载均衡在系统架构中是一个非常重要,并且是不得不去实施的内容。因为负载均衡是对系统的高可用、网络压力的缓解和处理能力扩容的重要手段之一。我们通常所说的负载均衡都指的是服务端负载均衡,其中分为硬件负载均衡和软件负载均衡。硬件负载均衡主要通过在服务器节点之间按照专门用于负载均衡的设备,比如F5等;而软件负载均衡则是通过在服务器上安装一些用于负载均衡功能或模块等软件来完成请求分发工作,比如Nginx等。不论采用硬件负载均衡还是软件负载均衡,只要是服务端都能以类似下图的架构方式构建起来
在这里插入图片描述
硬件负载均衡的设备或是软件负载均衡的软件模块都会维护一个下挂可用的服务端清单,通过心跳检测来剔除故障的服务端节点以保证清单中都是可以正常访问的服务端节点。当客户端发送请求到负载均衡设备的时候,该设备按某种算法(比如线性轮询、按权重负载、按流量负载等)从维护的可用服务端清单中取出一台服务端端地址,然后进行转发。

    而客户端负载均衡和服务端负载均衡最大的不同点在于上面所提到服务清单所存储的位置。在客户端负载均衡中,所有客户端节点都维护着自己要访问的服务端清单,而这些服务端端清单来自于服务注册中心,比如上一章我们介绍的Eureka服务端。同服务端负载均衡的架构类似,在客户端负载均衡中也需要心跳去维护服务端清单的健康性,默认会创建针对各个服务治理框架的Ribbon自动化整合配置,比如Eureka中的org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,Consul中的org.springframework.cloud.consul.discovery.RibbonConsulAutoConfiguration。在实际使用的时候,我们可以通过查看这两个类的实现,以找到它们的配置详情来帮助我们更好地使用它。

    通过Spring Cloud Ribbon的封装,我们在微服务架构中使用客户端负载均衡调用非常简单,只需要如下两步:

    ▪️服务提供者只需要启动多个服务实例并注册到一个注册中心或是多个相关联的服务注册中心。

    ▪️服务消费者直接通过调用被@LoadBalanced注解修饰过的RestTemplate来实现面向服务的接口调用。

    这样,我们就可以将服务提供者的高可用以及服务消费者的负载均衡调用一起实现了

3.GET请求

在RestTemplate中,对GET请求可以通过如下两个方法进行调用实现

3.1getForEntity

该方法返回的是ResponseEntity,该对象是Spring对HTTP请求响应的封装,其中主要存储了HTTP的几个重要元素,比如HTTP请求状态码的枚举对象HttpStatus(也就是我们常说的404、500这些错误码)、在它的父类HttpEntity中还存储着HTTP请求的头信息对象HttpHeaders以及泛型类型的请求体对象。比如下面的例子,就是访问USER-SERVER服务端/user请求,同时最后一个参数didi会替换url中的{1}占位符,而返回的ResponseEntity对象的body内容类型会根据第二个参数转换为String类型

RestTemplate template = new RestTemplate(new OkHttp3ClientHttpRequestFactory());

        System.out.println(template.getRequestFactory());

        ResponseEntity<String> forEntity = restTemplate.getForEntity("www.baidu.com", String.class, "11");

        String body = forEntity.getBody();

        System.out.println(forEntity);

若我们希望返回body是一个User对象类型,也可以这样实现:

RestTemplate template = new RestTemplate(new OkHttp3ClientHttpRequestFactory());

        System.out.println(template.getRequestFactory());

        ResponseEntity<RestTemplateConfig> forEntity = restTemplate.getForEntity("www.baidu.com", RestTemplateConfig.class, "11");

        RestTemplateConfig body = forEntity.getBody();

上面的例子是比较常用的方法,getForEntity函数实际上提供了以下三种不同的重载实现
1.getForEntity(String url, Class responseType,Object… urlVariables)

/**
     *
     * @param url(请求的地址)
     * @param responseType(请求响应体body的包装类型)
     * @param uriVariables(url中的参数绑定)
     * @param <T>
     * @return
     * @throws RestClientException
     */
    @Override
	public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables)
			throws RestClientException {

		RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
		ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
		return nonNull(execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables));
	}
    

GET请求的参数绑定通过使用url中拼接的方式,比如http://USER-SERVICE/user?name=didi,我们可以像这样自己将参数拼接到 url中,但更好的方法是在url中使用占位符并配合urlVariables参数实现GET请求的参数绑定,比如url定义为:getForEntity(“http://USER-SERVICE/user?name={1}”, String.class, “didi”),其中第三个参数didi会替换掉url中的{1}站位符。这里需要注意的是,由于urlVariables参数是一个数组,所以它的顺序会对应url中占位符定义的数字顺序
2.getForEntity(String url, Class responseType, Map urlVariables);
该方法提供的参数重,只有urlVariables的参数类型与上面的方法不同。这里使用了Map类型,所以使用该方法进行参数绑定时需要再占位符中指定Map中的参数的key值,比如url定义为http://USER-SERVICE/user?name={name},在Map类型的urlVariables中,我们就需要put一个key为name的参数来绑定url中{name}占位符的值,比如

RestTemplate template = new RestTemplate(new OkHttp3ClientHttpRequestFactory());

        System.out.println(template.getRequestFactory());

        HashMap<String, String> map = new HashMap<>();
        map.put("name","value");

        ResponseEntity<RestTemplateConfig> forEntity = restTemplate.getForEntity("www.baidu.com/user?name={name}", RestTemplateConfig.class, map);

        RestTemplateConfig body = forEntity.getBody();

3.getForEntity(URI url, Class responseType)
该方法使用uri对象来代替之前url和urlVariables参数来指定访问地址和参数绑定。URI是JDK java.net包下单一个类,它表示一个统一资源标识符(Uniform Resource Identifier)引用,比如下面的例子

RestTemplate template = new RestTemplate(new OkHttp3ClientHttpRequestFactory());

        UriComponents dzlUri = UriComponentsBuilder.fromUriString("www.baidu.com/user?name={name}").build().expand("dzl").encode();

        URI uri = dzlUri.toUri();

        ResponseEntity<RestTemplateConfig> forEntity = template.getForEntity(uri, RestTemplateConfig.class);

        RestTemplateConfig body = forEntity.getBody();

3.2getForObject

该方法可以理解为对getForEntity的进一步封装,它通过HttpMessageConverterExtractor对HTTP的请求响应体body内容进行对象转换,实现请求直接返回包装好的对象内容
string的情况下

RestTemplate template = new RestTemplate(new OkHttp3ClientHttpRequestFactory());

        String forObject = template.getForObject("www.baidu.com", String.class, "11");

当body是一个对象时,可以直接这样实现

RestTemplate template = new RestTemplate(new OkHttp3ClientHttpRequestFactory());

        RestTemplateConfig forObject = template.getForObject("www.baidu.com", RestTemplateConfig.class, "11");

当不需要关注请求响应除body外的其他内容时,该函数就非常好用,可以少一个从Response中获取body的步骤。它与getForEntity函数类似,也提供了三种不同的重载实现

▪️getForObject(String url, Class responseType, Object ... urlVariables)

▪️getForObject(String url, Class responseType, Map urlVariables)

▪️getForObject(URI url, Class responseType)

4.POST 请求

在RestTemplate中,对POST请求时可以通过如下三个方法调用实现

4.1postForEntity

该方法同GET请求中的getForEntity类似,会在调用后返回ResponseEntity对象,其中T为请求响应的body类型。比如下面这个例子,使用postForEntity提交POST请求到USER-SERVICE服务的/user接口,提交的body内容为user对象,请求响应返回的body类型为String

postForEntity函数也实现了三种不同的重载方法

▪️postForEntity(String url, Object request, Class responseType, Object... uriVariables)

▪️postForEntity(String url, Object request, Class responseType, Map uriVariables)

▪️postForEntity(URI url, Object request, Class responseType)

这些函数中的参数用法大部分与getForEntity一致,比如,第一个重载函数和第二个重载函数中的uriVariables参数都用来对url中的参数进行绑定使用;responseType参数是对请求响应的body内容的类型定义。这里需要注意的是新增加的request参数,该参数可以是一个普通对象,也可以是一个HttpEntity对象。如果是普通对象,而非HttpEntity对象的时候,RestTemplate会将请求对象转换为一个HttpEntity对象来处理;其中Object就是request的类型,request内容会呗视作完整的body来处理;而如果request是一个HttpEntity对象,那么就会被当作一个完成的HTTP请求对象来处理,这个request中不仅包含了body的内容,也包含了header的内容

4.2postForObject

该方法也跟getForObject的类型类似,它的作用就是简化postForEntity的后续处理。通过直接将请求响应的body内容包装成对象来返回使用
postForObject函数也实现了三种不同的重载方法

▪️postForObject(String url, Object request, Class responseType, Object... uriVariables)

▪️postForObject(String url, Object request, Class responseType, Map uriVariables)

▪️postForObject(URI url, Object request, Class responseType)

4.3postForLocation

该方法实现了以POST请求提交资源,并返回新的资源的URI

RestTemplate template = new RestTemplate(new OkHttp3ClientHttpRequestFactory());

        URI uri = template.postForLocation("www.baidu.com", RestTemplateConfig.class, "11");

postForLocation函数也实现了三种不同的重载方法

▪️postForLocation(String url, Object request, Object... uriVariables)

▪️postForLocation(String url, Object request, Map uriVariables)

▪️postForLocation(URI url, Object request)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值