1.负载均衡:

​ 负载均衡在系统架构中是一个非常重要,并且不得不去实施的内容。因为负载均衡是对系统高可用,网络压力的缓解和处理能力扩容的重要手段之一。我们通常说的负载均衡都指的是服务端负载均衡,其中分为硬件负载均衡和软件负载均衡。硬件负载均衡主要通过在服务器节点之间安装专门用于负载均衡的设备,而软件负载均衡则是通过在服务器上安装一些具有均衡负载功能或模块的软件来完成请求分发的工作,比如Nginx等。不论采用硬件负载均衡还是软件负载均衡,只要是服务端负载均衡都能以类似下图的架构方式构建起来:

​ 硬件负载均衡的设备或是软件负载均衡的软件模块都会维护一个下挂可用的服务端清单,通过心跳检测来剔除故障的服务端节点以保证清单中都是可以正常访问的服务端节点。当客户端发送请求到负载均衡设备的时候,该设备按某种算法(比如线性轮询,按权重负载,按流量负载)从维护的可用服务清单中取出一台服务端的地址,然后进行转发。

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

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

  1. 服务提供者只需要启动多个服务实例并注册到一个注册中心或是多个相关联的服务注册中心
  2. 服务消费者直接通过调用被@LoadBalanced注解修饰过的RestTemplate来实现面向服务的接口调用

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

2.RestTemplate详解:

xxxForEntity/xxxForObject:主要介绍get跟post

​ get方法主要有6中调用方式,其中又可以分为getForEntity和getForObject,每个方法有3中重载方式。

​ getForEntity函数。该方法返回的是ResponseEntity,该对象是Spring对HTTP请求响应的封装,其中主要存储了HTTP的几个重要元素,比如HTTP请求状态码的枚举对象HttpStatus(也就是我们常说的400,404这些错误码),在它的父类HttpEntity中还存储着HTTP请求的头信息对象HttpHeaders以及泛型类型的请求体对象。

​ getForObject函数,我们可以理解为它是对getForEntity的进一步封装,它通过HttpMessageConverterExtractor对HTTP的请求响应体body内容进行对象转换,实现请求直接返回包装好的对象内容。

​ 在了解了两种调用方式的不同的后,我们再来看看他们的参数:

  • String url:get请求访问地址,例如:“http://USER_SERVICE/user?name=zhangsan”

  • Class responseType: ResponseEntity对象的泛型类型,也就是我们返回数据的实例类型

  • Map<String,?> urlVariables:get请求携带的参数,如果以这种方式携带参数,则调用方式如下:

     RestTemplate restTemplate = new RestTemplate();
    Map<String,String> param = new HashMap<>();
    param.put("name","zhangsan");
    restTemplate.getForEntity("http://USER_SERVICE/user?name={name}", User.class,param);
  • Object… urlVariables:get请求携带的参数,如果以这种方式携带参数,则调用方式如下:

            RestTemplate restTemplate = new RestTemplate();
    String [] param = {"zhangsan","11"};
    restTemplate.getForEntity("http://USER_SERVICE/user?name={1}&age={2}", User.class,param);
  • URI url: get请求访问地址,这里使用URI对象来替代之前的url和urlVariables参数来指定访问地址和参数绑定。URI是JDK中java.net包下的一个类,它表示一个统一资源标识符引用。调用方式如下:

     RestTemplate restTemplate = new RestTemplate();
    UriComponents uriComponents = UriComponentsBuilder
    .fromUriString("http://USER_SERVICE/user?name={name}")
    .build()
    .expand("zhangsan").encode();
    URI uri = uriComponents.toUri();
    restTemplate.getForEntity(uri, User.class);

    或者:

     RestTemplate restTemplate = new RestTemplate();
    UriComponentsBuilder uriComponents = UriComponentsBuilder
    .fromUriString("http://USER_SERVICE/user");
    uriComponents.queryParam("name","zhangsan");
    restTemplate.getForEntity(uriComponents.build().toUri(), User.class);

采用上面的这种调用方式,并使用get请求的话,没办法携带头信息(反正我没找到)。但是post方法是可以的,我们看下post方法的调用方式:





可以看到跟get请求相比,post方法多携带了一个参数Object request,在这个参数中,我们可以携带我们的头信息,调用方式如下:

RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity entity = new HttpEntity(httpHeaders);
UriComponentsBuilder uriComponents = UriComponentsBuilder
.fromUriString("http://USER_SERVICE/user");
uriComponents.queryParam("name", "zhangsan");
restTemplate.postForEntity(uriComponents.build().toUri(), entity, User.class);

用上面这种方式调用的话,参数是拼接在url后面的,只不过会在头信息中携带我们定义的信息

