第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)

一:Nacos配置管理

1.1:统一配置管理

1.1.1:配置更改热更新

  • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第1张图片
  1. 在Nacos中添加配置信息

    • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第2张图片
  2. 在弹出表单中填写配置信息

    • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第3张图片
  3. 配置获取步骤如下

    • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第4张图片
  4. 引入Nacos的配置管理客户端依赖

    • 
      <dependency>
          <groupId>com.alibaba.cloudgroupId>
          <artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
      dependency>
      
  5. 在userservice中的resource目录添加bootstrap.yml文件,这个文件是引导文件,优先级高于application.yml

    • spring:
        application:
          name: userservice #服务名称
        profiles:
          active: dev #开发环境,这里是dev
        cloud:
          nacos:
            server-addr: localhost:8848 #Nacos地址
            config:
              file-extension: yaml #配置文件后缀
      
  6. 我们在user-service中将pattern.dataformat这个属性注入到UserController中做测试

    • @RestController
      @RequestMapping("/user")
      public class UserController {
          
          // 注入nacos中的配置属性
          @Value("${pattern.dateformat}")
          private String dateformat;
          
          // 编写controller,通过日期格式化器来格式化现在时间并返回
          @GetMapping("now")
          public String now(){
              //这里要使用LoclDateTime。使用LocalDateTime报错【Unsupported field: HourOfDay】
              return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat, Locale.CHINA));
          }
          // ... 略
      }
      

1.1.2:总结

  • 将配置交给Nacos管理的步骤
    1. 在Nacos中添加配置文件
    2. 在微服务中引入nacos的config依赖
    3. 在微服务中添加bootstrap.yml,配置nacos地址、当前环境、服务名称、文件后缀名。这些决定了程序启动时去nacos读取哪个文件。

1.2:配置热更新

1.2.1:配置自动刷新

Nacos中的配置文件变更后,微服务无需重启就可以感知。不过需要通过下面两种配置实现

  • 方式一:在@Vlue注入的变量所在类上添加注解**@RefreshScope**

    • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第5张图片
  • 方式二:使用@ConfigurationProperties注解

    • 创建一个实体类

    • @Component
      @Data
      @ConfigurationProperties(prefix = "pattern")
      public class PatternProperties {
          private String dateformat;
      }
      
    • 将实体类注入

    • @Autowired
      private PatternProperties PatternProperties;
      
      @GetMapping("/now")
      public String now(){
          return LocalDateTime.now().format(DateTimeFormatter.ofPattern(PatternProperties.getDateformat(), Locale.CHINA));
      }
      

1.2.2:总结

  • Nacos配置更改后,微服务可以实现热更新,方式:
    1. 通过@Value注解注入,结合@RefreshScope来刷新
    2. 通过@ConfigurationProperties注入,自动刷新
  • 注意事项:
    • 不是所有的配置都适合放到配置中心,维护起来比较麻烦
    • 建议将一些关键参数,需要运行时调整参数放到nacos配置中心,一般都是自定义配置

1.3:配置共享

1.3.1:多环境配置共享

微服务启动时会从nacos读取多个配置文件

  • 【spring.application.name】-【spring.profiles.active】.yaml,例如:userservice-dev.yaml
  • 【spring.application.name】.yaml,例如:userservice.yaml

