SpringCloud-Ali

本文详细介绍了如何将Spring Cloud Alibaba的Nacos集成到微服务中,包括服务注册与发现、Nacos集群搭建、Ribbon负载均衡以及Sentinel熔断降级。此外,还探讨了Spring Cloud Gateway作为API网关的配置和使用,以及Nacos配置中心的使用方法。
摘要由CSDN通过智能技术生成

概述

  • Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用服务的必需组件。
  • 方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。
  • 依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置。
  • 就可以将 Spring Cloud 应用接入阿里分布式应用解决方案,通过阿里中间件来迅速搭建分布式应用系统。
版本介绍

组件关系

在这里插入图片描述

依赖关系
在这里插入图片描述

Nacos概述

什么是Nacos

  • Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集。
  • 帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。
    关键特性

搭建NacosServer

  • 官网下载解压启动

在这里插入图片描述

  • 打开浏览器, 在浏览器当中输入: http://localhost:8848/nacos/
  • 账号:nacos
  • 密码:nacos
    在这里插入图片描述

服务注册与发现

工程准备

1.创建父工程 spring-cloud-alibaba-parent ,在父工程当中导入依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.3.RELEASE</version>
</parent>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.1.1.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

2.创建两个子工程 user 与 goods 工程

我创建一个user为例,goods就自己创建了

  • 依赖
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
  • controller
@RestController
public class UserController {

    @RequestMapping("/getUser")
    public ResponseResult getUser() {
        return ResponseResult.success("My User");
    }

}
  • util
public class ResponseResult extends HashMap {
    public static String SUCCESS_CODE = "200";
    public static String ERROR_CODE = "500";
    public static String DATA_KEY = "data";
    public static String MSG_KEY = "msg";

    private ResponseResult() {
    }

    public ResponseResult set(String key, Object object) {
        super.put(key, object);
        return this;
    }

    private static ResponseResult newResponseResult() {
        return new ResponseResult();
    }

    public static ResponseResult success() {
        return ResponseResult.newResponseResult()
                .set("code", ResponseResult.SUCCESS_CODE)
                .set(ResponseResult.MSG_KEY, "操作成功");
    }

    public static ResponseResult success(String msg) {

        return ResponseResult.newResponseResult()
                .set("code", ResponseResult.SUCCESS_CODE)
                .set(ResponseResult.MSG_KEY, msg);
    }

    public static ResponseResult success(String msg, Object object) {

        return ResponseResult.newResponseResult()
                .set("code", ResponseResult.SUCCESS_CODE)
                .set(ResponseResult.MSG_KEY, msg)
                .set(ResponseResult.DATA_KEY, object);
    }

    public ResponseResult data(Object obj) {
        return this.set("data", obj);
    }

    public static ResponseResult error() {
        return ResponseResult.newResponseResult()
                .set(ResponseResult.MSG_KEY, "操作失败")
                .set("code", ResponseResult.ERROR_CODE);
    }

    public static ResponseResult error(String msg) {
        return ResponseResult.newResponseResult()
                .set(ResponseResult.MSG_KEY, msg)
                .set("code", ResponseResult.ERROR_CODE);
    }

    public static ResponseResult error(String msg, Object object) {
        return ResponseResult.newResponseResult()
                .set(ResponseResult.MSG_KEY, msg)
                .set(ResponseResult.DATA_KEY, object)
                .set("code", ResponseResult.ERROR_CODE);
    }

}
  • 启动类
@SpringBootApplication
public class AppUser {
    public static void main(String[] args) {
        SpringApplication.run(AppUser.class, args);
    }
}
  • 配置文件 application.yml
logging:
  level:
    cn.ddossec: debug # 日志级别
server:
  port: 5000 # 端口号
spring:
  application:
    name: consumption-user # 服务名称
  • 在user工程当中添加依赖
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency> 
  • 在启动类上添加注解 @EnableDiscoveryClient

  • 在配置文件添加添加配置