http://USER_SERVICE/user?name=zhangsan

如果我们要以请求体的方式携带我们的参数,需要这样调用

        RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// 换成对象也可以
Map<String,Object> param = new HashMap<>();
param.put("name","zhangsan");
HttpEntity entity = new HttpEntity(param,httpHeaders);
UriComponentsBuilder uriComponents = UriComponentsBuilder
.fromUriString("http://USER_SERVICE/user");
restTemplate.postForEntity(uriComponents.build().toUri(), entity, User.class);

问题来了,如果我要以get请求的方式访问,并且还要携带头信息该怎么办呢?这就要说第二种调用方式了

exchange:

exchange方法可以在发送个服务器端的请求中设置头信息。

我们观察其参数可以发现

  • HttpMethod method:一个枚举类,主要列举了Http请求的各种请求方式。如get:HttpMethod.GET
  • HttpEntity requestEntity:请求参数封装,跟我们之前的用法一样
  • 其余的参数之前已经分析过了就不讲了
execute源码分析:

​ 如果我们去跟踪exchange方法就会发现,它其实就是调用了execute方法,不只是exchange,xxxForEntity/xxxForObjext其实底层都调用了execute方法。这里,为了对RestTemplate有更深的理解,我们现在来分析这个方法。

​ 我们追踪这个方法,会发现,它调用了doExecute这个方法

protected <T> T doExecute(URI url, @Nullable HttpMethod method, @Nullable RequestCallback requestCallback,
@Nullable ResponseExtractor<T> responseExtractor) throws RestClientException { Assert.notNull(url, "URI is required");
Assert.notNull(method, "HttpMethod is required");
ClientHttpResponse response = null;
try {
// 1.构建一个request对象
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) {
// 2. 发送请求前对request对象进行一些处理
requestCallback.doWithRequest(request);
}
// 3.发送请求,得到响应
response = request.execute();
// 4.处理一些错误信息
handleResponse(url, method, response);
// 5.解析请求数据
return (responseExtractor != null ? responseExtractor.extractData(response) : null);
}
catch (IOException ex) {
String resource = url.toString();
String query = url.getRawQuery();
resource = (query != null ? resource.substring(0, resource.indexOf('?')) : resource);
throw new ResourceAccessException("I/O error on " + method.name() +
" request for \"" + resource + "\": " + ex.getMessage(), ex);
}
finally {
if (response != null) {
response.close();
}
}
}
  1. ClientHttpRequest request = createRequest(url, method);

这句话的主要目的是构建一个ClientHttpRequest 对象,我们跟踪下代码:

  protected ClientHttpRequest createRequest(URI url, HttpMethod method) throws IOException {
ClientHttpRequest request = this.getRequestFactory().createRequest(url, method);
if (this.logger.isDebugEnabled()) {
this.logger.debug("HTTP " + method.name() + " " + url);
} return request;
}

它会获取一个ClientHttpRequestFactory,然后构建一个ClientHttpRequest对象,我们可以看到默认会采用SimpleClientHttpRequestFactory,代码如下:

 private ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();

如果我们要配置不同的工厂要怎么配置呢?我们可以通过org.springframework.boot.web.client.RestTemplateBuilder对象,例如,我们要以okHttpClient作为RestTemplate的底层实现

 RestTemplateBuilder builder = new RestTemplateBuilder();
ClientHttpRequestFactory okHttp3ClientHttpRequestFactory = new OkHttp3ClientHttpRequestFactory();
RestTemplate build = builder
.requestFactory(() -> okHttp3ClientHttpRequestFactory).build();
  1. requestCallback.doWithRequest(request);这里主要是对头信息做了一下处理,具体源码大家可以自己看下
  2. response = request.execute();发送一个http请求
  3. handleResponse(url, method, response);处理错误信息
  4. responseExtractor.extractData(response),按我们定义的ResponseEntity中的泛型跟HttpMessageConverter解析数据类型

​ 由于Ribbon中,采用了RestTemplate所以花时间系统的了解了一下RestTemplate,接下来,我们就要系统的学习一下Ribbon。

