SpringCloud

文章目录

  • 第一章 SpringCloud简介
  • SpringCloud软件架构演进
  • 微服务架构
    • 1、微服务理念
    • 2、现在大型互联网公司,都在使用微服务架构:
    • 3、springcloud组件:
  • 第二章 走进springcloud
  • 了解springcloud
  • dubbo对比
  • 第三章 停更/升级/替换
  • 第四章 微服务架构编码构建
    • 一、 搭建 Provider 和 Consumer 服务
      • 1、父工程 spring-cloud-parent
      • 2、提供者 eureka-provider
      • 3、消费者 eureka-consumer
    • 二、使用 RestTemplate 完成远程调用(重要)
      • consumer工程中 RestTemplateConfig
      • OrderController
  • 第五章 Eureka服务注册与发现
    • 一、Eureka
    • 二、搭建 Eureka Server 服务
      • eureka-server工程
    • 三、改造 Provider 和 Consumer 称为 Eureka Client
      • Provider工程
      • Consumer
    • 四、Consumer 服务 通过从 Eureka Server 中抓取 Provider 地址,完成远程调用
      • Consumer
    • 五、Euraka配置详解
      • 1、实例信息配置 Eureka Instance
      • 2、客户端特性配置 Eureka Client
      • 3、注册中心端配置 Eureka Server
      • 4、仪表盘配置 Eureka Server
    • 六、高可用
      • 创建eureka-server1
      • 创建eureka-server2
  • 第六章 Zookeeper服务注册与发现
    • 配置文件
    • window启动zookeeper
    • zookeeper-provider
    • zookeeper-consumer
  • 第七章 Consul服务注册与发现
    • 一、 是什么:
    • 二、 怎么用:
      • 1、准备
      • 2、搭建 consul-provider
      • 3、搭建 consul-consumer
    • 三个注册中心的异同 (面试题)
  • 第八章 Ribbon负载均衡服务调用
    • 一、是什么
      • 1、服务端负载均衡
      • 2、客户端负载均衡
    • 二、如何使用
      • 步骤
      • 01eureka-consumer-9000 - 注册为Ribbon
      • 01eureka-provider-8000
    • 三、Ribbon负载均衡策略
    • 四、 设置Ribbon负载均衡策略
      • 方式一:代码
      • 方式二:配置
  • 第九章、OpenFeign服务接口调用
    • 一、概述
    • 二、快速入门
      • 1、在消费端引入 open-feign 依赖:
      • 2、在启动类 添加 @EnableFeignClients 注解,开启Feign功能
      • 3、编写Feign调用接口。复制粘贴被调方的conreoller方法,加上类路径。
      • 4、测试调用
    • 三、其他设置
      • 1、超时设置
      • 2、日志记录
  • 第十章 Hystrix断路器 (豪猪)保险丝
    • 一、概述
    • Hystrix工作流程
      • 官网图例
      • 步骤说明
    • Hystix 主要功能
      • 1、隔离
        • 1、线程池隔离
        • 2、信号量隔离
      • 2、降级:
      • 3、熔断
      • 4、限流
    • 二、服务降级
      • 服务提供方
        • 1、在服务提供方,引入 hystrix 依赖
        • 2、方法
        • 3、使用 @HystrixCommand 注解配置降级方法
        • 4、在启动类上开启Hystrix功能:@EnableCircuitBreaker
      • 测试:
        • 1、出错,服务方降级了 出现异常
        • 2、出错,服务方降级了 超时异常
      • 服务消费方
        • 1、此时使用feign 组件调用,fegin已经集成了 hystrix 组件。
        • 2、定义feign 调用接口实现类,复写方法,即 降级方法
        • 3、在 @FeignClient 注解中使用 fallback 属性设置降级处理类。
        • 4、配置开启
    • 三、熔断
    • 四、熔断监控-运维
    • Turbine聚合监控
      • 1、搭建监控模块
        • 1、创建监控模块
        • 2、引入Turbine聚合监控起步依赖
        • 3、修改application.yml
        • 4、创建启动类
      • 2、修改被监控模块
        • 1、导入依赖:
        • 2、配置Bean
        • 3、启动类上添加注解@EnableHystrixDashboard
      • 3、启动测试
        • 1、启动服务:
        • 2、访问:
    • 特别注意: 根据情况进行配置(重要)
      • 方式一:
      • 方式二:
      • 可能会出现的状态
  • 第十一章 zuul路由网关
  • 第十二章 Gateway新一代网关
    • 一、 概述
    • 二、 快速入门
      • 1、搭建网关模块 api-gateway-server
      • 2、引入依赖:starter-gateway
      • 3、编写启动类
      • 4、编写配置文件
      • 5、启动测试
    • 三、 静态路由
    • 四、动态路由
      • 1、引入eureka-client配置
      • 2、修改uri属性:uri: lb://服务名称
    • 五、微服务名称配置 很少使用
    • 六、过滤器
      • 内置过滤器 局部过滤器:
      • 内置过滤器 全局过滤器: route同级
        • 拓展:(内置过滤器说明,和详细使用)
      • 自定义过滤器
        • 1、自定义 局部过滤器 (麻烦,很少使用)
        • 2、自定义 全局过滤器 常用

作者: gh-xiaohe
gh-xiaohe的博客
觉得博主文章写的不错的话,希望大家三连(✌关注,✌点赞,✌评论),多多支持一下!!!

第一章 SpringCloud简介

SpringCloud软件架构演进

1、单挑架构

SpringCloud_第1张图片

2、垂直结构

SpringCloud_第2张图片

3、分布式架构

把拆封出来小的模块,可以随意的增减

SpringCloud_第3张图片

4、SOA架构

两两服务都可以直接相互调用,会发生服务调用网络非常的繁杂

SpringCloud_第4张图片

5、微服务架构

任意两个服务直接调用,并不需要总线帮助我们调用,而是在注册中心中记录一些,服务所在的位置(记录信息少)

SpringCloud_第5张图片

微服务架构

1、微服务理念

①"微服务”一词源 于 Martin Fowler的名为 Microservices的博文,可以在他的官方博客上找到博客链接

②微服务是系统架构上的一种设计风格,它的主旨是将一个原本独立的系统拆分成多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间一般通过 HTTP 的 RESTfuL API 进行通信协作。

restfull 风格:数据的增删改查,使用http的不同方式。数据传输用json。

  • 查询 GET ip:port/user/1
  • 新增 POST ip:port/user json{username:itlils,age:18}
  • 修改 PUT ip:port/user/1 json{username:itlils,age:19}
  • 删除 DELETE ip:port/user/1

③由于有了轻量级的通信协作基础,所以这些微服务可以使用不同的语言来编写。大厂,各种语言混用。

2、现在大型互联网公司,都在使用微服务架构:

SpringCloud_第6张图片

3、springcloud组件:

用户请求过来之后,访问哪一个后端的微服务

  • 1、先通过网关:过滤非法请求 getway/zuul
  • 2、如何调用,服务注册中心与发现:告诉网关,请求应该转发到哪个微服务 Ribbon
  • 3、用户服务可能启动多份,但是配置是一样的,配置中心共同管理,在网管中用OAuth2用来授权
  • 4、每调用一次服务,统计今天有多少用户,访问了哪些服务,Metrics监控KAirosDB 调用链的监控CAT、日志的监控ELK、健康的检查

SpringCloud_第7张图片

Spring Cloud Netflix

  • Netflix OSS 开源组件集成,包括Eureka、Hystrix、Ribbon、Feign、Zuul等核心组件。

    • Eureka:服务治理组件,包括服务端的注册中心和客户端的服务发现机制;

    • Ribbon:负载均衡的服务调用组件,具有多种负载均衡调用策略;

    • Hystrix:服务容错组件,实现了断路器模式,为依赖服务的出错和延迟提供了容错能力;

    • Feign:基于Ribbon和Hystrix的声明式服务调用组件;

    • Zuul:API网关组件,对请求提供路由及过滤功能。

第二章 走进springcloud

了解springcloud

①Spring Cloud 是 一系列框架的有序集合。

②Spring Cloud 并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来

③通过Spring Boot 风格进行再封装,屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。

④它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、 断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署

dubbo对比

SpringCloud_第8张图片

相同点:Spring Cloud 与 Dubbo 都是实现微服务有效的工具。

不相同点:

  • Dubbo 只是实现了服务治理,而 Spring Cloud 子项目分别覆盖了微服务架构下的众多部件。
  • Dubbo 使用 RPC 通讯协议,Spring Cloud 使用 RESTful 完成通信(三次握手,四次挥手,响应头,响应体),Dubbo 效率略高于 Spring Cloud。

小结:

  • 微服务就是将项目的各个模块拆分为可独立运行、部署、测试的架构设计风格。
  • Spring 公司将其他公司中微服务架构常用的组件整合起来,并使用 SpringBoot 简化其开发、配置。称为 Spring Cloud。
  • Spring Cloud 与 Dubbo都是实现微服务有效的工具。Dubbo 性能更好,而 Spring Cloud 功能更全面。Dubbo 已经融入到spingcloudAlibaba这一套

第三章 停更/升级/替换

红色不维护。

绿色是alibaba一套,推荐使用

SpringCloud_第9张图片

第四章 微服务架构编码构建

SpringCloud_第10张图片

一、 搭建 Provider 和 Consumer 服务

1、父工程 spring-cloud-parent

约定大约配置 见本人博客:

  • 创建工程

  • 使用utf-8编码

  • maven设置 --> 不建议使用系统自带的

pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>

    <groupId>com.ydlclassgroupId>
    <artifactId>spring-cloud-parentartifactId>
    <version>1.0.0version>

    
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.2.11.RELEASEversion>
    parent>

    <properties>
        <maven.compiler.source>8maven.compiler.source>
        <maven.compiler.target>8maven.compiler.target>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
    properties>
    
project>

2、提供者 eureka-provider

SpringCloud_第11张图片

搭建springboot工程:

  • 1、pom 导包
  • 2、配置文件 application.yml
  • 3、主启动类 @SpringBootApplication

pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-cloud-parentartifactId>
        <groupId>com.ydlclassgroupId>
        <version>1.0.0version>
    parent>
    <modelVersion>4.0.0modelVersion>

    <artifactId>eureka-providerartifactId>

    <properties>
        <maven.compiler.source>8maven.compiler.source>
        <maven.compiler.target>8maven.compiler.target>
    properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
    dependencies>

project>

application.yml

server:
  port: 8000

主启动类

package com.ydlclass.provider;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }
}

Goods

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Goods {

    private int id;//商品id
    private String title;//商品名
    private double price;//价格
    private int count;//库存
}

GoodsController

@RestController
@RequestMapping("/goods")
public class GoodsController {

    @Autowired
    private GoodsService goodsService;