cloud:
  nacos:
    discovery:
      server-addr: localhost:8848 #nacos服务的地址 不要加http
  • 启动工程后, 在nacos当中查询服务列表
    在这里插入图片描述

  • 使用相同方式 把goods服务注册到nacos上

  • 在 user 工程中通过服务发现调用goods工程

  • 在启动类配置 RestTemplate

@Bean
public RestTemplate restTemplate(){
    return new RestTemplate();
}
  • 服务发现调用
@RestController
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private DiscoveryClient discoveryClient;

    @RequestMapping("/getUser")
    public ResponseResult getUser() {
        List<ServiceInstance> instances = discoveryClient.getInstances("provide-goods");
        ServiceInstance serviceInstance = instances.get(0);
        System.out.println(serviceInstance);

        String url = serviceInstance.getUri() + "/getGoods".toString();
        return ResponseResult.success("调用成功",restTemplate.getForObject(url, Object.class));
    }

}

nacos集群

1.编译源码, 支持mysql8数据库

  • 1.下载nacos源码

  • 2.下载后, 修改源码进行编译,把mysql数据库改为mysql8
    修改pom文件
    在这里插入图片描述

  • 修改 MysqlHealthCheckProcessor 导入的包为mysql8的驱动包
    在这里插入图片描述

  • 修改数据库连接配置为mysql8的配置
    在这里插入图片描述

db.url.0=jdbc:mysql://11.162.196.161:3306/diamond_devtest?serverTimezone=GMT%2B8&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.url.1=jdbc:mysql://11.163.152.91:3306/diamond_devtest?serverTimezone=GMT%2B8&characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
  • 进入到源码根目录,使用mvn进行打包
mvn -Prelease-nacos clean install -U -Dmaven.skip.test=true

  • 打包后, 找到nacos-1.1.4\distribution\target\nacos-server-1.1.4\nacos\conf

2.在数据库当中创建 nacos_config,导入nacos中sql数据
在这里插入图片描述

3.复制3份nacos工程,分别配置信息

  • 设置端口号:8849、8850、8851
  • 示例

在这里插入图片描述

在这里插入图片描述

  • 分别设置每一个工程的端口号

  • 设置数据库连接信息

在这里插入图片描述

指定数据源为
Mysqlspring.datasource.platform=mysql
数据库实例数量

db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user=root
db.password=1234
  • 分别设置每一个工程的 application.properties 文件当中进行设置

  • 集群信息

  • 复制一份 cluster.conf.example 文件改为 cluster.conf 配置以下信息

192.168.43.95:8849
192.168.43.95:8850
192.168.43.95:8851
  • 192.168.43.95:是本机IP

在这里插入图片描述

  • 每一份工程复制一份过去就行

4.分别进入到每一份工程bin目录下,修改 startup.cmd

在这里插入图片描述

cluster

  • 修改完毕后,开始分别启动每一个

5.在nginx当中配置反向代理

在这里插入图片描述


upstream nacos {
  server 169.254.108.9:8849;
  server 169.254.108.9:8850;
  server 169.254.108.9:8851;
}
location /nacos {
	proxy_pass http://nacos/nacos;
}

6.启动 nginx 地址栏访问: http://localhost/nacos/

7.将服务注册到Nacos当中,直接写上nginx的地址

在这里插入图片描述

集成Ribbon

使用Ribbon
1.不需要添加依赖

2.在 RestTemplate 上添加注解 @LoadBalanced

在这里插入图片描述

3.在调用时, 就可以使用服务名称来进行调用 , 和之前的使用方式 是一样的

在这里插入图片描述

@RequestMapping("/getGoods")
public ResponseResult getGoods() {
    String url = "http://provide-goods/getGoods";
    return ResponseResult.success("调用成功",restTemplate.getForObject(url, Object.class));
}

默认使用是 轮询 策略