Spring Cloud 学习 之 Spring Cloud Ribbon(基础知识铺垫)的更多相关文章

  1. Spring Cloud 学习 之 Spring Cloud Eureka(源码分析)

    Spring Cloud 学习 之 Spring Cloud Eureka(源码分析) Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 ...

  2. Spring Cloud 学习 之 Spring Cloud Eureka(搭建)

    Spring Boot版本:2.1.4.RELEASE Spring Cloud版本:Greenwich.SR1 文章目录 搭建服务注册中心: 注册服务提供者: 高可用注册中心: 搭建服务注册中心: ...

  3. 学习 shell脚本之前的基础知识

    转载自:http://www.92csz.com/study/linux/12.htm  学习 shell脚本之前的基础知识 日常的linux系统管理工作中必不可少的就是shell脚本,如果不会写sh ...

  4. 【转载】salesforce 零基础开发入门学习(二)变量基础知识,集合,表达式,流程控制语句

    salesforce 零基础开发入门学习(二)变量基础知识,集合,表达式,流程控制语句 salesforce如果简单的说可以大概分成两个部分:Apex,VisualForce Page. 其中Apex ...

  5. Spring Cloud学习笔记--Spring Boot初次搭建

    1. Spring Boot简介 初次接触Spring的时候,我感觉这是一个很难接触的框架,因为其庞杂的配置文件,我最不喜欢的就是xml文件,这种文件的可读性很不好.所以很久以来我的Spring学习都 ...

  6. spring cloud学习(六)Spring Cloud Config

    Spring Cloud Config 参考个人项目 参考个人项目 : (希望大家能给个star~) https://github.com/FunriLy/springcloud-study/tree ...

  7. Spring Cloud 学习 (九) Spring Security, OAuth2

    Spring Security Spring Security 是 Spring Resource 社区的一个安全组件.在安全方面,有两个主要的领域,一是"认证",即你是谁:二是& ...

  8. Spring Boot学习笔记---Spring Boot 基础及使用idea搭建项目

    最近一段时间一直在学习Spring Boot,刚进的一家公司也正好有用到这个技术.虽然一直在学习,但是还没有好好的总结,今天周末先简单总结一下基础知识,等有时间再慢慢学习总结吧. Spring Boo ...

  9. Spring.NET学习笔记1——控制反转(基础篇)

    在学习Spring.NET这个控制反转(IoC)和面向切面(AOP)的容器框架之前,我们先来看一下什么是控制反转(IoC). 控制反转(Inversion of Control,英文缩写为IoC),也 ...

  10. Spring 框架学习(1)--Spring、Spring MVC扫盲

    纸上得来终觉浅,绝知此事要躬行 文章大纲 什么是spring 传统Java web应用架构 更强的Java Web应用架构--MVC框架 Spring--粘合式框架 spring的内涵 spring核 ...

随机推荐

  1. windows powershell校验下载的文件MD5和SHA1值

    Windows自带MD5 SHA1 SHA256命令行工具 certutil -hashfile <文件名> <hash类型> 打开windows powershell,进入到 ...

  2. for循环,for…in循环,forEach循环的区别

    for循环,for…in循环,forEach循环的区别for循环通关for循环,生成所有的索引下标for(var i = 0 ; i <= arr.length-1 ; i++){ 程序内容 } ...

  3. vue2.x学习笔记(三)

    接着前面的内容:https://www.cnblogs.com/yanggb/p/12562137.html. vue实例 要使用vue提供的特性与功能,都需要通过vue实例来使用. 创建一个vue实 ...

  4. 详解 方法的覆盖 —— toString() 与 equals()的覆盖

    在学习本篇博文前,建议先学习完本人的博文--<详解 继承(上)-- 工具的抽象与分层> 在本人之前的博文中曾讲过"基类"的知识,那么,本篇博文中的主题--Object类 ...

  5. Os-Hax: 1 靶机记录

    靶机地址:172.16.1.197 Kali地址:172.16.1.108 1 信息搜集 靶机首页 相关信息查看 端口扫描: 开放22和80 目录扫描: 访问http://172.16.1.197/c ...

  6. 基于nodejs的游戏服务器

    开源一个四年前自己写的node服务器,有兴趣的可以继续开发-- 架构为mysql,redis,node. 数据格式为 protocol buff 如果只做简单的演示,这个架构非常适合你.. 还是typ ...

  7. react: typescript jest && enzyme

    Install Jest 1.install jest dependencies jest @types/jest ts-jest -D 2.jest.config.js module.exports ...

  8. Docker 搭建 ELK 集群步骤

    前言 本篇文章主要介绍在两台机器上使用 Docker 搭建 ELK. 正文 环境 CentOS 7.7 系统 Docker version 19.03.8 docker-compose version ...

  9. Golang Map实现(四) map 的赋值和扩容

    title: Golang Map 实现 (四) date: 2020-04-28 18:20:30 tags: golang map 操作,是map 实现中较复杂的逻辑.因为当赋值时,为了减少has ...

  10. 备忘录模式 (c++实现)

    模式定义 备忘录(Memento): 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样以后就可以将该对象恢复到原先保存的状态. 模式动机 备忘录模式比较适用于功能比较复 ...