    @GetMapping("findById/{id}")
    public Goods findById(@PathVariable("id") int id) {
        Goods goods = goodsService.findById(id);
        return goods;
    }
    
} 

GoodsService

@Service
public class GoodsService {
    @Autowired
    private GoodsDao goodsDao;

    public Goods findById(int id){
        Goods goods = goodsDao.findById(id);
        return goods;
    }
}
}

GoodsDao

@Repository
public class GoodsDao {
    public Goods findById(int id){
        //查数据库
        return new Goods(id,"手机",2000,100);
    }
}

SpringCloud_第12张图片

3、消费者 eureka-consumer

SpringCloud_第13张图片

pom.xml


<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-cloud-parentartifactId>
        <groupId>com.ydlclassgroupId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <modelVersion>4.0.0modelVersion>

    <artifactId>eureka-consumerartifactId>


    <dependencies>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

    dependencies>
project>

Goods

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Goods {

    private int id;//商品id
    private String title;//商品名
    private double price;//价格
    private int count;//库存
}

OrderController

@RestController
@RequestMapping("/order")
public class OrderController {

    @GetMapping("/add/{id}")
    public Goods add(@PathVariable("id") Integer id){
        //业务逻辑
        //1查询商品
        //2减库存
        //3支付
        //4物流

        return new Goods();
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jwhvJMzV-1672322886840)(SpringCloud.assets/image-20220404112103333.e5ed7fec.png)]

二、使用 RestTemplate 完成远程调用(重要)

让order服务发送 http 请求访问到goods服务

  • Spring提供的一种简单便捷的模板类,用于在 java 代码里访问 restful 服务。
  • 其功能与 HttpClient 类似,但是 RestTemplate 实现更优雅,使用更方便。
  • Java Http客户端有很多: httpClient、okhttp 麻烦:新建链接、发请求、断链接

consumer工程中 RestTemplateConfig

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

OrderController

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

     // 下单:应该是post 请求此时是浏览器测试,用get请求
    @GetMapping("/add/{id}")
    public Goods add(@PathVariable("id") Integer id){

        String url = "http://localhost:8000/goods/findById/" + id; // 访问此请求

        /*  返回是数据
            Goods对象的 json串 转换成 实体类
            {
                id: 1,
                title: "手机",
                price: 2000,
                count: 100
            }
        */
        Goods goods = restTemplate.getForObject(url, Goods.class);// responseType: 响应体中

        return goods;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BZegZxTo-1673097028226)(SpringCloud.assets/image-20230101220933439.png)]

第五章 Eureka服务注册与发现

SpringCloud_第14张图片

一、Eureka

  • Eureka 是 Netflix 公司开源的一个服务注册与发现的组件。
  • Eureka 和其他 Netflix 公司的服务组件(例如负载均衡、熔断器、网关等) 一起,被 Spring Cloud 社区整合为Spring-Cloud-Netflix 模块。
  • Eureka 包含两个组件:Eureka Server (注册中心) 和 Eureka Client (服务提供者、服务消费者)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4JYhuAte-1673097028228)(SpringCloud.assets/image-20230104042544641.png)]

二、搭建 Eureka Server 服务

  • (1)创建 eureka-server 模块
  • (2) 引入 SpringCloud 和 euraka-server 相关依赖
  • (3)完成 Eureka Server 相关配置
  • (4)启动该模块

父工程 pom

    
    <parent>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-parentartifactId>
        <version>2.2.11.RELEASEversion>
    parent>

    <properties>

        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
        <java.version>1.8java.version>
        
        <spring-cloud.version>Greenwich.RELEASEspring-cloud.version>
        <lombok.version>RELEASElombok.version>
    properties>


    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-devtoolsartifactId>
                <scope>runtimescope>
                <optional>trueoptional>
            dependency>

            <dependency>
                <groupId>org.projectlombokgroupId>
                <artifactId>lombokartifactId>
                <version>${lombok.version}version>
                <scope>truescope>
            dependency>

            <dependency>
                <groupId>org.springframework.cloudgroupId>
                <artifactId>spring-cloud-dependenciesartifactId>
                <version>${spring-cloud.version}version>
                <type>pomtype>
                <scope>importscope>
            dependency>
        dependencies>
    dependencyManagement>

eureka-server工程

    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
        dependency>
    dependencies>

@EnableEurekaServer eureka的服务端

// 启用EurekaServer
@SpringBootApplication
@EnableEurekaServer
public class EurekaApp {

    public static void main(String[] args) {
        SpringApplication.run(EurekaApp.class,args);
    }
}

eureka 一共有4部分 配置

  • 1、dashboard:eureka的web控制台配置
  • 2、server:eureka的服务端配置
  • 3、client:eureka的客户端配置
  • 4、instance:eureka的实例配置
server:
  port: 8761 # 默认8761 端口

# eureka 配置
# eureka 一共有4部分 配置
# 1. dashboard:eureka的web控制台配置
# 2. server:eureka的服务端配置
# 3. client:eureka的客户端配置
# 4. instance:eureka的实例配置

eureka:
  instance: # eureka的 实例配置
    hostname: localhost # 主机名
  client: # 客户端的属性
    service-url:
      # localhost:8761/eureka
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
    # 是否注册自己 
    register-with-eureka: false # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
    fetch-registry: false # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
  dashboard: # 图形化界面 (默认即可)
    path: /  # 路径
    enabled: true # 默认开启
#  server: # 服务端的属性

SpringCloud_第15张图片

三、改造 Provider 和 Consumer 称为 Eureka Client

① 引 eureka-client 相关依赖
② 完成 eureka client 相关配置
③ 启动测试

Provider工程

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>
@SpringBootApplication
@EnableEurekaClient // 开启Eureka客户端
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class,args);
    }
}

server:
  port: 8001

eureka:
  instance:
    hostname: localhost # 主机名
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
  application:
    name: eureka-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径

Consumer

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>
@EnableDiscoveryClient // 激活DiscoveryClient
@EnableEurekaClient
@SpringBootApplication
public class ConsumerApp {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}
server:
  port: 9000

eureka:
  instance:
    hostname: localhost # 主机名
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
  application:
    name: eureka-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径

四、Consumer 服务 通过从 Eureka Server 中抓取 Provider 地址,完成远程调用

Consumer

OrderController

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient; // 发现客户端

     // 下单:应该是post 请求此时是浏览器测试,用get请求
    @GetMapping("/add/{id}")
    public Goods add(@PathVariable("id") Integer id){

        // 服务发现
        List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER");// 获取实例:实例的名称
        if(instances!=null || instances.size() < 0) {

        }
        // 如果是多个实例,选取一个实例 (比如: 随机或者权重) 策略
        ServiceInstance serviceInstance = instances.get(0);
        String host = serviceInstance.getHost();// ip
        int port = serviceInstance.getPort();// 端口
        System.out.println("host = " + host + " port = " + port);
        String url = "http://" + host + ":" + port + "/goods/findById/" + id;
        Goods goods = restTemplate.getForObject(url, Goods.class);// responseType: 响应体中
        return goods;
    }
}

SpringCloud_第16张图片

主启动类中激活激活 DiscoveryClient

@EnableDiscoveryClient // 激活DiscoveryClient
@EnableEurekaClient
@SpringBootApplication
public class ConsumerApp {

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

五、Euraka配置详解

Eureka包含四个部分的配置

  • instance:当前Eureka Instance实例信息配置
  • client:Eureka Client客户端特性配置
  • server:Eureka Server注册中心特性配置
  • dashboard:Eureka Server注册中心仪表盘配置

    Eureka Instance、Eureka Client、Eureka Server在org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean配置类里,实际上它是com.netflix.appinfo.EurekaInstanceConfig的实现类,替代了netflix的com.netflix.appinfo.CloudInstanceConfig的默认实现。