自定义负载均衡策略

配置方式与之前一样
在这里插入图片描述

配置懒加载
在这里插入图片描述

ribbon:
  eager-load:
    enabled: true
    clients: provide-goods  #多个服务使用逗号隔开

Nacos集成Ribbon,支持权重的负载均衡算法
1.自定义权重算法

在这里插入图片描述

public class NacosWeightRule extends AbstractLoadBalancerRule {

@Autowired
private NacosDiscoveryProperties nacosDiscoveryProperties;

@Override
public void initWithNiwsConfig(IClientConfig iClientConfig) {

}

@Override
public Server choose(Object o) {
    BaseLoadBalancer loadBalancer = (BaseLoadBalancer) this.getLoadBalancer();
    // 获取请求微服务的名称
    String name = loadBalancer.getName();
    // 获取nacos服务发现相关名称
    NamingService namingService = nacosDiscoveryProperties.namingServiceInstance();
    // nacos client自动通过基于权重的负载均衡算法,选择实例
    try {
        Instance instance = namingService.selectOneHealthyInstance(name);
        return new NacosServer(instance);
    } catch (NacosException e) {
        e.printStackTrace();
    }
    return null;
}

}
2.配置使用自定义的算法
在这里插入图片描述

3.在nacos服务中心当中配置服务的权重

在这里插入图片描述

集成Feign

使用步骤
在客户端引入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

在启动类上面加上注解 @EnableFeignClients

创建服务 FeignClient

创建一个 service 文件夹,在该文件下创建一个接口

在接口加上添加 @FeignClient() 注解,参数就是你的微服务名字

示例
在这里插入图片描述



@FeignClient(name = "provide-goods")
public interface GoodsFeignClient {

    @RequestMapping("/getGoods")
    public Object getGoods();

}

控制器调用
在这里插入图片描述

单个参数请求
goods工程

在这里插入图片描述

@RequestMapping("/getGoodsWithID/{id}")
public ResponseResult getGoodsWithID(@PathVariable Integer id){
    return ResponseResult.success("goods___id="+id);
}

Feign客户端

在这里插入图片描述


@RequestMapping("/getGoodsWithID/{id}")
public ResponseResult getGoodsWithID(@PathVariable Integer id);

user工程调用
在这里插入图片描述

多个参数请求
goods工程

在这里插入图片描述
Feign客户端
在这里插入图片描述

user工程调用
在这里插入图片描述

Sentinel

什么是 Sentinel
Sentinel是阿里开源的项目,提供了流量控制、熔断降级、系统负载保护等多个维度来保障服务之间的稳定性。

使用 Sentinel

  • 下载 sentinel 控制台服务器

  • 在 jar 目录当中打开控制台,输入 java -jar sentinel-dashboard-1.7.0.jar

在这里插入图片描述

  • 可以修改端口号:
java -Dserver.port=8088 -Dcsp.sentinel.dashboard.server=localhost:8088 -jar sentinel-dashboard-1.7.0.jar

在浏览器当中输入:localhost:8080
在这里插入图片描述

用户名和密码为 sentinel

  • 添加依赖
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
  • 添加配置
    在这里插入图片描述
sentinel:
  transport:
    dashboard: localhost:8080
  • 在浏览器当中进行访问:http://localhost:5000/getGoodsWithId/1

  • 访问完成后,再次查看控制台
    在这里插入图片描述

功能介绍

  • 实时监控
    1、 实时监控aip的执行通过/拒绝和对应响应时长

  • 簇点链路
    1、曾经被访问过的路径
    2、流控
    在这里插入图片描述

  • 资源名称,访问的路径,唯一名称

  • 针对来源
    1、可以针对调用者进行限流
    2、假设两个微服务a和b调用,可以对a和b单独的设置限流规则
    3、default为不区别来源

  • 阈值类型
    1、QPS:当调用api的QPS达到阈值时,就去做限流
    2、线程数:当调用api的线程数达到一定的域值时就去做限流
    3、是否集群
    4、流控模式
    4.1、直接:当违反定义的api规则时, 直接快速失败
    示例
    在这里插入图片描述

