基本介绍: 将业务的所有功能集中在一个项目中开发,打成一个包部署。
优点: 架构简单、部署成本低
缺点: 耦合度高
基本介绍: 根据业务功能对系统进行拆分,每个业务模块作为独立项目开发,称为一个服务。
优点: 降低服务耦合、有利于服务升级拓展
缺点: 架构复杂、难度大
分布式架构的要考虑的问题:
基本介绍: 微服务是一种经过良好架构设计的分布式架构方案。
特征:
优点: 拆分粒度更小、服务更独立、耦合度更低
缺点: 架构非常复杂,运维、监控、部署难度提高
SpringCloud 是目前国内使用最广泛的微服务框架。官网地址:https://spring.io/projects/spring-cloud
SpringCloud 集成了各种微服务功能组件,并基于 SpringBoot 实现了这些组件的自动装配,从而提供了良好的开箱即用体验
SpringCloud 与 SpringBoot 的版本兼容关系:
| Realesase Train(版本序列) | Boot Version |
|---|---|
| 2020.0.x aka Ilford | 2.4.x |
| Hoxton | 2.2.x, 2.3.x |
| Greenwich | 2.1.x |
| Finchley | 2.0.x |
| Edgware | 1.5.x |
| Dalston | 1.5.x |
基本介绍:
当我们需要远程调用一个 HTTP 接口时,我们经常会用到 RestTemplate 这个类,这个类是 Spring 框架提供的一个工具类。它提供了常见的 REST 请求方案的模版,例如 GET 请求、POST 请求、PUT 请求、DELETE 请求以及一些通用的请求执行方法 exchange 以及 execute。
常用方法:
| 方法 | 描述 |
|---|---|
getForObject | 通过 GET 请求获得响应结果 |
getForEntity | 通过 GET 请求获取 ResponseEntity 对象,包括状态码、响应头和响应数据等 |
headForHeaders | 以 HEAD 请求资源返回所有响应头信息 |
postForLocation | 用 POST 请求创建资源,并返回响应数据中响应的字段 Location 的数据 |
postForObject | 通过 POST 请求创建资源,获得响应结果 |
put | 通过 PUT 请求来创建或更新资源 |
patchForObject | 通过 PATH 请求来更新资源,并获得响应结果 |
delete | 通过 DELETE 请求来删除资源 |
optionsForAllow | 通过 ALLOW 请求来获得资源所允许访问的所有 HTTP 方法,可用来查看某个请求支持哪些请求方式 |
exchange | 更通过版本的请求处理方法,接受一个 RequestEntity 对象,可以设置路径、请求头、请求信息等,最后返回一个 ResponseEntity 实体 |
execute | 最通用的执行 HTTP 请求方法,上面所有方法都是基于 execute 的封装,可以全面控制请求信息,并通过回调接口获得响应数据 |
简单使用:
首先将 RestTemplate 在配置类中进行注入(启动类也属于配置类,可以直接在启动类中使用 @Bean 进行注入)![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MdIfVNhM-1656948229564)(C:/Users/bbbbbge/Pictures/接单/1656095024889.png)]](https://1000bd.com/contentImg/2022/07/05/081049175.png)
通过 RestTemplate 对象的 getForObject(url, Class<T> responseType) 方法,就能够通过 get 方法向其它微服务发送对应的请求去获取数据。![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KFZdLUnz-1656948229566)(C:/Users/bbbbbge/Pictures/接单/1656231414252.png)]](https://1000bd.com/contentImg/2022/07/05/081049371.png)
RestTamplate 远程调用出现的问题:
在 Eureka 框架中,微服务角色有两类:
EurekaServer(服务端,注册中心):用于记录服务信息,进行心跳监控
EurekaClient(客户端):包括服务提供者和消费者
在进行之后的步骤之前,需要在父工程中引入 spring-cloud-dependencies 依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR10</version>
<type>pom</type>
<scope>import</scope>
</dependency>
创建项目,引入 spring-cloud-starter-netflix-eureka-server eureka 服务端依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
编辑启动类,添加 @EnableEurekaServer 注解
@SpringBootApplication
@EnableEurekaServer
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
添加 application.yml 文件,编写下面的配置:
server:
port: 10086 # 服务端口
spring:
application:
name: eurekaserver # eureka 的服务名称
eureka:
client:
service-url: # eureka 的地址信息
defaultZone: http://127.0.0.1:10086/eureka
通过配置的 eureka 的地址信息就能够访问到 eureka 注册中心的状况![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mex0b2wT-1656948229566)(C:/Users/bbbbbge/Pictures/接单/1656341408374.png)]](https://1000bd.com/contentImg/2022/07/05/081049662.png)
在要注册的服务中引入 spring-cloud-starter-netflix-eureka-server eureka 客户端依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
在 application.yml 文件中编写下面的配置:
server:
port: 8080 # 服务端口
spring:
application:
name: aservice # 注册到 eureka 中的服务名称
eureka:
client:
service-url: # 配置 eureka 的地址信息
defaultZone: http://127.0.0.1:10086/eureka
通过配置的 eureka 的地址信息就能够查看注册到 eureka 中的实例![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qe0f7CMx-1656948229567)(C:/Users/bbbbbge/Pictures/接单/1656343129036.png)]](https://1000bd.com/contentImg/2022/07/05/081049828.png)
以上是对某个服务进行一个实例的部署,如果要部署多个实例,则为了避免端口冲突,需要修改端口配置
右击要部署多个的服务,点击 Copy Configuration…![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8h5DZg2v-1656948229567)(C:/Users/bbbbbge/Pictures/接单/1656343480426.png)]](https://1000bd.com/contentImg/2022/07/05/081050042.png)
修改配置的名字,并在 VM options 这栏加上 -Dserver.port=新的端口号 却修改配置的端口号![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8xFK82WM-1656948229568)(C:/Users/bbbbbge/Pictures/接单/1656347980434.png)]](https://1000bd.com/contentImg/2022/07/05/081050260.png)
启动项目后,在 eureka 的注册中心就能看到 aservice 服务注册了两个实例![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uewyNpfC-1656948229568)(C:/Users/bbbbbge/Pictures/接单/1656348161947.png)]](https://1000bd.com/contentImg/2022/07/05/081050466.png)
修改 RestTemplate 的 url 路径,用服务名代替 ip 和端口号![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pmIghAKw-1656948229568)(C:/Users/bbbbbge/Pictures/接单/1656354814704.png)]](https://1000bd.com/contentImg/2022/07/05/081050648.png)
在 RestTemplate 注册到 Spring 容器的位置加上 @LoadBalanced 负载均衡注解![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5ulQTgkl-1656948229569)(C:/Users/bbbbbge/Pictures/接单/1656355483969.png)]](https://1000bd.com/contentImg/2022/07/05/081050846.png)
启动项目,通过 bservice 服务访问 aservice 服务中的方法
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w4VjramO-1656948229569)(C:/Users/bbbbbge/Pictures/接单/1656403815931.png)]](https://1000bd.com/contentImg/2022/07/05/081051081.png)
通过浏览器直接访问 http://aservice/say/dog 是访问不到的,因为 aservice 不是正确的 ip 和端口号,而加上负载均衡的注解 @LoadBalanced 注解就能够对这个请求进行拦截,在 eureka-server 中找到 aservice 对应的 ip 和端口号,最终返回请求的数据。
加上 @LoadBalanced 就能就行拦截,那么拦截的动作是谁处理的呢?
请求会被一个叫 LoadBalancerInterceptor 的负载均衡拦截器给拦住,它能获取拦截请求中的主机名,即上述请求中的 aservice,并把它交给 RibbonLoadBalancerClient。RibbonLoadBalancerClient 又会把服务名交给 DynamicServerListLoadBalancer。DynamicServerListLoadBalancer 就会到 eureka-server 中获取到对应服务的服务列表并交给 IRule。IRule 会从服务列表中基于规则选取其中一个服务,将 ip 和端口号返回给 RibbonLoadBalancerClient。RibbonLoadBalancerClient 就会将请求修改成正确的地址并发送出去,最终获取到数据。
Ribbon 的负载均衡规则是一个叫做 IRule 的接口来定义的,它的每一个子接口都是一种规则![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3N2IzVPg-1656948229570)(C:/Users/bbbbbge/Pictures/接单/1656404672221.png)]](https://1000bd.com/contentImg/2022/07/05/081051274.png)
| 内置负载均衡规则类 | 规则描述 |
|---|---|
| RoundRobinRule | 简单轮询服务列表来选择服务器。它是 Ribbon 默认的负载均衡规则。 |
| WeightedResponseTimeRule | 为每一个服务器赋予一个权重。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,但权重值会影响服务器的选择。 |
| RandomRule | 随机选择一个可用的服务器。 |
| RetryRule | 重试机制的选择逻辑。 |
| ZoneAvoidanceRule | 以区域可用的服务器为基础进行服务器的选择。使用 Zone 对服务器进行分类,这个 Zone 可以理解为一个机房、一个机架。而后再对 Zone 内的的多个服务做轮询。 |
| AvailabilityFilteringRule | 1. 在默认情况下,这台服务器如果3次连接失败,就会被设置为“短路”状态。短路状态将持续30s,如果再次连接失败,短路的时间就会几何级地增加。2. 并发数过高的服务器,如果配置了 AvailabilityFilteringRule 规则,客户端就会将其忽略。 |
修改负载均衡规则方式:
直接在配置类或启动类中定义一个新的 IRule(定义后,该服务调用其它微服务都会使用如下规则)
// 将规则修改成随机选择
@Bean
public IRule randomRule(){
return new RandomRule();
}
在 application.yml 文件中,添加新的配置(配置后,该服务会对指定要调度的服务进行规则配置)
aservice: # 要调度的服务名
ribbon: # 负载均衡规则,修改为要使用的负载均衡的类的名称
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
Ribbon 默认是采用懒加载,即第一次访问时会去创建 LoadBalanceCilent,请求时间很长。而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过下面配置开启饥饿加载:
ribbon:
eager-load:
enabled: true # 开启饥饿加载
clients: # 指定饥饿加载的服务名称
- aservice # 指定对 aservice 服务开启饥饿加载
Nacos 是阿里巴巴的产品,现在是 SpringCloud 中的一个组件,相比于 Eureka 功能更加丰富。
Nacos 的安装方式如下:
下载 Nacos 的安装包,并解压好(下载地址为:https://github.com/alibaba/nacos/tags)
启动 Nacos(进入解压好的 bin 目录,通过控制台执行下面的命令)
# 单机启动 Nacos
startup.cmd -m standalone
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7UdiIyzO-1656948229570)(C:/Users/bbbbbge/Pictures/接单/1656411270965.png)]](https://1000bd.com/contentImg/2022/07/05/081051481.png)
Console 后面的地址就是 Nacos 的控制台地址,Ctrl + 鼠标左键就能够直接打开![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-viTlzdEl-1656948229571)(C:/Users/bbbbbge/Pictures/接单/1656411381451.png)]](https://1000bd.com/contentImg/2022/07/05/081051701.png)
登录 Nacos(默认账号和密码都是 nacos),登录成功后就会跳转到控制台页面![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hfiQWYEi-1656948229571)(C:/Users/bbbbbge/Pictures/接单/1656411465225.png)]](https://1000bd.com/contentImg/2022/07/05/081051852.png)
在父工程中添加 spring-cloud-alilbaba 的管理依赖:
<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>
在指定的服务中添加 nacos 的客户端依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
配置 application.yml 文件
spring:
application:
name: aservice # 服务名
cloud:
nacos:
server-addr: localhost:8848 # nacos 服务地址
运行项目后,指定服务就会注册到 nacos 中。在 nacos 的控制台就可以看到具体的信息。![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8bPlOEdE-1656948229572)(C:/Users/bbbbbge/Pictures/接单/1656424925594.png)]](https://1000bd.com/contentImg/2022/07/05/081052105.png)
通过 RestTemplate 就可以对注册到 nacos 上的服务进行调度。![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LFz7xvbY-1656948229572)(C:/Users/bbbbbge/Pictures/接单/1656425053931.png)]](https://1000bd.com/contentImg/2022/07/05/081052440.png)
一个服务可以分成多个集群,每个集群中又可以包括多个实例。![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-poMyes8m-1656948229572)(C:/Users/bbbbbge/Pictures/接单/1656430009373.png)]](https://1000bd.com/contentImg/2022/07/05/081052765.png)
服务跨集群调用问题:
服务调用尽可能选择本地集群的服务,跨集群调用延迟较高。当本地集群不可访问时,再去访问其它集群。
集群的配置方式:
当我们不配置集群时,Nacos 中集群显示为 DEFAULT,即表示没有集群![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3sfO8pW3-1656948229573)(C:/Users/bbbbbge/Pictures/接单/1656430202934.png)]](https://1000bd.com/contentImg/2022/07/05/081052967.png)
可以在 application.yml 文件中编辑如下配置,去配置集群
spring:
cloud:
nacos:
discovery:
cluster-name: CS # 集群名称
在 aservice 服务中设置好了集群名为 CS 后启动 aservice 的 8080 实例。然后再修改 aservice 的集群名为 HZ 并启动 aservice 的 8082 实例,Nacos 中的集群就会显示下面结果:![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rk2s8fEU-1656948229573)(C:/Users/bbbbbge/Pictures/接单/1656431370468.png)]](https://1000bd.com/contentImg/2022/07/05/081053120.png)
上面已经修改了 aservice 服务的配置,将 aservice 的两个实例分别配置到了两个集群中。不过将 bservice 设置集群名为 CS,当调用 asevice 实例时并不是优先调用的同集群中的 aservice 实例。这是因为服务在选择实例时是通过负载均衡的规则去选择的,而负载均衡的默认规则是轮询调度。因此想要优先调度同集群的实例,就要修改负载均衡的规则。
修改方式如下:
先设置好调度者的服务的集群名
在该服务中设置负载均衡的 IRule 为 NacosRule,这个规则优先会寻找与自己同集群的服务(不过是同集群中随机调度)
aservice: # 要调度的服务名
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # 负载均衡规则
Nacos 提供了权重配置来控制实例的访问频率,权重越大者访问频率越大。
应用场景:
将性能好的机器设置权重多一点,将性能差的机器设置权重少一点。
修改方式如下:
在 Nacos 控制台就可以设置实例的权重值,首先点击实例的编辑按钮![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6qAb8v2i-1656948229573)(C:/Users/bbbbbge/Pictures/接单/1656656597833.png)]](https://1000bd.com/contentImg/2022/07/05/081053262.png)
将权重修改为你要的值即可(权重值在 0~1 之间,0 表示不会被访问到)![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UcPmSWkP-1656948229573)(C:/Users/bbbbbge/Pictures/接单/1656656645890.png)]](https://1000bd.com/contentImg/2022/07/05/081053537.png)
Nacos 中服务存储和数据存储的最外层都是一个名为 namespace 的东西,用来做最外层的隔离。每个 namespace 都有唯一 ID,不同 namespace 下的服务是不可见的。![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qx26IF4V-1656948229574)(C:/Users/bbbbbge/Pictures/接单/1656660480767.png)]](https://1000bd.com/contentImg/2022/07/05/081053734.png)
在 Nacos 控制台我们可以看到,我们注册的实例都默认存放在一个叫 public 的命名空间中![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PuW4rUvr-1656948229574)(C:/Users/bbbbbge/Pictures/接单/1656660625465.png)]](https://1000bd.com/contentImg/2022/07/05/081054035.png)
配置新的命名空间的方式:
在 Nacos 的控制台新建一个命名空间![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TU55tm73-1656948229574)(C:/Users/bbbbbge/Pictures/接单/1656660758688.png)]](https://1000bd.com/contentImg/2022/07/05/081054232.png)
创建好了之后,在服务列表就能看到新创建的命名空间了。![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mwzzzPxr-1656948229575)(C:/Users/bbbbbge/Pictures/接单/1656660883117.png)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dMD5vl2J-1656948229575)(C:/Users/bbbbbge/Pictures/接单/1656660825910.png)]](https://1000bd.com/contentImg/2022/07/05/081054420.png)
修改服务的 application.yml 文件,添加如下配置:
spring:
cloud:
nacos:
discovery:
namespace: a6fedd4e-c8fc-4695-b5d1-60bf72205819 # 命名空间的ID
重启服务![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ynwv4Elt-1656948229575)(C:/Users/bbbbbge/Pictures/接单/1656692676854.png)]](https://1000bd.com/contentImg/2022/07/05/081054594.png)
Nacos 支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式。默认采用临时实例。
配置非临时实例方式:
spring:
cloud:
nacos:
discovery:
ephemeral: false # 设置非临时实例
共同点:
区别:
在 Nacos 控制台中添加配置信息![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8GBcC7d3-1656948229575)(C:/Users/bbbbbge/Pictures/接单/1656695045238.png)]](https://1000bd.com/contentImg/2022/07/05/081054885.png)
在弹出的表单中填写配置信息![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WbasGM6j-1656948229576)(C:/Users/bbbbbge/Pictures/接单/1656695252200.png)]](https://1000bd.com/contentImg/2022/07/05/081055100.png)
当只读取本地配置文件时,步骤如下:![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p1SPDKZx-1656948229576)(C:/Users/bbbbbge/Pictures/接单/1656698700466.png)]](https://1000bd.com/contentImg/2022/07/05/081055269.png)
当需要读取 nacos 控制台中的配置文件时,步骤如下:![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aWRJzyUM-1656948229576)(C:/Users/bbbbbge/Pictures/接单/1656699154549.png)]](https://1000bd.com/contentImg/2022/07/05/081055487.png)
引入 Nacos 的配置管理客户端依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
在服务中的 resources 目录中添加一个 bootstrap.yml 文件(这个文件是引导文件,优先级高于 application.yml)
spring:
application:
name: aservice # 服务名称(与 nacos 控制台配置文件名对应)
profiles:
active: dev # 开发环境,这里是 dev(与 nacos 控制台配置文件名对应)
cloud:
nacos:
server-addr: localhost:8848 # Nacos 地址
config:
file-extension: yaml # 文件后缀名(与 nacos 控制台配置文件名对应)
Nacos 中的配置文件变更后,微服务无需重启就可以感知。不过需要通过下面两种配置实现:
方式一:在 @Value 注入的变量所在类上添加注解 @RefreshScope
@Value该注解的作用是将配置文件的属性读出来,有@Value("${}")和@Value("#{}")两种方式
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LQVBxxUC-1656948229577)(C:/Users/bbbbbge/Pictures/接单/1656700420178.png)]](https://1000bd.com/contentImg/2022/07/05/081055729.png)
方式二:使用 @ConfigurationProperties 注解
上面的例子将会读取配置文件中所有以 pattern 开头的属性,并和 bean 中的字段进行匹配。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NomAYv76-1656948229577)(C:/Users/bbbbbge/Pictures/接单/1656701109062.png)]](https://1000bd.com/contentImg/2022/07/05/081055996.png)
微服务从 nacos 读取配置文件时会读取两个配置:
[服务名]-[spring.profile.active].yaml 环境配置[服务名].yaml 默认配置,多环境共享优先级:
nacos 中的当前环境配置(服务名-环境.yaml)> nacos 中共享配置(服务名.yaml)> 本地配置
基本介绍:
Feign 是一个声明式的 HTTP 客户端,能够帮助我们优雅地实现 HTTP 请求的发送。官方地址:https://github.com/OpenFeign/feign
使用 Feign 步骤如下:
引入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在消费者的启动类中添加 @EnableFeignClients 注解开启 Feign 的功能:
@SpringBootApplication
@EnableFeignClients
public class BApplication {
public static void main(String[] args) {
SpringApplication.run(BApplication.class, args);
}
}
编写 FeignClient 接口:
@FeignClient("aservice") // 要调度的微服务
public interface AClient { // 该接口中包含和 aservice 服务中的多有需要调度的方法
@GetMapping("say/dog")
public String dogSay();
}
使用编写好的 FeignClient 中定义的方法
@RestController
@RequestMapping("b")
public class BController {
@Autowired
private AClient aClient;
@GetMapping("say")
public String bSay(){
return aClient.dogSay();
}
}
Feign 运行自定义配置来覆盖默认配置,可以修改的配置如下:
| 类型 | 作用 | 说明 |
|---|---|---|
| feign.Logger.Level | 修改日志级别 | 包含四种不同的级别:NONE(默认)、BASIC、HEADERS、FULL |
| feign.coder.Decoder | 响应结果的解析器 | HTTP 远程调用的结果做解析,例如解析 json 字符串为 java 对象 |
| feign.coder.Encoder | 请求参数编码 | 将请求参数编码,便于通过 HTTP 请求发送 |
| feign.Contract | 支持的注解格式 | 默认是 SpringMVC 的注解 |
| feign.Retryer | 失败重试机制 | 请求失败的重试机制,默认是没有,不过会使用 Ribbon 的重试 |
配置 Feign 日志有两种方式:
方式一:配置文件方式
全局生效
feign:
client:
config:
default: # default 表示全局配置,即对调度的所有微服务都作如下配置
loggerLevel: Full # 日志级别
局部生效
feign:
client:
config:
aservice: # 具体服务名称,针对某个要被调度的微服务进行配置
loggerLevel: Full # 日志级别
方式二:java 代码方式,需要先声明一个 Bean
public class FeignClientConfiguration{
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.BASIC;
}
}
而后如果是全局配置,则把它放到 @EnableFeignClients 这个注解中
@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class);
如果是局部配置,则把它放到 @FeignClient 这个注解中
@FeignClient(value = "aservice", configuration = FeignClientConfiguration.class);
Feign 底层的客户端实现:
优化 Feign 的性能主要包括:
Feign 添加 HttpClient 的支持方式:
引入依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
配置连接池:
feign:
httpclient:
enabled: true # 开启 feign 对 httpClient 的支持
max-connections: 200 # 最大连接数
max-connections-per-route: 50 # 每个路径的最大连接数
方式一(继承):给消费者的 FeignClient 和提供者的 controller 定义统一的父接口作为标准
方式二(抽取):
首先创建一个 module,命名为 feign-api,然后引入 feign 的 starter 依赖
在 feign-api 中编写提供者的 FeignClient、POJO 和 Feign 的默认配置
在消费者中引入 feign-api 的依赖
重启项目
当定义的 FeignClient 不在 SpringBootApplication 的扫描包范围时,这些 FeignClient 无法使用。有两种方式解决:
方式一:指定 FeignClient 所在包
@EnableFeignClients(basePackages = "com.mmr.feign.clients")
方式二:指定 FeignClient 字节码
@EnableFeignClients(clients = {AClient.class})
网关的功能:
网关的技术实现: 在 SpringCloud 中网关的实现包括两种
Zuul 是基于 Servlet 的实现,属于阻塞式编程。而 SpringCloudGateway 则是基于 Spring5 中提供的 WebFlux,属于响应式编程的实现,具备更好的性能。
搭建网关服务端步骤:
创建新的 module,引入 SpringCloudGateway 和 nacos 的服务发现依赖
<!-- 网关依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- nacos 服务发现依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
编写路由配置及 nacos 地址
server:
port: 10010 # 网关端口
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos 地址
gateway:
routes: # 网关路由配置
- id: a-service # 路由id,自定义,唯一
uri: lb://aservice # 路由的目标地址,lb 表示负载均衡,后面接服务名称
predicates: # 路由断言,用来判断请求是否符合路由规则的条件
- Path=/a/** # 路径匹配,只要是以 /a/ 开头就符合要求
网关路由可以配置的内容包括:
路由断言工厂 Route Predicate Factory 的作用:
配置文件中写的断言规则只是字符串,这些字符串会被 Predicate Factory 读取并处理,转变为路由判断的条件。
Spring 提供了11种基本的 Predicate 工厂:
| 名称 | 说明 | 示例 |
|---|---|---|
| After | 是某个时间点后的请求 | - After=2037-01-20T17:42:47.789-07:00[America/Denver] |
| Before | 是某个时间点之前的请求 | - Before=2037-04-13T15:42:47.433+07:00[Asia/Shanghai] |
| Between | 是某两个时间点之前的请求 | - Between=2037-01-20T17:42:47.789-07[America/Denver],2037-04-13T15:42:47.433+07:00[America/Denver] |
| Cookie | 请求必须包含某些 cookie | - Cookie=chocolate,ch.p |
| Header | 请求必须包含某些 header | - Header-X-Request-Id,\d+ |
| Host | 请求必须是访问某个 host(域名) | - Host=**.somehost.org, * *.anotherhost.org |
| Method | 请求方式必须是指定方式 | - Method=GET,POST |
| Path | 请求路径必须符合指定规则 | - Path=/red/{segment},/blue/** |
| Query | 请求者的参数必须包含指定参数 | - Query=name,jack |
| RemoteAddr | 请求者的ip必须是指定范围 | - RemoteAddr=192.168.1.1/24 |
| Weight | 权重处理 |
GatewayFilter 是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理。
Spring 提供了31种不同的路由过滤器工厂,例如:
| 名称 | 说明 |
|---|---|
| AddRequestHeader | 给当前请求添加一个请求头 |
| RemoveRequestHeader | 移除请求中的请求头 |
| AddResponseHeader | 给响应结果添加一个响应头 |
| RemoveResponseHeader | 从相应结果中移除某个响应头 |
| RequestRateLimiter | 限制请求的流量 |
给某个路由添加过滤器的配置方式:
spring:
cloud:
gateway:
routes: # 网关路由配置
- id: a-service
uri: lb://aservice
predicates:
- Path=/a/**
filters: # 过滤器
- AddRequestHeader=Truth, new header # 添加请求头,键值对用逗号隔开
默认过滤器:
如果要对所有的路由都添加一个过滤器,则可以讲过滤器工厂写到 default-filters 下。
spring:
cloud:
gateway:
routes: # 网关路由配置
- id: a-service
uri: lb://aservice
predicates:
- Path=/a/**
default-filters: # 默认过滤器,会对所有的路由请求都生效
- AddRequestHeader=Truth, new header # 添加请求头,键值对用逗号隔开
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与 GatewayFilter 的作用一样。
区别在于 GatewayFilter 通过配置定义,处理逻辑是固定的。而 GlobalFilter 的逻辑需要自己写代码实现。
定义方式是实现 GlobalFilter 接口:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-08wObZxX-1656948229577)(C:/Users/bbbbbge/Pictures/接单/1656924871151.png)]](https://1000bd.com/contentImg/2022/07/05/081056174.png)
案例:定义全局过滤器,拦截并判断用户身份
需求:参数中是否有 authorization,且 authorization 的参数值是否为 admin
@Order(-1) // 顺序注解,也可以通过实现接口 Ordered
@Component
public class Authorization implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 获取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> queryParams = request.getQueryParams();
// 2. 获取参数中的 authorization 参数
String authorization = queryParams.getFirst("authorization");
// 3. 判断参数值是否等于 admin
if("admin".equals(authorization)){
// 4. 是,放行
return chain.filter(exchange);
}
// 5. 否,拦截
// 5.1 设置状态码,表示未登录
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
// 5.2 拦截请求
return exchange.getResponse().setComplete();
}
}
请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter。
请求路由后,会将当前路由过滤器和 DefaultFilter、GlobalFilter 合并到一个过滤器链(集合)中,排序后以此执行每个过滤器。
过滤器执行顺序:
跨域:域名不一致就是跨域,不要包括:
跨域问题:浏览器禁止请求的发起者与服务端发生跨域 ajax 请求,请求被浏览器拦截的问题
解决方案: CORS
网关处理跨域采用的同样是 CORS 方案,并且只需要简单配置即可实现:
spring:
cloud:
gateway:
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决 options 请求被拦截问题
corsConfigurations:
'[/**]': # 拦截一切请求,都进行跨域处理
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8090"
- "http://www.baidu.com"
allowedMethods: # 允许的跨域 ajax 的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带 cookie
maxAge: 360000 # 这次跨域检测的有效期