    Eureka Instance、Eureka Client、Eureka ServerEureka Instance、Eureka Client、Eureka Server的配置信息全部以eureka.instance.xxx的格式配置。

1、实例信息配置 Eureka Instance

eureka:
    instance:
        hostname: localhost # 主机名
        prefer-ip-address: # 是否将自己的ip注册到eureka中,默认false 注册 主机名
        ip-address: # 设置当前实例ip
        instance-id: # 修改instance-id显示
        lease-renewal-interval-in-seconds: 30 # 每一次eureka client 向 eureka server发送心跳的时间间隔   默认
        lease-expiration-duration-in-seconds: 90 # 如果90秒内eureka server没有收到eureka client的心跳包,则剔除该服务  默认   
配置列表
hostname = null 主机名,不配置的时候讲根据操作系统的主机名来获取
preferIpAddress = false 是否优先使用IP地址作为主机名的标识
leaseRenewalIntervalInSeconds = 30 实例续约间隔时间
leaseExpirationDurationInSeconds = 90 实例超时时间,表示最大leaseExpirationDurationInSeconds秒后没有续约,Server就认为他不可用了,随之就会将其剔除。
ipAddress=null 实例的IP地址
instanceId 注册到eureka上的唯一实例ID,不能与相同appname的其他实例重复。
appname = unknown 应用名,首先获取spring.application.name的值,如果取值为空,则取默认unknown。
appGroupName = null 应用组名
instanceEnabledOnit = false 实例注册到Eureka上是,是否立刻开启通讯。有时候应用在准备好服务之前需要一些预处理。
nonSecurePort = 80 非安全的端口
securePort = 443 安全端口
nonSecurePortEnabled = true 是否开启非安全端口通讯
securePortEnabled = false 是否开启安全端口通讯
virtualHostName = unknown 虚拟主机名,首先获取spring.application.name的值,如果取值为空,则取默认unknown。
secureVirtualHostName = unknown 安全虚拟主机名,首先获取spring.application.name的值,如果取值为空,则取默认unknown。
metadataMap = new HashMap(); 实例元数据,可以供其他实例使用。比如spring-boot-admin在监控时,获取实例的上下文和端口。
dataCenterInfo = new MyDataCenterInfo(DataCenterInfo.Name.MyOwn); 实例部署的数据中心。如AWS、MyOwn。
statusPageUrlPath = “/actuator/info” 实例状态页相对url
statusPageUrl = null 实例状态页绝对URL
homePageUrlPath = “/” 实例主页相对URL
homePageUrl = null 实例主页绝对URL
healthCheckUrlUrlPath = “/actuator/health” 实例健康检查相对URL
healthCheckUrl = null 实例健康检查绝对URL
secureHealthCheckUrl = null 实例安全的健康检查绝对URL
namespace = “eureka” 配置属性的命名空间(Spring Cloud中被忽略)

2、客户端特性配置 Eureka Client

eureka:
    client:
        service-url:
       		 # eureka服务端地址,将来客户端使用该地址和eureka进行通信
        	defaultZone: 
        register-with-eureka: # 是否将自己的路径 注册到eureka上。
        fetch-registry: # 是否需要从eureka中抓取数据。
配置列表
enabled=true 是否启用Eureka client。
registryFetchIntervalSeconds=30 定时从Eureka Server拉取服务注册信息的间隔时间
instanceInfoReplicationIntervalSeconds=30 定时将实例信息(如果变化了)复制到Eureka Server的间隔时间。(InstanceInfoReplicator线程)
initialInstanceInfoReplicationIntervalSeconds=40 首次将实例信息复制到Eureka Server的延迟时间。(InstanceInfoReplicator线程)
eurekaServiceUrlPollIntervalSeconds=300 拉取Eureka Server地址的间隔时间(Eureka Server有可能增减)
proxyPort=null Eureka Server的代理端口
proxyHost=null Eureka Server的代理主机名
proxyUserName=null Eureka Server的代理用户名
proxyPassword=null Eureka Server的代理密码
eurekaServerReadTimeoutSeconds=8 从Eureka Server读取信息的超时时间
eurekaServerConnectTimeoutSeconds=5 连接Eureka Server的超时时间
backupRegistryImpl=null Eureka Client第一次启动时获取服务注册信息的调用的回溯实现。Eureka Client启动时首次会检查有没有BackupRegistry的实现类,如果有实现类,则优先从这个实现类里获取服务注册信息。
eurekaServerTotalConnections=200 Eureka client连接Eureka Server的链接总数
eurekaServerTotalConnectionsPerHost=50 Eureka client连接单台Eureka Server的链接总数
eurekaServerURLContext=null 当Eureka server的列表在DNS中时,Eureka Server的上下文路径。如http://xxxx/eureka。
eurekaServerPort=null 当Eureka server的列表在DNS中时,Eureka Server的端口。
eurekaServerDNSName=null 当Eureka server的列表在DNS中时,且要通过DNSName获取Eureka Server列表时,DNS名字。
region=“us-east-1” 实例所属区域。
eurekaConnectionIdleTimeoutSeconds = 30 Eureka Client和Eureka Server之间的Http连接的空闲超时时间。
heartbeatExecutorThreadPoolSize=2 心跳(续约)执行器线程池大小。
heartbeatExecutorExponentialBackOffBound=10 心跳执行器在续约过程中超时后的再次执行续约的最大延迟倍数。默认最大延迟时间=10 * eureka.instance.leaseRenewalIntervalInSeconds
cacheRefreshExecutorThreadPoolSize=2 cacheRefreshExecutord的线程池大小(获取注册信息)
cacheRefreshExecutorExponentialBackOffBound=10 cacheRefreshExecutord的再次执行的最大延迟倍数。默认最大延迟时间=10 *eureka.client.registryFetchIntervalSeconds
serviceUrl= new HashMap();serviceUrl.put(DEFAULT_ZONE, DEFAULT_URL); Eureka Server的分区地址。默认添加了一个defualtZone。也就是最常用的配置eureka.client.service-url.defaultZone=xxx
registerWithEureka=true 是否注册到Eureka Server。
preferSameZoneEureka=true 是否使用相同Zone下的Eureka server。
logDeltaDiff=false 是否记录Eureka Server和Eureka Client之间注册信息的差异
disableDelta=false 是否开启增量同步注册信息。
fetchRemoteRegionsRegistry=null 获取注册服务的远程地区,以逗号隔开。
availabilityZones=new HashMap() 可用分区列表。用逗号隔开。
filterOnlyUpInstances = true 是否只拉取UP状态的实例。
fetchRegistry=true 是否拉取注册信息。
shouldUnregisterOnShutdown = true 是否在停止服务的时候向Eureka Server发起Cancel指令。
shouldEnforceRegistrationAtInit = false 是否在初始化过程中注册服务。

3、注册中心端配置 Eureka Server

eureka:
    server: 
        enable-self-preservation: true # 是否开启自我保护机制,默认true
        eviction-interval-timer-in-ms: 120000  # 120s 清理间隔(单位毫秒,默认是60*1000)
	instance:
        lease-renewal-interval-in-seconds: 30 # 每一次eureka client 向 eureka server发送心跳的时间间隔   默认
        lease-expiration-duration-in-seconds: 90 # 如果90秒内eureka server没有收到eureka client的心跳包,则剔除该服务  默认     
配置列表
enableSelfPreservation=true 是否开启自我保护
renewalPercentThreshold = 0.85 自我保护续约百分比阀值因子。如果实际续约数小于续约数阀值,则开启自我保护
renewalThresholdUpdateIntervalMs = 15 * 60 * 1000 续约数阀值更新频率。
peerEurekaNodesUpdateIntervalMs = 10 * 60 * 1000 Eureka Server节点更新频率。
enableReplicatedRequestCompression = false 是否启用复制请求压缩。
waitTimeInMsWhenSyncEmpty=5 * 60 * 1000 当从其他节点同步实例信息为空时等待的时间。
peerNodeConnectTimeoutMs=200 节点间连接的超时时间。
peerNodeReadTimeoutMs=200 节点间读取信息的超时时间。
peerNodeTotalConnections=1000 节点间连接总数。
peerNodeTotalConnectionsPerHost = 500; 单个节点间连接总数。
peerNodeConnectionIdleTimeoutSeconds = 30; 节点间连接空闲超时时间。
retentionTimeInMSInDeltaQueue = 3 * MINUTES; 增量队列的缓存时间。
deltaRetentionTimerIntervalInMs = 30 * 1000; 清理增量队列中过期的频率。
evictionIntervalTimerInMs = 60 * 1000; 剔除任务频率。
responseCacheAutoExpirationInSeconds = 180; 注册列表缓存超时时间(当注册列表没有变化时)
responseCacheUpdateIntervalMs = 30 * 1000; 注册列表缓存更新频率。
useReadOnlyResponseCache = true; 是否开启注册列表的二级缓存。
disableDelta=false。 是否为client提供增量信息。
maxThreadsForStatusReplication = 1; 状态同步的最大线程数。
maxElementsInStatusReplicationPool = 10000; 状态同步队列的最大容量。
syncWhenTimestampDiffers = true; 当时间差异时是否同步。
registrySyncRetries = 0; 注册信息同步重试次数。
registrySyncRetryWaitMs = 30 * 1000; 注册信息同步重试期间的时间间隔。
maxElementsInPeerReplicationPool = 10000; 节点间同步事件的最大容量。
minThreadsForPeerReplication = 5; 节点间同步的最小线程数。
maxThreadsForPeerReplication = 20; 节点间同步的最大线程数。
maxTimeForReplication = 30000; 节点间同步的最大时间,单位为毫秒。
disableDeltaForRemoteRegions = false; 是否启用远程区域增量。
remoteRegionConnectTimeoutMs = 1000; 远程区域连接超时时间。
remoteRegionReadTimeoutMs = 1000; 远程区域读取超时时间。
remoteRegionTotalConnections = 1000; 远程区域最大连接数
remoteRegionTotalConnectionsPerHost = 500; 远程区域单机连接数
remoteRegionConnectionIdleTimeoutSeconds = 30; 远程区域连接空闲超时时间。
remoteRegionRegistryFetchInterval = 30; 远程区域注册信息拉取频率。
remoteRegionFetchThreadPoolSize = 20; 远程区域注册信息线程数。

4、仪表盘配置 Eureka Server

eureka:
    dashboard: # 
        enabled: true # 是否启用eureka web控制台
        path: / # 设置eureka web控制台默认访问路径

改造 provider

server:
  port: 8001

eureka:
  instance:
    hostname: localhost # 主机名
    prefer-ip-address: true # 将当前实例的ip注册到eureka server 中。默认是false 注册主机名
    ip-address: 127.0.0.1 # 设置当前实例的ip
    instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port} # 设置web控制台显示的 实例id
    lease-renewal-interval-in-seconds: 3 # 每隔3 秒发一次心跳包
    lease-expiration-duration-in-seconds: 9 # 如果9秒没有发心跳包,服务器呀,你把我干掉吧~
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
  application:
    name: eureka-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径

consumer

server:
  port: 9000


eureka:
  instance:
    hostname: localhost # 主机名
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
  application:
    name: eureka-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径

server

server:
  port: 8761 # 默认8761 端口

# eureka 配置
# eureka 一共有4部分 配置
# 1. dashboard:eureka的web控制台配置
# 2. server:eureka的服务端配置
# 3. client:eureka的客户端配置
# 4. instance:eureka的实例配置

eureka:
  instance:
    hostname: localhost # 主机名
    instance-id: # 修改instance-id显示
    prefer-ip-address: true # 将当前实例的ip注册到eureka server 中。默认是false 注册主机名
    ip-address: 127.0.0.1 # 设置当前实例的ip
    lease-renewal-interval-in-seconds: 30 # 每一次eureka client 向 eureka server发送心跳的时间间隔
    lease-expiration-duration-in-seconds: 90 # 如果90秒内eureka server没有收到eureka client的心跳包,则剔除该服务
  client: # 客户端的属性
    service-url:
      # localhost:8761/eureka
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
    # 是否注册自己
    register-with-eureka: false # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
    fetch-registry: false # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
  dashboard: # 图形化界面 (默认即可)
    path: /  # 路径
    enabled: true # 默认开启
#  server: # 服务端的属性
spring:
  application:
    name: eureka-server

六、高可用

SpringCloud_第17张图片

  • 1、准备两个Eureka Server
  • 2、分别进行配置,相互注册
  • 3、Eureka Client 分别注册到这两个 Eureka Server中
  • 4、相互注册,服务名称一致

创建eureka-server1

server:
  port: 8761

eureka:
  instance:
    hostname: eureka-server1 # 主机名
  client:
    service-url:
      defaultZone: http://eureka-server2:8762/eureka
    register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
    fetch-registry: true # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
  server:
    enable-self-preservation: true
    eviction-interval-timer-in-ms: 120000
spring:
  application:
    name: eureka-server-ha

创建eureka-server2

server:
  port: 8762

eureka:
  instance:
    hostname: eureka-server2 # 主机名
  client:
    service-url:
      defaultZone: http://eureka-server1:8761/eureka
    register-with-eureka: true # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
    fetch-registry: true # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
  server:
    enable-self-preservation: true
    eviction-interval-timer-in-ms: 120000
spring:
  application:
    name: eureka-server-ha

修改 C:\Windows\System32\drivers\etc\hosts

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TFFGohSz-1673097146272)(SpringCloud.assets/image-20220406144138369.3a3af0a9.png)]

provider

eureka:
  client:
    service-url:
      defaultZone: http://eureka-server1:8761/eureka,http://eureka-server2:8762/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信

consumer

eureka:
  client:
    service-url:
      defaultZone: http://eureka-server1:8761/eureka,http://eureka-server2:8762/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信

SpringCloud_第18张图片

测试:

1、是否完成相互注册(高可用集群)

2、集群是否完成高可用:能都调用通,一个挂掉,是否能访问