一秒种超过一次时, 就会触发限流

在这里插入图片描述

4.2、关联

当关联的资源达到阈值时, 限流自己

示例

在这里插入图片描述
在这里插入图片描述

http://localhost:5000/getGoodsWithObj?name=leader_tblog&id=18 访问时, 就会被限流

查询接口调用过快, 如果影响修改接口,或者修改接口影响查询接口, 根据业务需求,来进行关联限流

4.3、链路

指定资源从入口资源进来的流量,如果达到阈值,就开启限流

4.4、流控效果

  • 快速失败
    直接失败,抛出异常信息
  • Warm Up
    1、根据 codeFactor 从设置的阈值除以codeFactor,经过预热时长,才到达设置的QPS阈值
    2、假设设置的阈值为90 那么就会90/3(默认) 30 作为最初的阈值 ,预热指定的时长 才去达到90的值限流
  • 排队等待
    1、匀速排队,让请求以均匀的速度通过,阈值类型必须设置成QPS,否则无效
    2、超过了定义的时长, 就会抛出异常

代码配置

引入依赖

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.7.0</version>
</dependency>
  • 定义资源名称
private static final String GET_GOODS_KEY = "getMyGoods";
  • 定义限流规则
@RequestMapping("/initFlowRules")
public void initFlowRules(){
    List<FlowRule> rules = new ArrayList<>();
    FlowRule rule = new FlowRule();
    //设置资源名称
    rule.setResource(GET_GOODS_KEY);
    //设置针对来源
    rule.setLimitApp("default");
    //设置阈值类型
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    // 设置阈值
    rule.setCount(1);
    rules.add(rule);
    FlowRuleManager.loadRules(rules);
}
  • 应用到被限流的接口上
@RequestMapping("/getMyGoods")
public String getMyGoods(){
    try (Entry entry = SphU.entry(GET_GOODS_KEY)) {
        // 被保护的逻辑
        return "getMyGoods";
    } catch (BlockException ex) {
        // 处理被流控的逻辑
        return "被限流了";
    }
}

自动执行流控代码

使用 springboot 自带的 ApplicationRunner 接口

使用方式,实现 ApplicationRunner 接口,在 run 方法当中执行流控代码

示例
在这里插入图片描述

@Component
public class SentinelRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        initFlowRules();
    }
    private static final String GET_GOODS_KEY = "getMyGoods";
    public void initFlowRules(){
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        //设置资源名称
        rule.setResource(GET_GOODS_KEY);
        //设置针对来源
        rule.setLimitApp("default");
        //设置阈值类型
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 设置阈值
        rule.setCount(1);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }
}

使用注解改进代码

  • Sentinel 支持通过 @SentinelResource 注解定义资源并配置 blockHandler 和 fallback 函数来进行限流之后的处理
  • blockHandler 函数会在原方法被限流/降级/系统保护的时候调用
  • fallback 函数会针对所有类型的异常
    示例
    在这里插入图片描述
private static final String GET_GOODS_KEY = "getMyGoods";

@SentinelResource(value = GET_GOODS_KEY, blockHandler = "blockHandlerMethod")
@RequestMapping("/getMyGoods")
public String getMyGoods() {
    return "getMyGoods";
}

public String blockHandlerMethod(BlockException e) {
    e.printStackTrace();
    return "被限流了----";
}

降级规则
降级策略

RT

平均响应时间 (DEGRADE_GRADE_RT):当 1s 内持续进入 5 个请求,
对应时刻的平均响应时间(秒级)均超过阈值(count,以 ms 为单位)
那么在接下的时间窗口之内,对这个方法的调用都会自动地熔断

异常比例