无论profile如何变化,【spring.application.name】.yaml这个文件一定会加载,因此多环境配置共享配置可以写入这个文件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iwtpzCG8-1655275466389)(https://limiing-picgo.oss-cn-guangzhou.aliyuncs.com/picgo/image-20220614163242964.png)]

1.3.2:多环境配置优先级:

  • 当前环境配置【服务名称-profile.yaml】 > nacos中的配置【服务名称.yaml】 > 本地配置【application.yaml】

1.3.3:总结

  • 微服务会从Nacos读取配置文件
    1. 【服务名称】- 【spring.profile.active】. yaml,环境配置
    2. 【服务名称】. yaml,默认配置,多环境共享
  • 优先级
    1. 【服务名称】- 【环境】.yaml > 【服务名称】.yaml > 本地配置

1.3.4:多服务共享配置

不同服务之间可以共享配置文件,通过下面的两种方式来指定

  • 方式一:

    • spring:
        application:
          name: userservice #服务名称
        profiles:
          active: dev #开发环境,这里是dev
        cloud:
          nacos:
            server-addr: localhost:8848 #Nacos地址
            config:
              file-extension: yaml #配置文件后缀
              shared-configs: #多服务共享配置列表
                - data-id: common.yaml #要共享的配置文件id
      
  • 方式二:

    • spring:
        application:
          name: userservice #服务名称
        profiles:
          active: dev #开发环境,这里是dev
        cloud:
          nacos:
            server-addr: localhost:8848 #Nacos地址
            config:
              file-extension: yaml #配置文件后缀
              extension-configs:
                - data-id: common.yaml # 配置文件ID
      

1.3.5:多服务共享配置优先级

  • 服务名称-profile.yaml > 服务名称.yaml > extension-configs > shared-configs > 本地配置

1.3.6:总结

  • Nacos默认读取的配置文件:
    1. 【服务名称】- 【spring.profile.active】.yaml,默认配置
    2. 【服务名称】.yaml,多环节共享
  • 不同微服务共享的配置文件
    1. 通过shared-configs 指定
    2. 通过extension-configs指定
  • 优先级:
    • 环境配置 》 服务名称.yaml 》extension-config 》shared-configs》本地配置

1.4:搭建Nacos集群

1.4.1:集群结构图

  • 官方给出的Nacos集群图
    • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第6张图片
  • 其中包含3个nacos节点,然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用Nginx。
  • 我们计划的集群结构:
    • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第7张图片

1.4.2:集群搭建步骤

  • 搭建集群的基本步骤
    • 搭建数据库,初始化数据库表结构
    • 下载 nacos 安装包
    • 配置 nacos
    • 启动nacos集群
    • Nginx反向代理

1.4.3:初始化数据库

Nacos默认数据存储在内嵌数据库Derby中,不属于生产可用的数据库。

  1. 新建一个数据库,名为 nacos,然后导入下面的SQL:

    • CREATE TABLE `config_info` (
        `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
        `data_id` varchar(255) NOT NULL COMMENT 'data_id',
        `group_id` varchar(255) DEFAULT NULL,
        `content` longtext NOT NULL COMMENT 'content',
        `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
        `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
        `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
        `src_user` text COMMENT 'source user',
        `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
        `app_name` varchar(128) DEFAULT NULL,
        `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
        `c_desc` varchar(256) DEFAULT NULL,
        `c_use` varchar(64) DEFAULT NULL,
        `effect` varchar(64) DEFAULT NULL,
        `type` varchar(64) DEFAULT NULL,
        `c_schema` text,
        PRIMARY KEY (`id`),
        UNIQUE KEY `uk_configinfo_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info';
      
      /******************************************/
      /*   数据库全名 = nacos_config   */
      /*   表名称 = config_info_aggr   */
      /******************************************/
      CREATE TABLE `config_info_aggr` (
        `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
        `data_id` varchar(255) NOT NULL COMMENT 'data_id',
        `group_id` varchar(255) NOT NULL COMMENT 'group_id',
        `datum_id` varchar(255) NOT NULL COMMENT 'datum_id',
        `content` longtext NOT NULL COMMENT '内容',
        `gmt_modified` datetime NOT NULL COMMENT '修改时间',
        `app_name` varchar(128) DEFAULT NULL,
        `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
        PRIMARY KEY (`id`),
        UNIQUE KEY `uk_configinfoaggr_datagrouptenantdatum` (`data_id`,`group_id`,`tenant_id`,`datum_id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='增加租户字段';
      
      
      /******************************************/
      /*   数据库全名 = nacos_config   */
      /*   表名称 = config_info_beta   */
      /******************************************/
      CREATE TABLE `config_info_beta` (
        `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
        `data_id` varchar(255) NOT NULL COMMENT 'data_id',
        `group_id` varchar(128) NOT NULL COMMENT 'group_id',
        `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
        `content` longtext NOT NULL COMMENT 'content',
        `beta_ips` varchar(1024) DEFAULT NULL COMMENT 'betaIps',
        `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
        `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
        `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
        `src_user` text COMMENT 'source user',
        `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
        `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
        PRIMARY KEY (`id`),
        UNIQUE KEY `uk_configinfobeta_datagrouptenant` (`data_id`,`group_id`,`tenant_id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_beta';
      
      /******************************************/
      /*   数据库全名 = nacos_config   */
      /*   表名称 = config_info_tag   */
      /******************************************/
      CREATE TABLE `config_info_tag` (
        `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
        `data_id` varchar(255) NOT NULL COMMENT 'data_id',
        `group_id` varchar(128) NOT NULL COMMENT 'group_id',
        `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
        `tag_id` varchar(128) NOT NULL COMMENT 'tag_id',
        `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
        `content` longtext NOT NULL COMMENT 'content',
        `md5` varchar(32) DEFAULT NULL COMMENT 'md5',
        `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
        `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
        `src_user` text COMMENT 'source user',
        `src_ip` varchar(50) DEFAULT NULL COMMENT 'source ip',
        PRIMARY KEY (`id`),
        UNIQUE KEY `uk_configinfotag_datagrouptenanttag` (`data_id`,`group_id`,`tenant_id`,`tag_id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_info_tag';
      
      /******************************************/
      /*   数据库全名 = nacos_config   */
      /*   表名称 = config_tags_relation   */
      /******************************************/
      CREATE TABLE `config_tags_relation` (
        `id` bigint(20) NOT NULL COMMENT 'id',
        `tag_name` varchar(128) NOT NULL COMMENT 'tag_name',
        `tag_type` varchar(64) DEFAULT NULL COMMENT 'tag_type',
        `data_id` varchar(255) NOT NULL COMMENT 'data_id',
        `group_id` varchar(128) NOT NULL COMMENT 'group_id',
        `tenant_id` varchar(128) DEFAULT '' COMMENT 'tenant_id',
        `nid` bigint(20) NOT NULL AUTO_INCREMENT,
        PRIMARY KEY (`nid`),
        UNIQUE KEY `uk_configtagrelation_configidtag` (`id`,`tag_name`,`tag_type`),
        KEY `idx_tenant_id` (`tenant_id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='config_tag_relation';
      
      /******************************************/
      /*   数据库全名 = nacos_config   */
      /*   表名称 = group_capacity   */
      /******************************************/
      CREATE TABLE `group_capacity` (
        `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
        `group_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Group ID,空字符表示整个集群',
        `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
        `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
        `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
        `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数,,0表示使用默认值',
        `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
        `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
        `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
        `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
        PRIMARY KEY (`id`),
        UNIQUE KEY `uk_group_id` (`group_id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='集群、各Group容量信息表';
      
      /******************************************/
      /*   数据库全名 = nacos_config   */
      /*   表名称 = his_config_info   */
      /******************************************/
      CREATE TABLE `his_config_info` (
        `id` bigint(64) unsigned NOT NULL,
        `nid` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
        `data_id` varchar(255) NOT NULL,
        `group_id` varchar(128) NOT NULL,
        `app_name` varchar(128) DEFAULT NULL COMMENT 'app_name',
        `content` longtext NOT NULL,
        `md5` varchar(32) DEFAULT NULL,
        `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
        `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
        `src_user` text,
        `src_ip` varchar(50) DEFAULT NULL,
        `op_type` char(10) DEFAULT NULL,
        `tenant_id` varchar(128) DEFAULT '' COMMENT '租户字段',
        PRIMARY KEY (`nid`),
        KEY `idx_gmt_create` (`gmt_create`),
        KEY `idx_gmt_modified` (`gmt_modified`),
        KEY `idx_did` (`data_id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='多租户改造';
      
      
      /******************************************/
      /*   数据库全名 = nacos_config   */
      /*   表名称 = tenant_capacity   */
      /******************************************/
      CREATE TABLE `tenant_capacity` (
        `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID',
        `tenant_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'Tenant ID',
        `quota` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '配额,0表示使用默认值',
        `usage` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '使用量',
        `max_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个配置大小上限,单位为字节,0表示使用默认值',
        `max_aggr_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '聚合子配置最大个数',
        `max_aggr_size` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '单个聚合数据的子配置大小上限,单位为字节,0表示使用默认值',
        `max_history_count` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '最大变更历史数量',
        `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
        `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
        PRIMARY KEY (`id`),
        UNIQUE KEY `uk_tenant_id` (`tenant_id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='租户容量信息表';
      
      
      CREATE TABLE `tenant_info` (
        `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
        `kp` varchar(128) NOT NULL COMMENT 'kp',
        `tenant_id` varchar(128) default '' COMMENT 'tenant_id',
        `tenant_name` varchar(128) default '' COMMENT 'tenant_name',
        `tenant_desc` varchar(256) DEFAULT NULL COMMENT 'tenant_desc',
        `create_source` varchar(32) DEFAULT NULL COMMENT 'create_source',
        `gmt_create` bigint(20) NOT NULL COMMENT '创建时间',
        `gmt_modified` bigint(20) NOT NULL COMMENT '修改时间',
        PRIMARY KEY (`id`),
        UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
        KEY `idx_tenant_id` (`tenant_id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';
      
      CREATE TABLE `users` (
      	`username` varchar(50) NOT NULL PRIMARY KEY,
      	`password` varchar(500) NOT NULL,
      	`enabled` boolean NOT NULL
      );
      
      CREATE TABLE `roles` (
      	`username` varchar(50) NOT NULL,
      	`role` varchar(50) NOT NULL,
      	UNIQUE INDEX `idx_user_role` (`username` ASC, `role` ASC) USING BTREE
      );
      
      CREATE TABLE `permissions` (
          `role` varchar(50) NOT NULL,
          `resource` varchar(255) NOT NULL,
          `action` varchar(8) NOT NULL,
          UNIQUE INDEX `uk_role_permission` (`role`,`resource`,`action`) USING BTREE
      );
      
      INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);
      
      INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');
      

1.4.5:下载Nacos

Nacos在Github上有下载地址:https://github.com/alibaba/nacos/tags,可用选择任意版本下载。

本例中采用1.4.1版本点击蓝色字体快速下载nacos:1.4.1。

1.4.6:配置Nacos

  • 将这个压缩包解压到任意非中文目录

    • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第8张图片
  • 目录说明

    • bin:启动脚本
    • conf:配置文件
    • data:数据
    • logs:日志
  • 进入nacos的conf目录,修改配置文件,【cluster.conf.example】重命名为【cluster.conf】

    • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第9张图片
  • 然后添加内容

    • 127.0.0.1:8845
      127.0.0.1.8846
      127.0.0.1.8847
      
    • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第10张图片

  • 然后修改application.properties文件,添加数据库配置

    • spring.datasource.platform=mysql
      db.num=1
      db.url.0=jdbc:mysql://rm-uf6727ey7l0dxx162zo.mysql.rds.aliyuncs.com:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
      db.user.0=root
      db.password.0=Zlm200818
      
    • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第11张图片

1.4.7:启动

  • 将Nacos文件夹复制三份,分别命名为:nacos1、nacos2、nacos3

    • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第12张图片
  • 然后分别修改三个文件夹中的application.properties

    • nacos1:

    • server.port=8845
      
    • nacos2

    • server.port=8846
      
    • nacos3

    • server.port=8847
      
  • 分别启动三个nacos节点:

    • startup.cmd
      

1.4.8:Nginx反向代理

  1. 下载Nginx安装包

  2. 解压到任意非中文目录下

  3. 修改conf/nginx.conf文件,配置如下

    • upstream nacos-cluster {
          server 127.0.0.1:8845;
      	server 127.0.0.1:8846;
      	server 127.0.0.1:8847;
      }
      
      server {
          listen       80;
          server_name  localhost;
      
          location /nacos {
              proxy_pass http://nacos-cluster;
          }
      }
      
  4. 而后在浏览器访问:http://localhost/nacos

1.4.9:优化

  • 实际部署时,需要给做反向代理的nginx服务器设置一个域名,这样后续如果有迁移nacos的客户端也无需更改配置
  • Nacos的各个节点应该部署到多个不同服务器,做好容灾和隔离

二:Feign远程调用

2.1:Feign替代RestTemplate

2.1.1:RestTemplate方式调用存在的问题

  • 先来看我们以前利用RestTemplate发起远程调用的代码:
    • image-20220615090639412
  • 存在下面的问题:
    • 代码可读性差,编程体验不统一
    • 参数复杂URL难以维护

2.1.2:Feign的介绍

Feign是一个声明式的http客户端,官方地址:https://github.com/OpenFeign/feign

  • 其作用就是帮助我们优雅的实现http请求的发送,解决上面提到的问题。
  • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第13张图片

2.1.3:定义和使用Feign客户端

  • 使用fenign的步骤如下:
  1. 引入依赖

    • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第14张图片
  2. 在order-service的启动类添加注解开启Feign的功能功能

    • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第15张图片
  3. 编写Feign客户端

    • image-20220615091152059
  • 主要是基于SpringMVC的注解来声明远程调用的信息,比如

    • 服务名称:userservice
    • 请求方式:GET
    • 请求路径:/user/{id}
    • 请求参数:Long id
    • 返回值类型:User
  1. 用Feign客户端代替RestTemplate

    • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第16张图片

2.2.4:总结

  • Feign的使用步骤
    1. 引入依赖
    2. 添加@EnableFeignClients注解
    3. 编写FeignClient接口
    4. 使用FeignClient中定义的方法代替RestTemplate

2.2:自定义配置

2.2.1:自定义Feign的配置

  • Feign运行自定义配置来覆盖默认配置,可用修改的配置如下:

    • 类型 作用 说明
      feign.Logger.Level 修改日志级别 包含四种不同的级别:NONE、BASIC、HEADERS、FULL
      feign.codec.Decoder 响应结果的解析器 http远程调用的结果做解析,例如解析json字符串为java对象
      feign.codec.Encoder 请求参数编码 将请求参数编码,便于通过http请求发送
      feign. Contract 支持的注解格式 默认是SpringMVC的注解
      feign. Retryer 失败重试机制 请求失败的重试机制,默认是没有,不过会使用Ribbon的重试
  • 一般我们需要配置的就是日志级别

配置Feign日志有两种方式

  • 方式一:配置文件方式

    • 全局生效

    • feign:
        client:
          config:
            default:     #这里default就是全局配置,如果写服务名称,则是针对某个服务的配置
              logger-level: : full #日志级别
      
    • 局部生效

    • feign:
        client:
          config:
            userservice:     #这里default就是全局配置,如果写服务名称,则是针对某个服务的配置
              logger-level: full #日志级别
      
  • 方式二:java代码方式,需要先声明一个Bean

    • public class FeignClinetConfiguration {
          @Bean
          public Logger.Level feignLogLevel() {
              return Logger.Level.BASIC;
          }
      }
      
    • 而后如果需要全局配置,则把它放到@EnableFeignClients这个注解中

    • image-20220615093348646

    • 如果需要局部配置,则把它放到@FeignClient这个注解中

    • image-20220615093413839

2.2.2:总结

  • Feign的日志配置:
    • 方式一是配置文件,feign,client.config.xxx.loggerLevel
      • 如果xxx是default则代表全局
      • 如果xxx是服务名称,例如userservice则代表某服务
    • 方式二是java代码配置Logger.Level这个Bean
      • 如果在@EnableFeignClients注解声明则代表全局
      • 如果在@FeignClient注解中声明则代表某服务

2.3:Feign使用优化

2.3.1:Feign的性能优化

  • Feign底层的客户端实现
    • URLConnection:默认实现,不支持连接池
    • Apache HttpClient:支持连接池
    • OKHttp:支持连接池
  • 因此优化Feign的性能主要包括
    • 使用连接池代替默认的URLConnection
    • 日志级别,最好使用basic或none

2.3.2:连接池配置

  • Feign添加HttpClient的支持

    • 引入依赖

    • 
      <dependency>
          <groupId>io.github.openfeigngroupId>
          <artifactId>feign-httpclientartifactId>
      dependency>
      
    • 配置连接池

    • feign:
        client:
          config:
            userservice:     #这里default就是全局配置,如果写服务名称,则是针对某个服务的配置
              logger-level: basic #日志级别,basic就是基本的请求和响应信息
        httpclient:
          enabled: true #开启Feign对httpClient的支持
          max-connections: 200 #最大连接数
          max-connections-per-route: 50 #每个路径的最大连接数
      

2.3.3:总结

  • Feign的优化
    1. 日志级别尽量用basic
    2. 使用HttpClient或OKHttp代替URLConnection
      • 引入feign-httpClient依赖
      • 配置文件开启httpClient功能,设置连接池参数

2.4:最佳实践

2.4.1:方式一(继承)

给消费者的FeignClient和提供者的controller定义统一的父接口作为标准

  • 服务紧耦合
  • 父接口参数列表中的映射不会被继承

第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第17张图片

2.4.2:方式二(抽取)

将FeignClient抽取为独立模块,并且把接口有关的POJO、默认的Feign配置都放到这个模块中,提供给消费者使用

第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第18张图片

2.4.3:总结

  • Feign的最佳实践
    • 让controller和FeignClient继承同一接口
    • 将FeignClient、POJO、Feign的默认配置都定义到一个项目中,供所有消费者使用

2.4.4:抽取FeignClient

  • 实现最佳实践方式二的步骤如下:
    1. 首先创建一个module,命名为feign-api,然后引入feign的starter依赖
    2. 将order-service中编写的UserClient、User、DefaultFeignConfiguration都复制到feign-api项目中
    3. 在order-service中引入feign-api的依赖
    4. 修改order-service中的所有与上述三个组件有关的import部分,改成feign-api中的包
    5. 重启测试
  • 在定义FeignClient不在SpringBootAPplication的扫描包范围时,这些FeignClient无法使用。有两种方式解决
    • 方式一:指定FeignClient所在包
    • image-20220615103850174
    • 方式二:指定FeignClient的字节码
    • image-20220615104325110

2.4.5:总结

  • 不同包的FeignClient的导入有两种方式
    1. 在@enableFeignClients注解中添加basePackages,指定FeignClient所在的包
    2. 在@EnableFeign注解中添加Clients,指定具体FeignClient的字节码

三:Gateway网关服务

3.1:为什么需要网关

3.1.1:网关功能

  • 身份认证和权限校验
  • 服务路由、负载均衡
  • 请求限流

第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第19张图片

3.1.2:网关技术实现

  • 在SpringCloud中网关的实现包括两种:
    • Gateway
    • Zuul
  • Zuul时基于Servlet的实现,属于阻塞式编程。而SpringCloudGateway则是基于Spring5中提供的WebFlux,属于响应式编程的实现。具备更好的性能。

3.1.3:总结

  • 网关的作用:
    • 对用户请求做身份认证、权限校验
    • 将用户请求路由到微服务,并实现负载均衡
    • 对用户请求做限流

3.2:Gateway快速入门

3.2.1:搭建网关服务

搭建网关服务的步骤:

  1. 创建新的module,引入SpringCloudGateway的依赖和nacos的服务发现依赖:

    • <dependencies>
          
          <dependency>
              <groupId>com.alibaba.cloudgroupId>
              <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
          dependency>
          
          <dependency>
              <groupId>org.springframework.cloudgroupId>
              <artifactId>spring-cloud-starter-gatewayartifactId>
          dependency>
      dependencies>
      
  2. 编写路由配置及nacos地址

    • server:
        port: 10010 #网关端口
      spring:
        application:
          name: gateway
        cloud:
          nacos:
            server-addr: localhost:8848
          gateway:
            routes:
              - id: userservoce # 路由id,自定义,只要唯一即可
                #uri:http://127.0.0.1:8081 #路由嘚目标地址http就是固定地址
                uri: lb://userservice #路由嘚目标地址lb就是负载均衡,后面要跟服务名称
                predicates: #路由断言,也就是判断请求是否负荷路由规则的条件
                  - Path=/user/** #这个是按照路径匹配,只要以/user开头就符合要求
      
  3. 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第20张图片

3.2.2:总结

  • 网关搭建步骤:
    • 创建项目,引入nacos服务发现和gateway依赖
    • 配置application.yml,包括服务基本信息、nacos地址、路由
  • 路由配置包括
    • 路由id:路由的唯一标识
    • 路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡
    • 路由断言(predicates):判断路由的规则
    • 路由过滤器(filters):对请求或响应做处理

3.3:断言工厂

3.3.1:路由端游工厂(Route Redicate Factory)

  • 网关路由可以配置的内容包括
    • 路由id:路由唯一标识
    • uri:路由的目标地址,支持lb和http两种
    • predicates:路由断言,判断请求是否符合要求,符合则专注发到路由目的地
    • filters:路由过滤器,处理请求或响应
  • 我们在配置文件中写的断言规则只是字符串,这些字符串会被Predicate Factory读取并处理,转变为路由判断的条件
  • 例如Path=/user/**是按照路径匹配,这个规则是由lorg.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来处理的
  • 像这样的断言工厂在SpringCloudGateway还有十几个

3.3.2:11种基本的Predicate工厂

名称 说明 示例
After 是某个时间点后的请求 - After=2037-01-20T17:42:47.789-07:00[America/Denver]
Before 是某个时间点之前的请求 - Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]
Between 是某两个时间点之前的请求 - Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver]
Cookie 请求必须包含某些cookie - Cookie=chocolate, ch.p
Header 请求必须包含某些header - Header=X-Request-Id, \d+
Host 请求必须是访问某个host(域名) - Host=.somehost.org,.anotherhost.org
Method 请求方式必须是指定方式 - Method=GET,POST
Path 请求路径必须符合指定规则 - Path=/red/{segment},/blue/**
Query 请求参数必须包含指定参数 - Query=name, Jack或者- Query=name
RemoteAddr 请求者的ip必须是指定范围 - RemoteAddr=192.168.1.1/24
Weight 权重处理

3.3.3:总结

  • PredicateFactory的作用是什么?
    • 读取用户定义的断言条件,对请求做出判断
  • Path=/user/**是什么含义?
    • 路径是由/user开头的就认为是符合的

3.4:过滤器工厂

3.4.1:路由过滤器 GatewayFilter

GatewayFilter是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理。

第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第21张图片

  • Spring提供了31种不同的路由过滤器工厂。例如

    • 名称 说明
      AddRequestHeader 给当前请求添加一个请求头
      RemoveRequestHeader 移除请求中的一个请求头
      AddResponseHeader 给响应结果中添加一个响应头
      RemoveResponseHeader 从响应结果中移除有一个响应头
      RequestRateLimiter 限制请求的流量

3.4.2:案例

给所有进入userservice的请求添加一个请求头:Truth=zlm love wxt

  • 实现方式:在gatewya种修改application.yml文件,给userservice的路由添加过滤器

  • spring:
      application:
        name: gateway
      cloud:
        nacos:
          server-addr: localhost:8848
        gateway:
          routes:
            - id: userservoce # 路由id,自定义,只要唯一即可
              #uri:http://127.0.0.1:8081 #路由嘚目标地址http就是固定地址
              uri: lb://userservice #路由嘚目标地址lb就是负载均衡,后面要跟服务名称
              predicates: #路由断言,也就是判断请求是否负荷路由规则的条件
                - Path=/user/** #这个是按照路径匹配,只要以/user开头就符合要求
              filters: #过滤器
                - AddRequestHeader=Truth,zlm love wxt! #添加请求头
    

3.4.3:默认过滤器

如果要对所有的路由都生效,则可以将过来长期工厂写到default下。格式如下

spring:
  application:
    name: gateway
  cloud:
    nacos:
      server-addr: localhost:8848
    gateway:
      routes:
        - id: userservoce # 路由id,自定义,只要唯一即可
          #uri:http://127.0.0.1:8081 #路由嘚目标地址http就是固定地址
          uri: lb://userservice #路由嘚目标地址lb就是负载均衡,后面要跟服务名称
          predicates: #路由断言,也就是判断请求是否负荷路由规则的条件
            - Path=/user/** #这个是按照路径匹配,只要以/user开头就符合要求
          filters: #过滤器
            - AddRequestHeader=Truth,zlm love wxt! #只在对应的路生效。添加请求头
      default-filters: #默认过滤器,会对所有的路由请求都生效
        - AddRequestHeader=Truth,zlm love wxt! #添加请求头

3.4.4:总结

  • 过滤器的作用是什么
    • 对路由的请求或响应做加工处理,比如添加请求偷
    • 对配置在路由下面的过滤器只对当前路由的请求生效
  • defaultFilters的作用是什么?
    • 对所有的路由都生效的过滤器

3.5:全局过滤器

3.5.1:全局过滤器GlobalFilter

全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。区别在于GatewayFilter通过配置定义,处理逻辑是固定的。而GlobalFilter的逻辑需要自己写代码实现。定义方法是实现GlobalFilter接口

第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第22张图片

3.5.2:案例

定义全局过滤器,拦截并判断用户身份

  • 需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件

    • 参数中是否又authorization
    • authorization参数值是否为admin
  • 如果同时满足则放行,否则拦截

  • 步骤1:自定义过滤器

    • 自定义类,实现GlobalFilter接口,添加@Order注解
    • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第23张图片

3.5.3:总结

  • 全局过滤器的作用是什么?
    • 对所有的路由都生效的过滤器,并且可以自定义处理逻辑
  • 实现全局过滤器的步骤
    • 实现GlobalFilter接口
    • 添加@Order注解或实现Ordered接口
    • 编写处理逻辑

3.5.4:过滤器执行顺序

  • 请求进入网关会碰到三类过滤器:当前路由的过滤器、DefaultFilter、GlobalFilter
  • 请求路由后,会将当前路由过滤器和DefaultFilter、GlobalFilter、合并到一个过滤器链(集合)中,排序后一次执行每个过滤器
  • 第二章(Nacos配置管理、Feign远程调用、Gateway网关服务)_第24张图片
  • 每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。
  • GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定
  • 路由过滤器和defaultFilter的order由Spring指定,默认是按照声明顺序从1递增
  • 当过滤器的order值一样时,会按照 defaultFilter 》路由过滤器 》GlobalFilter的顺序执行。

3.5.5:总结

  • 路由过滤器、defaultFilter、全局过滤器的执行顺序?
    • order值越小,优先级越高
    • 当order值一样时,顺序时defaultFilter最先,然后是局部的路由过滤器,最后是全局过滤器

3.6:跨域问题

3.6.1:跨域问题处理

  • 跨域:域名不一致就是跨域,主要包括
    • 域名不同:www.taobao.com 和 www.taobao.org 和 www.jd.com 和 miaosha.jd.com
    • 域名相同,端口不同:localhost:8080和localhost:8081
  • 跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题
  • 解决方案:CORS

网关处理跨域采用的同样是CORS方案,并且只需要简单配置即可实现:

@Configuration
public class CrosConfig {
    @Bean
    public CorsWebFilter coreWebFilter() {
        CorsConfiguration config = new CorsConfiguration();
        // * 号表示匹配任意的
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");

        PathPatternParser patternParser = new PathPatternParser();
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(patternParser);
        // ** 代表所有
        source.registerCorsConfiguration("/**", config);

        CorsWebFilter corsWebFilter = new CorsWebFilter(source);

        return corsWebFilter;
    }
}

你可能感兴趣的:(gateway,java,spring,cloud)