3、高可用测试:停掉一个eureka,依然可以访问consumer。

eureka不更新了,所以淘汰了。

第六章 Zookeeper服务注册与发现

SpringCloud_第19张图片

有的老项目以前是dubbo,升级到微服务,使用zookeeper做注册中心。

zookeeper是一个分布式协调工具,可以实现注册中心功能。dubbo,大数据组件hadoop,hive,kafka。

实质:注册中心换成zk
下载:https://zookeeper.apache.org/

SpringCloud_第20张图片

配置文件

zookeeper\conf zoo_sample.cfg 重新命名为 zoo.cfg

tickTime=2000 # 心跳时间

initLimit=10 # 启示数

syncLimit=5 # 发送请求并确认,可以通过的数量

dataDir=F:/apache-zookeeper-3.5.6-bin/data  # 数据存放的位置

clientPort=2181 # 默认端口号

SpringCloud_第21张图片

window启动zookeeper

启动 : 在bin目录下 cmd zkServer.cmd 启动

zkServer.cmd # 服务端
zkCli.cmd  # 客户端

SpringCloud_第22张图片

zookeeper-provider

<artifactId>zookeeper-providerartifactId>

    <dependencies>
    
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        
        <artifactId>spring-cloud-starter-zookeeper-discoveryartifactId>
        <exclusions>
            <exclusion>
                <groupId>org.apache.zookeepergroupId>
                <artifactId>zookeeperartifactId>
            exclusion>
        exclusions>
    dependency>
    <dependency>
        
        <groupId>org.apache.zookeepergroupId>
        <artifactId>zookeeperartifactId>
        <version>3.7.0version>
        <exclusions>
            
            <exclusion>
                <groupId>org.slf4jgroupId>
                <artifactId>slf4j-log4j12artifactId>
            exclusion>
        exclusions>
    dependency>
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <optional>trueoptional>
    dependency>
    dependencies>
server:
  port: 8004

spring:
  application:
    name: zookeeper-provider
  cloud:
    zookeeper:
      connect-string: 127.0.0.1:2181 # zk地址

Zookeeper、Eureka、Consul 无所谓,都是注册到注册中心的客户端

@SpringBootApplication
@EnableDiscoveryClient // 开启发现客户端 是Zookeeper、Eureka、Consul 无所谓,都是注册到注册中心的客户端
public class ZookeeperProvider {
    public static void main(String[] args) {
        SpringApplication.run(ZookeeperProvider.class, args);
    }
}

业务逻辑代码直接复制粘贴过来

SpringCloud_第23张图片

Zookeeper客户端信息查看

# zookeeper 客户端
[zk: localhost:2181(CONNECTED) 0] ls /		# zookeeper-provider 未启动 
[zookeeper]
[zk: localhost:2181(CONNECTED) 1] ls /		# zookeeper-provider 启动后 
[services, zookeeper]
[zk: localhost:2181(CONNECTED) 2] ls /services # 可以发现服务已经注册上
[zookeeper-provider]
[zk: localhost:2181(CONNECTED) 3] ls /services/zookeeper-provider # 节点的id,记录一些信息
[4774a514-8395-4d2d-87fa-dd2a4344e349]
[zk: localhost:2181(CONNECTED) 4] ls /services/zookeeper-provider/4774a514-8395-4d2d-87fa-dd2a4344e349
[]
# 服务的提供者已经注册到 zookeeper 中

zookeeper-consumer

   <artifactId>zookeeper-consumerartifactId>

    <dependencies>
    
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        
        <artifactId>spring-cloud-starter-zookeeper-discoveryartifactId>
        <exclusions>
            <exclusion>
                <groupId>org.apache.zookeepergroupId>
                <artifactId>zookeeperartifactId>
            exclusion>
        exclusions>
    dependency>
    <dependency>
        
        <groupId>org.apache.zookeepergroupId>
        <artifactId>zookeeperartifactId>
        <version>3.7.0version>
        <exclusions>
            
            <exclusion>
                <groupId>org.slf4jgroupId>
                <artifactId>slf4j-log4j12artifactId>
            exclusion>
        exclusions>
    dependency>
    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <optional>trueoptional>
    dependency>
    dependencies>
server:
  port: 8005

spring:
  application:
    name: zookeeper-consumer
  cloud:
    zookeeper:
      connect-string: 127.0.0.1:2181 # zk地址
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

业务逻辑代码直接复制粘贴过来

SpringCloud_第24张图片

修改控制层中的 服务发现名称

List<ServiceInstance> instances = discoveryClient.getInstances("zookeeper-provider");

SpringCloud_第25张图片

SpringCloud_第26张图片

Zookeeper客户端信息查看

[zk: localhost:2181(CONNECTED) 5] ls /
[services, zookeeper]
[zk: localhost:2181(CONNECTED) 6] ls /services
[zookeeper-consumer, zookeeper-provider]
zookeeper-consumer   zookeeper-provider
[zk: localhost:2181(CONNECTED) 7] ls /services/zookeeper-consumer
[97a2cb66-b0bd-4798-b5ea-4e85bd5bd07e]

第七章 Consul服务注册与发现

SpringCloud_第27张图片

一、 是什么:

  • Consul 是由 HashiCorp 基于 GoLanguage 语言开发的,支持多数据中心,分布式高可用的服务发布和注册服务软件。
  • 用于实现分布式系统的服务发现与配置。
  • 使用起来也较 为简单。具有天然可移植性(支持Linux、windows和Mac OS X);安装包仅包含一个可执行文件,方便部署 。
  • Consul官网:https://www.consul.io/
  • Consul中文文档:https://www.springcloud.cc/spring-cloud-consul.html

二、 怎么用:

1、准备

运行 consul.exe agent -dev

consul.exe agent -dev
# or
consul agent -dev

访问控制台:地址http://localhost:8500/ui/dc1/services

SpringCloud_第28张图片

2、搭建 consul-provider

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-consul-discoveryartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>

    dependencies>
server:
  port: 8006

spring:
  application:
    name: consul-provider
  cloud:
    consul:
      host: 127.0.0.1
      port: 8500
      discovery:
        service-name: ${spring.application.name} # 把服务于叫成什么名字 (此时:把项目名注册上去)
@SpringBootApplication
@EnableDiscoveryClient
public class ConsulProvider {
    public static void main(String[] args) {
        SpringApplication.run(ConsulProvider.class,args);
    }
}

业务逻辑复制

SpringCloud_第29张图片

SpringCloud_第30张图片

3、搭建 consul-consumer

<dependencies>
    <dependency>
        <groupId>org.springframework.cloudgroupId>
        <artifactId>spring-cloud-starter-consul-discoveryartifactId>
    dependency>

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
dependencies>
server:
  port: 8007

spring:
  application:
    name: consul-consumer
  cloud:
    consul:
      host: 127.0.0.1
      port: 8500
      discovery:
        service-name: ${spring.application.name}
@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApp {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApp.class,args);
    }
}

业务逻辑复制

SpringCloud_第31张图片

controller只改一句话

List<ServiceInstance> instances = discoveryClient.getInstances("consul-provider");

SpringCloud_第32张图片

SpringCloud_第33张图片

最终测试调用成功即可:http://localhost:8007/order/add/9
SpringCloud_第34张图片

三个注册中心的异同 (面试题)

cap 面试

  • 1、c:consustency 强一致性
  • 2、a:avalibility 可用性
  • 3、p:partition tolerance 分区容忍性
组件 语言 cap 健康检查 暴露接口 cloud集成
eureka java ap 支持 http 已经集成
zookeeper java cp 支持 tcp 已经集成
consul go cp 支持 http 已经集成

第八章 Ribbon负载均衡服务调用

一、是什么

Netflix公司推出的http和TCP的客户端负载均衡工具。

Ribbon功能:

  • 简化远程调用代码
  • 内置很多负载均衡算法

1、服务端负载均衡

负载均衡算法在服务端,服务端维护服务列表。 负载均衡的操作在服务端

SpringCloud_第35张图片

2、客户端负载均衡

  • 负载均衡算法在客户端
  • 客户端维护服务列表

SpringCloud_第36张图片

二、如何使用

步骤

使用Ribbon 实现负载均衡策略:

  • 1、让 consumer 客户端变成 Ribbon的客户端
    • orderController 中改动 让其调用 服务名 + 路径 就可以 访问
  • 2、idea 创建两个provider的服务
  • 3、启动测试 : Ribbon 默认使用轮询算法
  • 4、自己配置负载均衡策略
    • 方式一:配置类方式
    • 方式二:yml文件方式

01eureka-consumer-9000 - 注册为Ribbon

1、新版的eureka依赖以及集成了Ribbon依赖,所以可以不引用

  
  <dependency>
      <groupId>org.springframework.cloudgroupId>
      <artifactId>spring-cloud-starter-netflix-ribbonartifactId>
 dependency>

SpringCloud_第37张图片

2、声明restTemplate时@LoadBalanced

// 01eureka-consumer-9000

@Configuration
public class RestTemplateConfig {

    @Bean
    @LoadBalanced // 1、进化成Ribbon 的客户端
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

SpringCloud_第38张图片

3、restTemplate请求远程服务时,ip端口替换为服务名

// 01eureka-consumer-9000

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient; // 发现客户端

     // 下单:应该是post 请求此时是浏览器测试,用get请求
    @GetMapping("/add/{id}")
    public Goods add(@PathVariable("id") Integer id){

        // ip 和 端口 就不用书写了 直接写 provider
        String url = "http://EUREKA-PROVIDER/goods/findById/" + id; 
        Goods goods = restTemplate.getForObject(url, Goods.class);

        return goods;
    }
}

SpringCloud_第39张图片

01eureka-provider-8000

1、启动2个eureka-provider-8000

idea设置 能启动两份 provider

  • 修改yml中的端口号

SpringCloud_第40张图片

在这里插入图片描述

是访问8000,还是8001,负载均衡 访问那个 还需一步操作

@RestController
@RequestMapping("/goods")
public class GoodsController {

    @Autowired
    private GoodsService goodsService;

    @Value("${server.port}")
    int port;

    @GetMapping("findById/{id}")
    public Goods findById(@PathVariable("id") int id) {
        Goods goods = goodsService.findById(id);

        goods.setTitle(goods.getTitle()+"|端口号:"+port);
        return goods;
    }

}

SpringCloud_第41张图片

2、多次访问consumer

SpringCloud_第42张图片

    多次刷新,发现:ribbon客户端,默认使用轮询算法,经行负载均衡调用。

三、Ribbon负载均衡策略