当资源的每秒请求量 >= 5,并且每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之后
资源进入降级状态

在这里插入图片描述

在这里插入图片描述

异常次数

当资源近 1 分钟的异常数目超过阈值之后会进行熔断。
注意由于统计时间窗口是分钟级别的,若 timeWindow 小于 60s,则结束熔断状态后仍可能再进入熔断状态。
在这里插入图片描述

热点规则

在这里插入图片描述
在这里插入图片描述

指定索引参数,如果在时间窗口内超过了指定的阈值,就会触发熔断

  • 参数例外项
    1、可以对指定的参数再进行设置限流
    2、参数级别

对指定的参数限流,甚至对指定参数的值进行限流

注意事项

参数必须是基本数据类型或String类型
在这里插入图片描述

系统规则

和其他的规则不太一样,它是针对应用来设的
前面设置的都是争对某一个资源。某一个方法来设置的

阈值类型

load: load是负载,只有在linux机器上才会生效。根据当前系统的负载来决定是不是触发保护。
RT: 这个应用上所有的流量的平均的响应时间,所有服务的平均响应时间超过一个值,那么我就停止接收新的请求。
线程数: 所有服务访问的线程数加起来。
入口qps: 所有服务的qps加起来达到一个值。
cpu使用率: cpu的使用率超过一个百分比
发生以上这些情况的时候把你整个应用给你断掉。所有服务都不提供了

授权规则

使用授权时要先指定来源,对指定来源的内容进行限流

指定来源方式

@Component
public class RequestOrigin implements RequestOriginParser {
    @Override
    public String parseOrigin(HttpServletRequest httpServletRequest) {
        //从请求参数中获取origin的参数并返回
        String origin = httpServletRequest.getParameter("origin");
        //如果获取不到origin 就抛出异常
        if (StringUtils.isBlank(origin)){
            throw new IllegalArgumentException("必须指定origin");
        }
        return origin;
    }
}

在这里插入图片描述

整合Feign

开启 feign 与 Sentinel 集成

feign:
  sentinel:
    enabled: true

整合方式与 Hystrix 一样

规则持久化

使用 Nacos 配置中心实现规则持久化

  • 在 nacos 配置中心当中添加配置 json 规则