内置负载均衡规则类 规则描述
RoundRobinRule 简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。
AvailabilityFilteringRule 对以下两种服务器进行忽略:(1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。注意:可以通过修改配置loadbalancer..connectionFailureCountThreshold来修改连接失败多少次之后被设置为短路状态。默认是3次。(2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上线,可以由客户端的..ActiveConnectionsLimit属性进行配置。
WeightedResponseTimeRule 为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。
ZoneAvoidanceRule 以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。
BestAvailableRule 忽略哪些短路的服务器,并选择并发数较低的服务器。
RandomRule 随机选择一个可用的服务器。
Retry 重试机制的选择逻辑

四、 设置Ribbon负载均衡策略

方式一:代码

consumer工程

1、MyRule 返回想要的规则即可

/**
 * creste by ydlclass.itcast
 */
@Configuration
public class MyRule {
    @Bean
    public IRule rule(){
        return new RandomRule();
    }
}

2、启动类

@RibbonClient(name ="EUREKA-PROVIDER",configuration = MyRule.class)

总结:

  • 1、IRule的具体实现类,看到他带的几个策略的写法。
  • 2、仿照策略的写法,自己写策略。
  • 3、调用不同的其他微服务时,可以采用不同的策略。

方式二:配置

consumer工程

EUREKA-PROVIDER: #远程服务名
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule #策略

作用:方便运维修改,重启。随时切换策略。

第九章、OpenFeign服务接口调用

一、概述

前言:

使用Ribbon调用非常方便 consumer 调用 provider 步骤:

  • 只需把RestTemplate 升级为Ribbon 的客户端 @LoaadBalanced

    • SpringCloud_第43张图片
  • 使用 @LoaadBalanced 的 人RestTemplate 发送一个请求

  • 请求写一个服务名称 就 ok了

    • SpringCloud_第44张图片

    已经很简单了, 但是:想 调用 provider 还需要写 restTemplate (比较麻烦),就想像调用本地方法一样 来进行一个远程调用实现 OpenFeign

  • Feign 是一个声明式的 REST 客户端,它用了基于接口的注解方式,很方便实现客户端像调用本地接口方法一样,进行远程调用。
  • Feign 最初由 Netflix 公司提供,但不支持SpringMVC注解,后由 SpringCloud 对其封装,支持了SpringMVC注解,让使用者更易于接受。
  • https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/#spring-cloud-openfeign

二、快速入门

1、在消费端引入 open-feign 依赖:

<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-openfeignartifactId>
dependency>

2、在启动类 添加 @EnableFeignClients 注解,开启Feign功能

@EnableDiscoveryClient // 激活DiscoveryClient
@EnableEurekaClient
@SpringBootApplication
//@RibbonClient(name ="EUREKA-PROVIDER",configuration = MyRule.class) 方式一: 配置类,实现负载均衡策略
@EnableFeignClients // 开启feign 的调用
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
}

3、编写Feign调用接口。复制粘贴被调方的conreoller方法,加上类路径。

GoodsFeignClient:

  • 注意不要忘记类上面的路径
@FeignClient("EUREKA-PROVIDER")  // Feign 的客户端 调用 EUREKA-PROVIDER 的服务
public interface GoodsFeign {

    /**
     * 调用的是哪个方法那?
     *      不用自己写: 需要调用 01eureka-provider-8000 中的 findById() 方法
     *                  把其方法复制过来即可
     */
    @GetMapping("/goods/findById/{id}")
    public Goods findById(@PathVariable("id") Integer id);
}

SpringCloud_第45张图片

4、测试调用

OrderController

@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private GoodsFeign goodsFeign;

    /**
     * OpenFeign 实现调用
     */
    @GetMapping("/add/{id}")
    public Goods add(@PathVariable("id") Integer id){

        //feign调用
        Goods goods = goodsFeign.findById(id);

        return goods;
        
    }

}

三、其他设置

1、超时设置

  • Feign 底层依赖于 Ribbon 实现负载均衡和远程调用

SpringCloud_第46张图片

  • Ribbon默认1秒超时。

  • 超时配置: yml中

# 设置Ribbon的超时时间
ribbon:
  ConnectTimeout: 1000 # 连接超时时间 默认1s
  ReadTimeout: 3000 # 逻辑处理的超时时间 默认1s

测试:

1、测试连接超时时间,provider都停掉

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8d0Wsu3N-1674454975677)(SpringCloud.assets/image-20230113210623529.png)]

2、测试逻辑处理的超时时间

provider

    @GetMapping("/findById/{id}")
    public Goods findById(@PathVariable("id") Integer id){
        Goods goods = goodsService.findById(id);
        goods.setTitle(goods.getTitle()+"|端口号:"+port);
        
        //模拟业务逻辑比较繁忙
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return goods;
    }

SpringCloud_第47张图片

2、日志记录

1、Feign 只能记录 debug 级别的日志信息。

    包名为程序所在的包 : 只要是com.gh 下用Feign 来远程调用,都把debug级别的日志打印出来

# 设置当前的日志级别 debug,feign只支持记录debug级别的日志
logging:
  level:
    com.gh: debug # 包名为程序所在的包 : 只要是com.gh 下用Feign 来远程调用,都把debug级别的日志打印出来

SpringCloud_第48张图片

2、定义Feign日志级别Bean(定义日志的级别:多详细或者多简略

FeignLogConfig:

  • 1、NONE,不记录
  • 2、BASIC,记录基本的请求行,响应状态码数据
  • 3、HEADERS,记录基本的请求行,响应状态码数据,记录响应头信息
  • 4、FULL;记录完成的请求 响应数据
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class FeignLogConfig {

    /*
        NONE,不记录
        BASIC,记录基本的请求行,响应状态码数据
        HEADERS,记录基本的请求行,响应状态码数据,记录响应头信息
        FULL;记录完成的请求 响应数据
     */

    @Bean
    public Logger.Level level(){
        return Logger.Level.FULL;
    }
}

3、启用该Bean:

GoodsFeignClient:

@FeignClient(value = "FEIGN-PROVIDER",configuration = FeignLogConfig.class)

设置为Full

SpringCloud_第49张图片

设置为headers

SpringCloud_第50张图片

第十章 Hystrix断路器 (豪猪)保险丝

一、概述

重点:能让服务的调用方,够快的知道被调方挂了!不至于说让用户在等待。

Hystix 是 Netflix 开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败(雪崩)。

雪崩:一个服务失败,导致整条链路的服务都失败的情形。

    某一个时间点 tb_D 表数据过多,导致D服务挂了,服务之间是依次调用,所以服务一次挂掉,(一直调不通,每秒可能损失10W笔订单)此现象称之为雪崩
SpringCloud_第51张图片

SpringCloud_第52张图片

Hystrix工作流程

官网介绍https://github.com/Netflix/Hystrix/wiki/How-it-Works

官网图例

SpringCloud_第53张图片

步骤说明

SpringCloud_第54张图片

SpringCloud_第55张图片

Hystix 主要功能

    在调用 挂掉的数据是,1s后拿不到数据,返回给调用的服务,相关的信息,能够较快的感知到信息,返回给用户,让用户知道,用户的操作是成功还是失败

SpringCloud_第56张图片

1、隔离

1、线程池隔离

    调用B、调用C、调用D,C挂了,没调通后进行重试,重试100次,才知道c挂了!(没有hystrix)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tAEKBpGQ-1674455314214)(SpringCloud.assets/image-20220411102317061.a569d3eb.png)]

    使用了hystrix,更细分线程池,B分配 30线程池,C分配 40线程池,D分配 30线程池(设置共100个线程池),让a更快的知道c挂了

SpringCloud_第57张图片

2、信号量隔离

    此时只能有一个线程请求,因为带着认证信息一个线程进行重复的调用重试100次,才知道c挂了,没有hystrix

SpringCloud_第58张图片

    使用了hystrix,更细分线程池,一个带着认证信息的线程,只需要重试40次,让a更快的知道c挂了

SpringCloud_第59张图片

2、降级:

服务提供方降级(异常,超时)

  • 根据id 查goods对象 报错 —> 返回一个特殊对象

    • 1、方法的返回值要和原方法一致

    • 2、方法参数和原方法一样

SpringCloud_第60张图片

消费方降级

SpringCloud_第61张图片

3、熔断

4、限流

是有限流,但是,项目一般不用。nginx或者网关限流。

二、服务降级

服务提供方

1、在服务提供方,引入 hystrix 依赖

		
         <dependency>
             <groupId>org.springframework.cloudgroupId>
             <artifactId>spring-cloud-starter-netflix-hystrixartifactId>
         dependency>

2、方法

    /**
     * 定义一个降级方法   返回特殊对象
     *
     *      1、方法的返回值要和原方法一致
     *      2、方法参数和原方法一样
     */
    public Goods findById_fallback(Integer id) {
        Goods goods = new Goods();
        goods.setId(-1);
        goods.setTitle("provider提供方降级!");
        goods.setPrice(-9.9);
        goods.setCount(-10);

        return goods;
    }

3、使用 @HystrixCommand 注解配置降级方法

    @GetMapping("/findById/{id}")
    @HystrixCommand(fallbackMethod = "findById_fallback",
            commandProperties = {
            //设置Hystrix的超时时间,默认1s
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000")
    })
    public Goods findById(@PathVariable("id") Integer id) {
        Goods goods = goodsService.findById(id);

        // 模拟异常   或者 模拟业务逻辑繁忙
        // 1、模拟异常
//        int a = 1/0;

        // 2、模拟业务逻辑繁忙
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        goods.setTitle(goods.getTitle()+"|端口号:"+port);
        return goods;
    }

SpringCloud_第62张图片

4、在启动类上开启Hystrix功能:@EnableCircuitBreaker

测试:

1、出错,服务方降级了 出现异常

SpringCloud_第63张图片

2、出错,服务方降级了 超时异常

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5s6zJt6T-1674455314216)(SpringCloud.assets/image-20230115161023516.png)]

原因: Hystrix 的默认时间是1s需要自行设置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WyTuGVRh-1674455314216)(SpringCloud.assets/image-20230115160941278.png)]

在理解

SpringCloud_第64张图片

服务消费方

1、此时使用feign 组件调用,fegin已经集成了 hystrix 组件。

SpringCloud_第65张图片

2、定义feign 调用接口实现类,复写方法,即 降级方法

GoodsFeignClientFallback

  • 不要忘记@Component注解
/**
 * GoodsFeign 的实现类
 */
@Component
public class GoodsFeignCallback implements GoodsFeign {
    @Override
    public Goods findById(Integer id) {
        Goods goods = new Goods();
        goods.setId(-2);
        goods.setTitle("调用方降级了!");
        goods.setPrice(-5.5);
        goods.setCount(-5);
        return goods;
    }
}

3、在 @FeignClient 注解中使用 fallback 属性设置降级处理类。

GoodsFeignClient

  • 如果接口调用不通 --> 执行此接口的实现类
/**
 * @author gh  Email:@2495140780qq.com
 * @Description
 * @date 2023-01-13-下午 8:34
 */
 // Feign 的客户端 调用 EUREKA-PROVIDER 的服务 时 , 打印的日志 复杂程度是  FeignLogConfig类中的 配置    失败了(fallback) 执行GoodsFeignCallback类中的方法
@FeignClient(value = "EUREKA-PROVIDER",configuration = FeignLogConfig.class,fallback = GoodsFeignCallback.class)
public interface GoodsFeign {

    /**
     * 调用的是哪个方法那?
     *      不用自己写: 需要调用 01eureka-provider-8000 中的 findById() 方法
     *                  把其方法复制过来即可
     */
    @GetMapping("/goods/findById/{id}")
    public Goods findById(@PathVariable("id") Integer id);
}

4、配置开启

# 开启feign对hystrix的支持
feign:
  hystrix:
    enabled: true

测试:停掉provider

SpringCloud_第66张图片

三、熔断

SpringCloud_第67张图片

测试:

provider --> GoodsController

  • id = 1 报错、 非1 正常执行

SpringCloud_第68张图片

访问两个接口

    id = 1 报错、 非1 正常执行,访问id=10 多少次都是正常执行,访问id =1 报错 提供方降级,此时导致id = 10 同样访问不了,在过一段时间之后,会进入到半开状态,在访问id=10 可以进行正常访问。

SpringCloud_第69张图片

    Hystrix 熔断机制,用于监控微服务调用情况,当失败的情况达到预定的阈值(5秒失败20次),会打开断路器,拒绝所有请求,直到服务恢复正常为止。

circuitBreaker.sleepWindowInMilliseconds:监控时间
circuitBreaker.requestVolumeThreshold:失败次数
circuitBreaker.errorThresholdPercentage:失败率

提供者controller中

  @HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = {
          //设置Hystrix的超时时间,默认1s
        @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"),
          //监控时间 默认5000 毫秒
          @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
          //失败次数。默认20次
          @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"),
          //失败率 默认50%
          @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50")

  })


SpringCloud_第70张图片

四、熔断监控-运维

1色
1圈 实心圆:共有两种含义。它通过颜色的变化代表了实例的健康程度,它的健康度从绿色<黄色<橙色<红色递减。
该实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化,流量越大该实心圆就越大。所以通过该实心圆的展示,就可以在大量的实例中快速的发现故障实例和高压力实例。
1线 曲线:用来记录2分钟内流量的相对变化,可以通过它来观察到流量的上升和下降趋势。

SpringCloud_第71张图片

SpringCloud_第72张图片

  • 1、Hystrix 提供了 Hystrix-dashboard 功能,用于实时监控微服务运行状态。

  • 2、但是Hystrix-dashboard只能监控一个微服务。

  • 3、Netflix 还提供了 Turbine ,进行聚合监控。

SpringCloud_第73张图片

Turbine聚合监控

1、搭建监控模块

1、创建监控模块

创建hystrix-monitor模块,使用Turbine聚合监控多个Hystrix dashboard功能

2、引入Turbine聚合监控起步依赖

  <dependencies>
        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboardartifactId>
        dependency>

        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-turbineartifactId>
        dependency>

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-actuatorartifactId>
        dependency>

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>


        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-testartifactId>
            <scope>testscope>
        dependency>
    dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>

3、修改application.yml

spring:
  application:
    name: hystrix-monitor
server:
  port: 8769
turbine:
  combine-host-port: true
  # 配置需要监控的服务名称列表
  app-config: xxx,xxxx, # 如 :EUREKA-PROVIDER,EUREKA-CONSUMER
  cluster-name-expression: "'default'"
  aggregator:
    cluster-config: default
  #instanceUrlSuffix: /actuator/hystrix.stream
# eureka 所在的位置 本机的 8761 端口  
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
# 根据版本不同进行选择添加      
#hystrix:
#  dashboard:
#    proxy-stream-allow-list: "*"

4、创建启动类

@SpringBootApplication
@EnableEurekaClient
@EnableTurbine //开启Turbine 很聚合监控功能
@EnableHystrixDashboard //开启Hystrix仪表盘监控功能
public class HystrixMonitorApp {
    public static void main(String[] args) {
        SpringApplication.run(HystrixMonitorApp.class,args);
    }
}

2、修改被监控模块

需要分别修改 hystrix-provider 和 hystrix-consumer 模块:

1、导入依赖:

        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-actuatorartifactId>
        dependency>

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-hystrixartifactId>
        dependency>

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboardartifactId>
        dependency>

2、配置Bean

此处为了方便,将其配置在启动类中。

@Configuration
public class HystrixConfig {

    @Bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/actuator/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }
}

3、启动类上添加注解@EnableHystrixDashboard

@EnableHystrixDashboard // 开启Hystrix仪表盘监控功能

3、启动测试

1、启动服务:

  • eureka-server
  • hystrix-provider
  • hystrix-consumer
  • hystrix-monitor

2、访问:

在浏览器访问http://localhost:8769/hystrix/ 进入Hystrix Dashboard界面

SpringCloud_第74张图片

界面中输入监控的Url地址 http://localhost:8769/turbine.stream,监控时间间隔2000毫秒和title,如下图

SpringCloud_第75张图片

  • 实心圆:它有颜色和大小之分,分别代表实例的监控程度和流量大小。如上图所示,它的健康度从绿色、黄色、橙色、红色递减。通过该实心圆的展示,我们就可以在大量的实例中快速的发现故障实例和高压力实例。
  • 曲线:用来记录 2 分钟内流量的相对变化,我们可以通过它来观察到流量的上升和下降趋势。

特别注意: 根据情况进行配置(重要)

方式一:

# 根据版本不同进行选择添加
#hystrix:
#  dashboard:
#    proxy-stream-allow-list: "*"

方式二:

    Hystrix需要在主启动类MainAppHystrix8001中指定监控路径

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker  //Circuit 回路  Breaker 断路器
public class PaymentHystrixMain8001 {
 
    public static void main(String[] args) {
        SpringApplication.run(PaymentHystrixMain8001.class, args);
    }
 
    /**
     *此配置是为了服务监控而配置,与服务容错本身无关,springcloud升级后的坑
     *ServletRegistrationBean因为springboot的默认路径不是"/hystrix.stream",
     *只要在自己的项目里配置上下面的servlet就可以了
     */
    @Bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
        registrationBean.setLoadOnStartup(1);
        registrationBean.addUrlMappings("/hystrix.stream");
        registrationBean.setName("HystrixMetricsStreamServlet");
        return registrationBean;
    }
}

SpringCloud_第76张图片

可能会出现的状态

SpringCloud_第77张图片

第十一章 zuul路由网关

zuul核心人员走了两个,zuul2的研发过久,spring公司等不及,自己研发的Gateway网关。

https://github.com/Netflix/zuul/wiki

第十二章 Gateway新一代网关

功能:路由+过滤

一、 概述

https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.2.1.RELEASE/reference/html/

项目的架构不建议使用

SpringCloud_第78张图片

  • 存在的问题:

    • 1、客户端需要记录不同微服务地址,增加客户端的复杂性
    • 2、每个后台微服务都需要认证
    • 3、http 发请求,涉及到跨域
    • 4、后台新增微服务,不能动态知道地址
  • 使用了网关:

    • 1、网关旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。

    • 2、在微服务架构中,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用N个微服务的接口完成一个用户请求。

    • 3、网关就是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发等

    • 4、在目前的网关解决方案里,有Nginx+ Lua、Netflix Zuul/zuul2 、Spring Cloud Gateway等等

SpringCloud_第79张图片

二、 快速入门

1、搭建网关模块 api-gateway-server

2、引入依赖:starter-gateway

	<dependencies>
        

        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-gatewayartifactId>
        dependency>

        
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>
    dependencies>

3、编写启动类

package com.ydlclass.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class ApiGatewayApp {

    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApp.class,args);
    }

}

4、编写配置文件

server:
  port: 80