[
    {
        "resource": "getMyGoods2",
        "limitApp": "default",
        "grade": 1,
        "count": 5,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

在这里插入图片描述

  • 在工程当中添加依赖
<!--添加此依赖,项目一启动时, 就去到nacos当中读取配置中心-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <version>1.7.0</version>
</dependency>

在配置文件当中添加 sentinel 读取 nacos 地址

eager: true
datasource:
  ds:
    nacos:
      server-addr: localhost:8849
      group-id: DEFAULT_GROUP
      rule-type: flow
      data-id: my-goods-sentinel
      data-type: json

Spring-Cloud-GateWay

概述
什么是 Spring-Cloud-GateWay

Spring Cloud Gateway 基于 Spring Boot 2, 是 Spring Cloud 的 全新 项目, 该项 目 提供 了 一个 构建 在 Spring 生态 之上 的 API 网关
Spring Cloud Gateway 旨在 提供 一种 简单 而 有效 的 途径 来 转发 请求, 并为 它们 提供 横 切 关注 点, 例如: 安全性、 监控/ 指标 和 弹性

优点

性能比较高, 是第一代网关 zuul 的 1.6 倍
功能强大, 内置了很多功能,转发/监控/限流
容易扩展

缺点

实现依赖 Netty 和 WebFlux,不是传统的 Servet 模型
不能将其部署在 Tomcat,Jetty 等 Servelt 容器当中,只能打成 Jar 包执行
需要 springboot2.0 及以上版本才支持

词汇

Route路由: 路由网关的基本构建块。 它由ID,目标URI,谓词集合和过滤器集合定义。 如果聚合谓词为真,则匹配路由
Predicate谓词: 对请求的内容进行匹配,条件筛选
Filter过滤器: 可以对请求进行过滤,在发送下游请求之前或之后修改请求和响应

快速入门

创建 gateWay 服务

添加依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency>
    <dependency>
        <groupId>io.projectreactor.netty</groupId>
        <artifactId>reactor-netty</artifactId>
        <version>0.9.4.RELEASE</version>
    </dependency>
</dependencies>

创建 启动类

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

添加 配置文件

logging:
  pattern:
    console: "%d{HH:mm:ss.SSS} %clr(%5p) %clr(-){faint} %clr(%-80.80logger{79}){cyan} %clr(:) %m%n"

server:
  port: 9000

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      routes: #当请求满足要求时,转发到指定的服务当中
        - id: goods_route  #唯一标识,默认是uuid
          uri: http://localhost:5000/ #请求要转发的地址
          order: 1 #路由优先级 越小, 优先级越高
          predicates: #谓词,断言(条件判断 转发请求要满足什么条件)
            - Path=/consumer-user/**  #当路径中有指定内容时, 才会转发到指定uri
          filters: #过滤器,拦截请求做一些额外处理
            - StripPrefix=1  #去掉添加的path内容

在浏览器 当中访问
http://localhost:9000/consumer-user/getGoodsWithId/1

GateWay整合Nacos

  • 在配置文件中添加 Nacos 的依赖, 把 gatWay 注册到 Nacos 当中
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
  • 在配置文件当中添加 nacos 的地址
cloud:
  nacos:
    discovery:
      server-addr: localhost:80 #nacos服务的地址 不要加http
  • 在启动类上添加注解
    @EnableDiscoveryClient
  • 配置 gateWay 从 nacos 中获取服务信息
discovery:
  locator:
    enabled: true #从nacos当中获取服务信息
  • 信息 uri 为服务地址
    lb: //服务名称
    lb: 为负载均衡调用
    lb: //consumer-user

在这里插入图片描述

谓词
什么是谓词 ( 断言 )
用于对请求进行判断 ,只有断言都返回值,才会真正的执行路由
满足条件,才能进行过滤,转发

内置断言工厂
基于 Datetime

AfterRoutePredicateFactory

判断请求日期是否晚于指定的日期

参数: 传递一个日期

示例

在这里插入图片描述

  • After=2020-12-30T23:59:59.789+08:00[Asia/Shanghai]
    BeforeRoutePredicateFactory

判断请求日期是否早于指定日期

参数: 传递一个日期

BetweenRoutePredicateFactory

判断请求日期是否在指定日期之间

参数: 传递两个日期

基于远程地址

RemoteAddrRoutePredicateFactory

判断请求主机地址是否在指定地址段时

参数: IP地址段

示例

在这里插入图片描述

  • RemoteAddr=192.168.1.1/24

基于 Cookie 的断言

CookieRoutePredicateFactory

判断请求 cookie 是否具有给定名称且值与正则表达式匹配

参数: cookie 名称 , 正则表达式
在这里插入图片描述

示例

  • Cookie=myCookName,[^gao]

基于 header

HeaderRoutePredicateFactory

判断请求 Header 是否具有给定名称且值与正则表达式匹配

参数: 标题名称 , 正则表达式

示例

  • Header=Request-Id,\d+

基于 Host

HostRoutePredicateFactory

判断请求的 Host 是否满足匹配条件

参数: 主机名模式

示例

  • Host=**.testhost.org

基于 Methods

MethodRoutePredicateFactory

判断请求类型是否为指定的类型

参数: 请求类型

示例

  • Method=GET

基于 Query 请求参数

QueryRouterPredicateFactory

判断请求参数是否具有给定名称且值与正则表达式匹配

参数: 请求参数名,正则表达式

示例

  • Query=name,test.

基于权重的断言工厂

WeightRoutePredicateFactory

对于同一组内容的路由,按权重进行转发

参数 : 组名,权重

示例

在这里插入图片描述

两个对于 / weight/** 路径转发的路由定义,这两个路由是同一个权重分组,且 weight_ route1 权重为 1, weight_ route2 权重为 9

对于 10 个访问 /weight/** 路径的请求来说,将会有 9 个路由到 weight_ route2,1 个路由到 weight_ route1

自定义谓词工厂
要求

名字必须是 配置+RoutePredicateFactory
必须继承 AbstractRoutePredicateFactory

方法介绍

List shortcutFieldOrder()

读取配置文件当中的参数,赋值到配置类中的属性上
要求和配置类当中的属性名称一致

Predicate apply

断言逻辑

class Config 内部类

接收配置文件当中对应的参数

示例

在这里插入图片描述
在这里插入图片描述

package cn.ddossec.factory;

import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

@Component
class AppTypeRoutePredicateFactory extends AbstractRoutePredicateFactory<AppTypeRoutePredicateFactory.Config> {

    //构造器
    public AppTypeRoutePredicateFactory() {
        super(AppTypeRoutePredicateFactory.Config.class);
    }

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

    @Override
    public Predicate<ServerWebExchange> apply(AppTypeRoutePredicateFactory.Config config) {
        return new Predicate<ServerWebExchange>() {
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                //接收参数
                String app = serverWebExchange.getRequest().getQueryParams().getFirst("app");
                if (StringUtils.isNotEmpty(app)) {
                    if (config.getAppType().equals(app))
                        return true;
                    else
                        return false;
                }
                return false;
            }
        };
    }


    public static class Config {
        private String appType;

        public Config(String appType) {
            this.appType = appType;
        }

        public String getAppType() {
            return appType;
        }

        public void setAppType(String appType) {
            this.appType = appType;
        }
    }

}

过滤器
什么是过滤器
GatewayFilter 网关过滤器用于拦截并链式处理 web 请求,可以实现横切的与应用无关的需求,比如:安全、访问超时的设置等
在请求传递过程当中,对请求和响应进行一些额外的处理

生命周期
pre

在 pre 类型的过滤器可以做参数校验、权限校验、流量监控、日志输出、协议转换等

post

在 post 类型的过滤器中可以做响应内容、响应头的修改,日志的输出,流量监控等

分类
局部过滤器

只作用在某 一个路由上

全局过滤器

作用在全部路由上

内置局部过滤器

  • AddRequestHeader
    为原始请求添加 Header
    Header 名称及值

  • AddRequestParameter
    为原始请求添加请求参数
    参数名及值

  • AddResponseHeader
    为原始响应添加Header
    Header名称及值

  • DedupeResponseHeader
    剔除响应头中重复的值
    需要去重的Header名称及重复策略

  • Hystrix
    为路由引入 Hystrix 的断路器保护
    HystrixCommand 名称

  • FallBackHeader
    为fallbackUri的请求头中添加具体的异常信息
    Header的名称

  • PrefixPath
    为原始请求添加前缀
    前缀路径

  • PreserveHostHeader
    为请求添加一个PreservHostHeader=true的属性,路由过滤器会检查该属性以决定是否要发送原始的Host
    没有参数

  • RequestRateLimiter
    用于对请求限流

  • RedirectTo
    将原始请求重定向到指定的URL
    http状态码及重定向的url

  • RemoveHopByHopHeadersFilter
    为原始请求删除IETF组织规定的一系列Header
    默认就会启用

  • RewritePath
    重写原始请求路径
    原始路径正则表达式及重写后路径的正则表达式

  • RewriteResponseHeader
    重写原始请求中的某个Header
    Header名称,值的正则表达式,重写后的值

  • SaveSession
    在请求转发之前,强制执行webSession::save操作

  • secureHeaders
    为原始响应添加一系列安全作用的响应头

  • SetStatus
    修改响应的状态码
    HTTP状态码,可以是数字也可以是字符串

  • StripPrefix
    用于截断原始请求的路径
    使用数字表示要截断的路径的数量

  • Retry
    针对不同的响应进行重试

  • RequestSize
    设置允许接收最大请求包的大小
    请求包大小,单位为字节

  • ModifyRequestBody
    在转发请求之前修改原始请求体内容
    修改后的请求体内容

  • ModifyResponseBody
    修改原始响应体的内容
    修改后的响应体内容

自定义局部过滤器
与自定义谓词方式大致一样

@Component
public class LogStatusGatewayFilterFactory extends AbstractGatewayFilterFactory<LogStatusGatewayFilterFactory.Config> {
    public LogStatusGatewayFilterFactory() {
        super(LogStatusGatewayFilterFactory.Config.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("cacheStatus", "consoleStatus");
    }

    @Override
    public GatewayFilter apply(Config config) {
        return new GatewayFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                if (config.getCacheStatus())
                    System.out.println("缓存状态");
                if (config.getConsoleStatus())
                    System.out.println("控制台状态");
                return chain.filter(exchange);
            }
        };
    }

    @Validated
    public static class Config {

        private Boolean cacheStatus;
        private Boolean consoleStatus;

        public Boolean getCacheStatus() {
            return cacheStatus;
        }

        public void setCacheStatus(Boolean cacheStatus) {
            this.cacheStatus = cacheStatus;
        }

        public Boolean getConsoleStatus() {
            return consoleStatus;
        }

        public void setConsoleStatus(Boolean consoleStatus) {
            this.consoleStatus = consoleStatus;
        }
    }
}

全局内置过滤器
在这里插入图片描述

@Component
public class TokenClobalFilter implements GlobalFilter, Ordered {

    /**
     * 过滤器执行的顺序
     * @return
     */
    @Override
    public int getOrder() {
        return 0;
    }

    /**
     * 执行过滤器逻辑
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getQueryParams().getFirst("token");
        if(!"admin".equals(token)){
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }

        return chain.filter(exchange);
    }
}

工作流程
示例图
在这里插入图片描述

介绍

DispatcherHandler

所有请求的调度器,负载请求分发

RoutePredicateHandlerMapping

路由谓语匹配器,用于路由的查找,以及找到路由后返回对应的 WebHandler

DispatcherHandler 会依次遍历 HandlerMapping 集合进行处理

FilteringWebHandler

使用Filter链表处理请求的 WebHandler

RoutePredicateHandlerMapping 找到路由后返回对应的 FilteringWebHandler 对请求进行处理。
FilteringWebHandler 负责组装Filter链表并调用链表处理请求。

Nacos配置中心

概述
Nacos 提供用于存储配置和其他元数据的 key/value 存储,为分布式系统中的外部化配置提供服务器端和客户端支持。
使用 Spring Cloud Alibaba Nacos Config,您可以在 Nacos Server 集中管理你 Spring Cloud 应用的外部属性配置。

快速入门

  • 客户端使用方式
    添加依赖
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

编写 bootstrap.yml 配置文件

spring:
  profiles:
    active: dev  #${spring.profile.active}

  application:
    name: consumer-user  #${prefix}

  cloud:
    nacos:
      config:
        server-addr: localhost:80
        file-extension: yaml  #${file-extension}
  • 在 Nacos 管理中心添加配置
    在这里插入图片描述

动态刷新
在这里插入图片描述

@Value("${user.name}")
private String username;

@RequestMapping("/getUserName")
public String getUserName(){
    return username;
}

在控制器当中添加注解 @RefreshScope

命名空间与分组
namespace 命名空间

用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。
Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
在没有明确指定 ${spring.cloud.nacos.config.namespace} 配置的情况下, 默认使用的是 Nacos 上 Public 这个namespae。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Group 分组

将不同的微服务划分到不同的分组当中

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

DataID

具体的配置文件地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值