spring:
  application:
    name: api-gateway-server

  cloud:
    # 网关配置
    gateway:
      # 路由配置:转发规则
      routes: #集合。
      # id: 唯一标识。默认是一个UUID
      # uri: 转发路径
      # predicates: 条件,用于请求网关路径的匹配规则
      # filters:配置局部过滤器的

      - id: eureka-provider
        # 静态路由
        # uri: http://localhost:8001/
        # 动态路由
        uri: lb://GATEWAY-PROVIDER
        predicates:
        - Path=/goods/**
        filters:
        - AddRequestParameter=username,zhangsan

      - id: eureka-consumer
        # uri: http://localhost:9000
        uri: lb://GATEWAY-CONSUMER
        predicates:
        - Path=/order/**
        # 微服务名称配置
      discovery:
        locator:
          enabled: true # 设置为true 请求路径前可以添加微服务名称
          lower-case-service-id: true # 允许为小写


eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

5、启动测试

http://localhost/goods/findById/2

SpringCloud_第80张图片

三、 静态路由

uri: http://localhost:8000/

四、动态路由

SpringCloud_第81张图片

1、引入eureka-client配置

		<dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka

2、修改uri属性:uri: lb://服务名称

uri: lb://eureka-provider

http://localhost/goods/findById/2

SpringCloud_第82张图片

五、微服务名称配置 很少使用

spring:
  cloud:
    # 网关配置
    gateway:   
    # 微服务名称配置
      discovery:
        locator:
          enabled: true # 设置为true 请求路径前可以添加微服务名称
          lower-case-service-id: true # 允许为小写

SpringCloud_第83张图片

六、过滤器

  • 1、两个维度:
    • 内置过滤器 自定义过滤器
    • 局部过滤器 全局过滤器
  • 2、过滤器种类:
    • 内置局部过滤器
    • 内置全局过滤器
    • 自定义局部过滤器
    • 自定义全局过滤器

SpringCloud_第84张图片

Gateway 支持过滤器功能,对请求或响应进行拦截,完成一些通用操作。

  • Gateway 提供两种过滤器方式:“pre”和“post”

    • # 刚进来走到网关 先做一些事情 在发送给微服务
      pre 过滤器,在转发之前执行,可以做参数校验、权限校验、流量监控、日志输出、协议转换等。  
      
      # 返回给用户之前
      post 过滤器,在响应之前执行,可以做响应内容、响应头的修改,日志的输出,流量监控等。	
      
  • Gateway 还提供了两种类型过滤器

    • GatewayFilter:局部过滤器,针对单个路由
      GlobalFilter :全局过滤器,针对所有路由	
      

内置过滤器 局部过滤器:

- id: gateway-provider
     #uri: http://localhost:8001/
     uri: lb://GATEWAY-PROVIDER
     predicates:
     - Path=/goods/**
        filters:
            - AddResponseHeader=foo, bar

SpringCloud_第85张图片

内置过滤器 全局过滤器: route同级

      default-filters:
        - AddResponseHeader=yld,itlils

SpringCloud_第86张图片

拓展:(内置过滤器说明,和详细使用)

内置的过滤器工厂

    这里简单将Spring Cloud Gateway内置的所有过滤器工厂整理成了一张表格。如下:

过滤器工厂 作用 参数
AddRequestHeader 为原始请求添加Header Header的名称及值
AddRequestParameter 为原始请求添加请求参数 参数名称及值
AddResponseHeader 为原始响应添加Header Header的名称及值
DedupeResponseHeader 剔除响应头中重复的值 需要去重的Header名称及去重策略
Hystrix 为路由引入Hystrix的断路器保护 HystrixCommand的名称
FallbackHeaders 为fallbackUri的请求头中添加具体的异常信息 Header的名称
PrefixPath 为原始请求路径添加前缀 前缀路径
PreserveHostHeader 为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host
RequestRateLimiter 用于对请求限流,限流算法为令牌桶 keyResolver、rateLimiter、statusCode、denyEmptyKey、emptyKeyStatus
RedirectTo 将原始请求重定向到指定的URL http状态码及重定向的url
RemoveHopByHopHeadersFilter 为原始请求删除IETF组织规定的一系列Header 默认就会启用,可以通过配置指定仅删除哪些Header
RemoveRequestHeader 为原始请求删除某个Header Header名称
RemoveResponseHeader 为原始响应删除某个Header Header名称
RewritePath 重写原始的请求路径 原始路径正则表达式以及重写后路径的正则表达式
RewriteResponseHeader 重写原始响应中的某个Header Header名称,值的正则表达式,重写后的值
SaveSession 在转发请求之前,强制执行WebSession::save操作
secureHeaders 为原始响应添加一系列起安全作用的响应头 无,支持修改这些安全响应头的值
SetPath 修改原始的请求路径 修改后的路径
SetResponseHeader 修改原始响应中某个Header的值 Header名称,修改后的值
SetStatus 修改原始响应的状态码 HTTP 状态码,可以是数字,也可以是字符串
StripPrefix 用于截断原始请求的路径 使用数字表示要截断的路径的数量
Retry 针对不同的响应进行重试 retries、statuses、methods、series
RequestSize 设置允许接收最大请求包的大小。如果请求包大小超过设置的值,则返回 413 Payload Too Large 请求包大小,单位为字节,默认值为5M
ModifyRequestBody 在转发请求之前修改原始请求体内容 修改后的请求体内容
ModifyResponseBody 修改原始响应体的内容 修改后的响应体内容
Default 为所有路由添加过滤器 过滤器工厂名称及值

Tips每个过滤器工厂都对应一个实现类,并且这些类的名称必须以GatewayFilterFactory结尾,这是Spring Cloud Gateway的一个约定,例如AddRequestHeader对应的实现类为AddRequestHeaderGatewayFilterFactory

官方文档:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.0.RELEASE/single/spring-cloud-gateway.html#_gatewayfilter_factories

1、AddRequestHeader GatewayFilter Factory

为原始请求添加Header,配置示例:

spring:
cloud:
gateway:
routes:
    - id: add_request_header_route
      uri: https://example.org
      filters:
      - AddRequestHeader=X-Request-Foo, Bar

为原始请求添加名为 X-Request-Foo ,值为 Bar 的请求头

2、AddRequestParameter GatewayFilter Factory

为原始请求添加请求参数及值,配置示例:

spring:
cloud:
  gateway:
    routes:
    - id: add_request_parameter_route
      uri: https://example.org
      filters:
      - AddRequestParameter=foo, bar

为原始请求添加名为foo,值为bar的参数,即:foo=bar

3、AddResponseHeader GatewayFilter Factory

为原始响应添加Header,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: add_response_header_route
      uri: https://example.org
      filters:
      - AddResponseHeader=X-Response-Foo, Bar

为原始响应添加名为 X-Request-Foo ,值为 Bar 的响应头

4、DedupeResponseHeader GatewayFilter Factory

DedupeResponseHeader可以根据配置的Header名称及去重策略剔除响应头中重复的值,这是Spring Cloud Greenwich SR2提供的新特性,低于这个版本无法使用。

我们在Gateway以及微服务上都设置了CORS(解决跨域)Header的话,如果不做任何配置,那么请求 -> 网关 -> 微服务,获得的CORS Header的值,就将会是这样的:

Access-Control-Allow-Credentials: true, true
Access-Control-Allow-Origin: https://musk.mars, https://musk.mars

可以看到这两个Header的值都重复了,若想把这两个Header的值去重的话,就需要使用到DedupeResponseHeader,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: dedupe_response_header_route
      uri: https://example.org
      filters:
      # 若需要去重的Header有多个,使用空格分隔
      - DedupeResponseHeader=Access-Control-Allow-Credentials Access-Control-Allow-Origin

去重策略:

  • RETAIN_FIRST:默认值,保留第一个值
  • RETAIN_LAST:保留最后一个值
  • RETAIN_UNIQUE:保留所有唯一值,以它们第一次出现的顺序保留

若想对该过滤器工厂有个比较全面的了解的话,建议阅读该过滤器工厂的源码,因为源码里有详细的注释及示例,比官方文档写得还好:org.springframework.cloud.gateway.filter.factory.DedupeResponseHeaderGatewayFilterFactory

5、Hystrix GatewayFilter Factory

为路由引入Hystrix的断路器保护,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: hystrix_route
      uri: https://example.org
      filters:
      - Hystrix=myCommandName

Hystrix是Spring Cloud第一代容错组件,不过已经进入维护模式,未来Hystrix会被Spring Cloud移除掉,取而代之的是Alibaba Sentinel/Resilience4J。所以本文不做详细介绍了,感兴趣的话可以参考官方文档:

  • Hystrix GatewayFilter Factoryopen in new window

6、FallbackHeaders GatewayFilter Factory

同样是对Hystrix的支持,上一小节所介绍的过滤器工厂支持一个配置参数:fallbackUri,该配置用于当发生异常时将请求转发到一个特定的uri上。而FallbackHeaders这个过滤工厂可以在转发请求到该uri时添加一个Header,这个Header的值为具体的异常信息。配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: ingredients
      uri: lb://ingredients
      predicates:
      - Path=//ingredients/**
      filters:
      - name: Hystrix
        args:
          name: fetchIngredients
          fallbackUri: forward:/fallback
    - id: ingredients-fallback
      uri: http://localhost:9994
      predicates:
      - Path=/fallback
      filters:
      - name: FallbackHeaders
        args:
          executionExceptionTypeHeaderName: Test-Header

这里也不做详细介绍了,感兴趣可以参考官方文档:

  • FallbackHeaders GatewayFilter Factoryopen in new window

7、PrefixPath GatewayFilter Factory

为原始的请求路径添加一个前缀路径,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: prefixpath_route
      uri: https://example.org
      filters:
      - PrefixPath=/mypath

该配置使访问${GATEWAY_URL}/hello 会转发到https://example.org/mypath/hello

8、PreserveHostHeader GatewayFilter Factory

为请求添加一个preserveHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host Header。配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: preserve_host_route
      uri: https://example.org
      filters:
      - PreserveHostHeader

如果不设置,那么名为 Host 的Header将由Http Client控制

9、RequestRateLimiter GatewayFilter Factory

用于对请求进行限流,限流算法为令牌桶。配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: requestratelimiter_route
      uri: https://example.org
      filters:
      - name: RequestRateLimiter
        args:
          redis-rate-limiter.replenishRate: 10
          redis-rate-limiter.burstCapacity: 20

由于另一篇文章中已经介绍过如何使用该过滤器工厂实现网关限流,所以这里就不再赘述了:

  • Spring Cloud Gateway - 扩展open in new window

或者参考官方文档:

  • RequestRateLimiter GatewayFilter Factoryopen in new window

10、RedirectTo GatewayFilter Factory

将原始请求重定向到指定的Url,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: redirect_route
      uri: https://example.org
      filters:
      - RedirectTo=302, https://acme.org

该配置使访问 ${GATEWAY_URL}/hello 会被重定向到 https://acme.org/hello ,并且携带一个 Location:http://acme.org 的Header,而返回客户端的HTTP状态码为302

注意事项:

  • HTTP状态码应为3xx,例如301
  • URL必须是合法的URL,该URL会作为Location Header的值

11、RemoveHopByHopHeadersFilter GatewayFilter Factory

为原始请求删除IETFopen in new window组织规定的一系列Header,默认删除的Header如下:

  • Connection
  • Keep-Alive
  • Proxy-Authenticate
  • Proxy-Authorization
  • TE
  • Trailer
  • Transfer-Encoding
  • Upgrade

可以通过配置去指定仅删除哪些Header,配置示例:

spring:
cloud:
 gateway:
    filter:
      remove-hop-by-hop:
        # 多个Header使用逗号(,)分隔
        headers: Connection,Keep-Alive

12、RemoveRequestHeader GatewayFilter Factory

为原始请求删除某个Header,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: removerequestheader_route
      uri: https://example.org
      filters:
      - RemoveRequestHeader=X-Request-Foo

删除原始请求中名为 X-Request-Foo 的请求头

13、RemoveResponseHeader GatewayFilter Factory

为原始响应删除某个Header,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: removeresponseheader_route
      uri: https://example.org
      filters:
      - RemoveResponseHeader=X-Response-Foo

删除原始响应中名为 X-Request-Foo 的响应头

14、RewritePath GatewayFilter Factory

通过正则表达式重写原始的请求路径,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: rewritepath_route
      uri: https://example.org
      predicates:
      - Path=/foo/**
      filters:
      # 参数1为原始路径的正则表达式,参数2为重写后路径的正则表达式
      - RewritePath=/foo/(?>.*), /$\{segment}

该配置使得访问 /foo/bar 时,会将路径重写为/bar 再进行转发,也就是会转发到 https://example.org/bar。需要注意的是:由于YAML语法,需用$\ 替换 $

15、RewriteResponseHeader GatewayFilter Factory

重写原始响应中的某个Header,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: rewriteresponseheader_route
      uri: https://example.org
      filters:
      # 参数1为Header名称,参数2为值的正则表达式,参数3为重写后的值
      - RewriteResponseHeader=X-Response-Foo, password=[^&]+, password=***

该配置的意义在于:如果响应头中 X-Response-Foo 的值为/42?user=ford&password=omg!what&flag=true,那么就会被按照配置的值重写成/42?user=ford&password=***&flag=true,也就是把其中的password=omg!what重写成了password=***

16、SaveSession GatewayFilter Factory

在转发请求之前,强制执行WebSession::save操作,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: save_session
      uri: https://example.org
      predicates:
      - Path=/foo/**
      filters:
      - SaveSession

主要用在那种像 Spring Session 延迟数据存储(数据不是立刻持久化)的,并希望在请求转发前确保session状态保存情况。如果你将Spring Secutiry于Spring Session集成使用,并想确保安全信息都传到下游机器,你就需要配置这个filter。

17、secureHeaders GatewayFilter Factory

secureHeaders过滤器工厂主要是参考了这篇博客open in new window中的建议,为原始响应添加了一系列起安全作用的响应头。默认会添加如下Headers(包括值):

  • X-Xss-Protection:1; mode=block
  • Strict-Transport-Security:max-age=631138519
  • X-Frame-Options:DENY
  • X-Content-Type-Options:nosniff
  • Referrer-Policy:no-referrer
  • Content-Security-Policy:default-src 'self' https:; font-src 'self' https: data:; img-src 'self' https: data:; object-src 'none'; script-src https:; style-src 'self' https: 'unsafe-inline'
  • X-Download-Options:noopen
  • X-Permitted-Cross-Domain-Policies:none

如果你想修改这些Header的值,那么就需要使用这些Headers对应的后缀,如下:

  • xss-protection-header
  • strict-transport-security
  • frame-options
  • content-type-options
  • referrer-policy
  • content-security-policy
  • download-options
  • permitted-cross-domain-policies

配置示例:

spring:
cloud:
 gateway:
    filter:
      secure-headers:
        # 修改 X-Xss-Protection 的值为 2; mode=unblock
        xss-protection-header: 2; mode=unblock

如果想禁用某些Header,可使用如下配置:

spring:
cloud:
 gateway:
    filter:
      secure-headers:
        # 多个使用逗号(,)分隔
        disable: frame-options,download-options

18、SetPath GatewayFilter Factory

修改原始的请求路径,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: setpath_route
      uri: https://example.org
      predicates:
      - Path=/foo/{segment}
      filters:
      - SetPath=/{segment}

该配置使访问 ${GATEWAY_URL}/foo/bar 时会转发到 https://example.org/bar ,也就是原本的/foo/bar被修改为了/bar

19、SetResponseHeader GatewayFilter Factory

修改原始响应中某个Header的值,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: setresponseheader_route
      uri: https://example.org
      filters:
      - SetResponseHeader=X-Response-Foo, Bar

将原始响应中 X-Response-Foo 的值修改为 Bar

20、SetStatus GatewayFilter Factory

修改原始响应的状态码,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: setstatusstring_route
      uri: https://example.org
      filters:
      # 字符串形式
      - SetStatus=BAD_REQUEST
    - id: setstatusint_route
      uri: https://example.org
      filters:
      # 数字形式
      - SetStatus=401

SetStatusd的值可以是数字,也可以是字符串。但一定要是Spring HttpStatus 枚举类中的值。上面这两种配置都可以返回401这个HTTP状态码。

21、StripPrefix GatewayFilter Factory

用于截断原始请求的路径,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: nameRoot
      uri: http://nameservice
      predicates:
      - Path=/name/**
      filters:
      # 数字表示要截断的路径的数量
      - StripPrefix=2

12

如上配置,如果请求的路径为 /name/bar/foo ,那么则会截断成/foo后进行转发 ,也就是会截断2个路径。

22、Retry GatewayFilter Factory

针对不同的响应进行重试,例如可以针对HTTP状态码进行重试,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: retry_test
      uri: http://localhost:8080/flakey
      predicates:
      - Host=*.retry.com
      filters:
      - name: Retry
        args:
          retries: 3
          statuses: BAD_GATEWAY

可配置如下参数:

  • retries:重试次数
  • statuses:需要重试的状态码,取值在 org.springframework.http.HttpStatus
  • methods:需要重试的请求方法,取值在 org.springframework.http.HttpMethod
  • series:HTTP状态码序列,取值在 org.springframework.http.HttpStatus.Series

23、RequestSize GatewayFilter Factory

设置允许接收最大请求包的大小,配置示例:

spring:
cloud:
 gateway:
    routes:
    - id: request_size_route
    uri: http://localhost:8080/upload
    predicates:
    - Path=/upload
    filters:
    - name: RequestSize
      args:
        # 单位为字节
        maxSize: 5000000

如果请求包大小超过设置的值,则会返回 413 Payload Too Large以及一个errorMessage

24、Modify Request Body GatewayFilter Factory

在转发请求之前修改原始请求体内容,该过滤器工厂只能通过代码配置,不支持在配置文件中配置。代码示例:

@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
 return builder.routes()
     .route("rewrite_request_obj", r -> r.host("*.rewriterequestobj.org")
          .filters(f -> f.prefixPath("/httpbin")
              .modifyRequestBody(String.class, Hello.class, MediaType.APPLICATION_JSON_VALUE,
                  (exchange, s) -> return Mono.just(new Hello(s.toUpperCase())))).uri(uri))
      .build();
}

static class Hello {
  String message;

  public Hello() { }

  public Hello(String message) {
      this.message = message;
  }

  public String getMessage() {
      return message;
  }

  public void setMessage(String message) {
      this.message = message;
  }
}

Tips:该过滤器工厂处于 BETA 状态,未来API可能会变化,生产环境请慎用

25、Modify Response Body GatewayFilter Factory

可用于修改原始响应体的内容,该过滤器工厂同样只能通过代码配置,不支持在配置文件中配置。代码示例:

@Bean
public RouteLocator routes(RouteLocatorBuilder builder) {
 return builder.routes()
     .route("rewrite_response_upper", r -> r.host("*.rewriteresponseupper.org")
          .filters(f -> f.prefixPath("/httpbin")
              .modifyResponseBody(String.class, String.class,
                  (exchange, s) -> Mono.just(s.toUpperCase()))).uri(uri)
      .build();
}

Tips:该过滤器工厂处于 BETA 状态,未来API可能会变化,生产环境请慎用

26、Default Filters

Default Filters用于为所有路由添加过滤器工厂,也就是说通过Default Filter所配置的过滤器工厂会作用到所有的路由上。配置示例:

spring:
cloud:
 gateway:
    default-filters:
    - AddResponseHeader=X-Response-Default-Foo, Default-Bar
    - PrefixPath=/httpbin

自定义过滤器

1、自定义 局部过滤器 (麻烦,很少使用)

StripPrefix的源码 --> 照猫画虎

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.cloud.gateway.filter.factory;

import java.util.Arrays;
import java.util.List;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.support.GatewayToStringStyler;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

public class StripPrefixGatewayFilterFactory extends AbstractGatewayFilterFactory<StripPrefixGatewayFilterFactory.Config> {
    public static final String PARTS_KEY = "parts";

    public StripPrefixGatewayFilterFactory() {
        super(StripPrefixGatewayFilterFactory.Config.class);
    }

    public List<String> shortcutFieldOrder() {
        return Arrays.asList("parts");
    }

    public GatewayFilter apply(StripPrefixGatewayFilterFactory.Config config) {
        return new GatewayFilter() {
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                ServerHttpRequest request = exchange.getRequest();
                ServerWebExchangeUtils.addOriginalRequestUrl(exchange, request.getURI());
                String path = request.getURI().getRawPath();
                String[] originalParts = StringUtils.tokenizeToStringArray(path, "/");
                StringBuilder newPath = new StringBuilder("/");

                for(int i = 0; i < originalParts.length; ++i) {
                    if (i >= config.getParts()) {
                        if (newPath.length() > 1) {
                            newPath.append('/');
                        }

                        newPath.append(originalParts[i]);
                    }
                }

                if (newPath.length() > 1 && path.endsWith("/")) {
                    newPath.append('/');
                }

                ServerHttpRequest newRequest = request.mutate().path(newPath.toString()).build();
                exchange.getAttributes().put(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());
                return chain.filter(exchange.mutate().request(newRequest).build());
            }

            public String toString() {
                return GatewayToStringStyler.filterToStringCreator(StripPrefixGatewayFilterFactory.this).append("parts", config.getParts()).toString();
            }
        };
    }

    public static class Config {
        private int parts;

        public Config() {
        }

        public int getParts() {
            return this.parts;
        }

        public void setParts(int parts) {
            this.parts = parts;
        }
    }
}

2、自定义 全局过滤器 常用

需求:

  • 1、黑客ip,直接给你拒接掉。
  • 2、某些请求路径 如“goods/findById”,危险操作,记录日志。

自定义全局过滤器步骤:

  • 1、定义类实现 GlobalFilter 和 Ordered接口
  • 2、复写方法
  • 3、完成逻辑处理

IpFilter

package com.gh.filter;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.InetAddress;
import java.net.InetSocketAddress;


/**
 * 实现Ip拦截过滤器
 *  1、实现两个接口
 *  2、复写方法
 *  3、完成逻辑处理
 */
@Component
public class IpFilter implements GlobalFilter, Ordered {

    // 写业务逻辑
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        // 拿到请求 和 响应

        // 找远程ip
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        InetSocketAddress remoteAddress = request.getRemoteAddress(); // 客户端请求的ip
        System.out.println("remoteAddress = " + remoteAddress);
        String hostName = remoteAddress.getHostName(); // 获取本机主机名称
        System.out.println("hostName = " + hostName);

        InetAddress address = remoteAddress.getAddress();
        System.out.println("address = " + address);
        String hostAddress = address.getHostAddress();  // ip地址
        System.out.println("hostAddress = " + hostAddress);

        String hostName1 = address.getHostName();
        System.out.println("hostName1 = " + hostName1);


        /*
                remoteAddress = /192.168.2.xx:2713
                hostName = DESKTOP-KQD226K.lan
                address = DESKTOP-KQD226K.lan/192.xx.2.128
                hostAddress = 192.168.2.xxx
                hostName1 = DESKTOP-KQD226K.lan
        */
        if (hostAddress.equals("192.168.2.xxx")) {
            // 让此 ip 拒绝访问  正常应该在数据库中获取
            response.setStatusCode(HttpStatus.UNAUTHORIZED); // 设置响应码 401 (未认证)
            return  response.setComplete();
        }

        //走完了,该到下一个过滤器了
        return chain.filter(exchange);
    }

    // 返回一个数值 越小越先执行
    @Override
    public int getOrder() {
        return 0;
    }
}

测试:

http://192.168.2.128/goods/findById/5 不使用localhost 使用自己的ip进行访问

SpringCloud_第87张图片

测试 --> 访问被拦截 把自己的ip设置为拒绝访问的话

SpringCloud_第88张图片

UrlFilter

/**
 * 某些请求路径 如“goods/findById”,危险操作,记录日志。
 */
@Component
public class UrlFilter implements GlobalFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //某些请求路径 如“goods/findById”,危险操作,记录日志。

        //拿到请求和响应,为所欲为
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        URI uri = request.getURI();
        System.out.println("uri = " + uri);

        String path = uri.getPath(); // 路径
        System.out.println(path);

        if(path.contains("goods/findById")){ // 包含路径
            //打日志
            System.out.println("path很危险!");
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 1;
    }
}

SpringCloud_第89张图片

你可能感兴趣的:(spring,cloud,java,微服务)