当前位置: 首页 > article >正文

微服务篇-深入了解使用 RestTemplate 远程调用、Nacos 注册中心基本原理与使用、OpenFeign 的基本使用

🔥博客主页: 【小扳_-CSDN博客】
❤感谢大家点赞👍收藏⭐评论✍

文章目录

        1.0 认识微服务

        1.1 单体架构

        1.2 微服务

        1.3 SpringCloud 框架

        2.0 服务调用

        2.1 RestTemplate 远程调用

        3.0 服务注册和发现

        3.1 注册中心原理

        3.2 Nacos 注册中心

        3.3 服务注册

        3.3.1 添加依赖

        3.3.2 配置 Nacos

        3.4 服务发现

        3.4.1 引入依赖

        3.4.2 配置 Nacos 地址

        3.4.3 发现并调用服务

        4.0 OpenFeign

        4.1 引入依赖

        4.2 启动 OpenFeign

        4.3 使用 FeignClient

        4.4 扫描包

        5.0 连接池

        5.1 引入依赖

        5.2 开启连接池

        6.0 日志配置

        6.1 定义日志级别

        6.2 配置


        1.0 认识微服务

        服务(Microservices)是一种软件架构风格,它将一个应用程序构建为一组小的、独立的服务,每个服务可以独立开发、部署和扩展。这种架构相较于传统的单体应用(Monolithic Architecture)具有许多优势,尤其是在灵活性和可维护性方面。

        1.1 单体架构

        单体架构(monolithic structure):顾名思义,整个项目中所有功能模块都在一个工程中开发;项目部署时需要对所有模块一起编译、打包;项目的架构设计、开发模式都非常简单。

         当项目规模较小时,这种模式上手快,部署、运维也都很方便,因此早期很多小型项目都采用这种模式。

        但随着项目的业务规模越来越大,团队开发人员也不断增加,单体架构就呈现出越来越多的问题:
        - 团队协作成本高:试想一下,你们团队数十个人同时协作开发同一个项目,由于所有模块都在一个项目中,不同模块的代码之间物理边界越来越模糊。最终要把功能合并到一个分支,你绝对会陷入到解决冲突的泥潭之中。
        - 系统发布效率低:任何模块变更都需要发布整个系统,而系统发布过程中需要多个模块之间制约较多,需要对比各种文件,任何一处出现问题都会导致发布失败,往往一次发布需要数十分钟甚至数小时。
        - 系统可用性差:单体架构各个功能模块是作为一个服务部署,相互之间会互相影响,一些热点功能会耗尽系统资源,导致其它服务低可用。

        1.2 微服务

        微服务架构,首先是服务化,就是将单体架构中的功能模块从单体应用中拆分出来,独立部署为多个服务。同时要满足下面的一些特点:
        - 单一职责:一个微服务负责一部分业务功能,并且其核心数据不依赖于其它模块。
        - 团队自治:每个微服务都有自己独立的开发、测试、发布、运维人员,团队人员规模不超过10人(2张披萨能喂饱)
        - 服务自治:每个微服务都独立打包部署,访问自己独立的数据库。并且要做好服务隔离,避免对其它服务产生影响

        1.3 SpringCloud 框架

        微服务拆分以后碰到的各种问题都有对应的解决方案和微服务组件,而 SpringCloud 框架可以说是目前 Java 领域最全面的微服务组件的集合了。

        而且 SpringCloud 依托于 SpringBoot 的自动装配能力,大大降低了其项目搭建、组件使用的成本。对于没有自研微服务组件能力的中小型企业,使用 SpringCloud 全家桶来实现微服务开发可以说是最合适的选择了。

        SpringCloud 官网:Spring Cloud

        SpringCloud 相关的依赖:

            <!--spring cloud-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud alibaba-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

        2.0 服务调用

        在微服务中,每一个模块都是独立的,那么模块与模块之间就不能直接通过 Bean 对象注入的方式来访问不同模块的方法了,则需要通过网络来建立模块与模块之间的联系了。

        前端向服务端查询数据,其实就是从浏览器远程查询服务端数据。比如刚才通过 Swagger 测试商品查询接口,而这种查询就是通过 http 请求的方式来完成的,不仅仅可以实现远程查询,还可以实现新增、删除等各种远程请求。

        2.1 RestTemplate 远程调用

        Spring 提供了一个 RestTemplate 的API,可以方便的实现 Http 请求的发送。

其中提供了大量的方法,方便发送 Http 请求,例如:

        可以看到常见的 Get、Post、Put、Delete 请求都支持,如果请求参数比较复杂,还可以使用 exchange 方法来构造请求。

使用步骤:

        1)先创建一个 IOC 容器对象:

package com.hmall.cart.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RemoteCallConfig {

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

        2)发送 HTTP 请求:

        可以看到,利用 RestTemplate 发送 http 请求与前端 ajax 发送请求非常相似,都包含四部分信息:
        - ① 请求方式
        - ② 请求路径
        - ③ 请求参数
        - ④  返回值类型

        3.0 服务注册和发现

        通过 Http 请求实现了跨微服务的远程调用。不过这种手动发送 Http 请求的方式存在一些问题。试想一下,假如商品微服务被调用较多,为了应对更高的并发,进行了多实例部署,如图:

        此时,每个 item-service 的实例其 IP 或端口不同,问题来了:
        - item-service 这么多实例,cart-service 如何知道每一个实例的地址?
        - http 请求要写 url 地址,cart-service 服务到底该调用哪个实例呢?
        - 如果在运行过程中,某一个 item-service 实例宕机,cart-service 依然在调用该怎么办?
        - 如果并发太高,item-service 临时多部署了N台实例,cart-service 如何知道新实例的地址?

        为了解决上述问题,就必须引入注册中心的概念了。

        3.1 注册中心原理

        在微服务远程调用的过程中,包括两个角色:
        - 服务提供者:提供接口供其它微服务访问,比如 item-service
        - 服务消费者:调用其它微服务提供的接口,比如 cart-service

        在大型微服务项目中,服务提供者的数量会非常多,为了管理这些服务就引入了注册中心的概念。注册中心、服务提供者、服务消费者三者间关系如下:

流程如下:
        - 服务启动时就会注册自己的服务信息(服务名、IP、端口)到注册中心。
        - 调用者可以从注册中心订阅想要的服务,获取服务对应的实例列表(1个服务可能多实例部署)
        - 调用者自己对实例列表负载均衡,挑选一个实例。
        - 调用者向该实例发起远程调用。

当服务提供者的实例宕机或者启动新实例时,调用者如何得知呢?
        - 服务提供者会定期向注册中心发送请求,报告自己的健康状态(心跳请求),当注册中心长时间收不到提供者的心跳时,会认为该实例宕机,将其从服务的实例列表中剔除。
        - 当服务有新实例启动时,会发送注册服务请求,其信息会被记录在注册中心的服务实例列表。
        - 当注册中心服务列表变更时,会主动通知微服务,更新本地服务列表。

        3.2 Nacos 注册中心

        目前开源的注册中心框架有很多,国内比较常见的有:
        - Eureka:Netflix 公司出品,目前被集成在 SpringCloud 当中,一般用于 Java 应用。
        - Nacos:Alibaba 公司出品,目前被集成在 SpringCloudAlibaba 中,一般用于 Java 应用。
        - Consul:HashiCorp 公司出品,目前集成在 SpringCloud 中,不限制微服务语言。

        以上几种注册中心都遵循 SpringCloud 中的 API 规范,因此在业务开发使用上没有太大差异。由于 Nacos 是国内产品,中文文档比较丰富,而且同时具备配置管理功能,因此在国内使用较多。

        基于 Docker 来部署 Nacos 的注册中心,首先要准备 MySQL 数据库表,用来存储 Nacos 的数据。

        1)首先配置相关的数据库表信息:

Nacos 相关存储的数据库:

 对应的数据库语句:

/******************************************/
/*   数据库全名 = nacos_config   */
/*   表名称 = config_info   */
/******************************************/
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 '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(20) 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 '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(20) 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 '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' COMMENT '修改时间',
  `src_user` text COMMENT 'source user',
  `src_ip` varchar(20) 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 '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' 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 '2010-05-05 00:00:00',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00',
  `src_user` text,
  `src_ip` varchar(20) 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 '2010-05-05 00:00:00' COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT '2010-05-05 00:00:00' 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,
    constraint uk_username_role UNIQUE (username,role)
);
 
CREATE TABLE permissions (
    role varchar(50) NOT NULL,
    resource varchar(512) NOT NULL,
    action varchar(8) NOT NULL,
    constraint uk_role_permission UNIQUE (role,resource,action)
);
 
INSERT INTO users (username, password, enabled) VALUES ('nacos', '$2a$10$EuWPZHzz32dJN7jexM34MOeYirDdFAZm2kuWj7VEOJhhZkDrxfvUu', TRUE);
 
INSERT INTO roles (username, role) VALUES ('nacos', 'ROLE_ADMIN');

        2)配置 Nacos 信息:

        nacos/custom.env 文件中,有一个 MYSQL_SERVICE_HOST 也就是 mysql 地址,需要修改为你自己的虚拟机 IP 地址:

PREFER_HOST_MODE=hostname
MODE=standalone
SPRING_DATASOURCE_PLATFORM=mysql
MYSQL_SERVICE_HOST=mysql
MYSQL_SERVICE_DB_NAME=nacos
MYSQL_SERVICE_PORT=3306
MYSQL_SERVICE_USER=root
MYSQL_SERVICE_PASSWORD=123
MYSQL_SERVICE_DB_PARAM=characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai

        将配置好的 nacos/custom.env 文件放到 /root 目录下。 

         接着,进入 root 目录,然后执行下面的 docker 命令:

docker run -d \
--name nacos \
--env-file ./nacos/custom.env \
-e JVM_XMS=256m -e JVM_XMX=256m \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
--restart=always \
--network hm-net\
nacos/nacos-server:v2.1.0-slim

        启动完成后,访问下面地址:http://IP:8848/nacos/,注意将 IP 替换为你自己的虚拟机 IP 地址。
        首次访问会跳转到登录页,账号密码都是 nacos 。

        3.3 服务注册

        接下来,把服务注册到 Nacos,步骤如下:
                - 引入依赖
                - 配置 Nacos 地址
                - 重启

        3.3.1 添加依赖

        添加依赖:

<!--nacos 服务注册发现-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

        3.3.2 配置 Nacos

        添加 nacos 地址配置:

spring:
  application:
    name: item-service # 服务名称
  cloud:
    nacos:
      server-addr: 192.168.150.101:8848 # nacos地址

        访问 nacos 控制台,可以发现服务注册成功:

        3.4 服务发现

        服务的消费者要去 nacos 订阅服务,这个过程就是服务发现,步骤如下:
        - 引入依赖
        - 配置 Nacos 地址
        - 发现并调用服务

        3.4.1 引入依赖

        在 pom.xml 中添加下面的依赖:

<!--nacos 服务注册发现-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

        可以发现,这里 Nacos 的依赖于服务注册时一致,这个依赖中同时包含了服务注册和发现的功能。因为任何一个微服务都可以调用别人,也可以被别人调用,即可以是调用者,也可以是提供者。

        3.4.2 配置 Nacos 地址

        添加 nacos 地址配置:

spring:
  cloud:
    nacos:
      server-addr: 192.168.150.101:8848

        3.4.3 发现并调用服务

        服务发现需要用到一个工具,DiscoveryClient,SpringCloud 已经帮我们自动装配,我们可以直接注入使用:

        接下来,我们就可以对原来的远程调用做修改了,之前调用时我们需要写死服务提供者的 IP 和端口:

        但现在不需要了,我们通过 DiscoveryClient 发现服务实例列表,然后通过负载均衡算法,选择一个实例去调用:

        4.0 OpenFeign

        利用 Nacos 实现了服务的治理,利用 RestTemplate 实现了服务的远程调用。但是远程调用的代码太复杂了:

        OpenFeign 就利用 SpringMVC 的相关注解来声明上述 4 个参数,然后基于动态代理帮我们生成远程调用的代码,而无需我们手动再编写,非常方便。

        4.1 引入依赖

        在服务的 pom.xml 中引入 OpenFeign 的依赖和 loadBalancer 依赖:

  <!--openFeign-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
  </dependency>
  <!--负载均衡器-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-loadbalancer</artifactId>
  </dependency>

        4.2 启动 OpenFeign

        接下来,在启动类上添加注解,启动 OpenFeign 功能:

        4.3 使用 FeignClient

        在服务中,定义一个新的接口,编写 Feign 客户端:
其中代码如下:

import com.hmall.api.dto.ItemDTO;
import com.hmall.api.dto.OrderDetailDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

import java.util.Collection;
import java.util.List;

@FeignClient("item-service")
public interface ItemClient {

    @GetMapping("/items")
    List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);

    @PutMapping("/items/stock/deduct")
    void deductStock(@RequestBody Collection<OrderDetailDTO> items);
}

解析:

        这里只需要声明接口,无需实现方法。接口中的几个关键信息:
        - @FeignClient("item-service") :声明服务名称
        - @GetMapping :声明请求方式
        - @GetMapping("/items") :声明请求路径
        - @RequestParam("ids") Collection<Long> ids :声明请求参数
        - List<ItemDTO> :返回值类型

        有了上述信息,OpenFeign 就可以利用动态代理帮我们实现这个方法,并且向 http://item-service/items 发送一个 GET 请求,携带 ids 为请求参数,并自动将返回值处理为 List<ItemDTO> 。
        我们只需要直接调用这个方法,即可实现远程调用了。

        最后,在 cart-service 的 com.hmall.cart.service.impl.CartServiceImpl 中改造代码,直接调用 ItemClient 的方法:

         feign 替我们完成了服务拉取、负载均衡、发送 http 请求的所有工作,是不是看起来优雅多了。而且,这里我们不再需要 RestTemplate 了,还省去了 RestTemplate 的注册。

        4.4 扫描包

        如果是使用了单独模块来管理全部的 FeignClient 接口,那么需要添加声明:

        1)第一种方式:声明扫描包

        2)第二种方式:声明要用的 FeignClient

        5.0 连接池

        Feign 底层发起 http 请求,依赖于其它的框架。其底层支持的 http 客户端实现包括:
        - HttpURLConnection:默认实现,不支持连接池
        - Apache HttpClient :支持连接池
        - OKHttp:支持连接池

        因此我们通常会使用带有连接池的客户端来代替默认的 HttpURLConnection,比如,我们使用 OKHttp 。

        5.1 引入依赖

        在 pom.xml 中引入依赖:

<!--OK http 的依赖 -->
<dependency>
  <groupId>io.github.openfeign</groupId>
  <artifactId>feign-okhttp</artifactId>
</dependency>

        5.2 开启连接池

        在 application.yml 配置文件中开启 Feign 的连接池功能:

feign:
  okhttp:
    enabled: true # 开启OKHttp功能

        重启服务,连接池就生效了。

        6.0 日志配置

        OpenFeign 只会在 FeignClient 所在包的日志级别为 DEBUG 时,才会输出日志。而且其日志级别有 4 级:
        - NONE:不记录任何日志信息,这是默认值。
        - BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
        - HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
        - FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
        Feign 默认的日志级别就是 NONE,所以默认我们看不到请求日志。

        6.1 定义日志级别

        新建一个配置类,定义 Feign 的日志级别:

代码如下:

package com.hmall.api.config;

import feign.Logger;
import org.springframework.context.annotation.Bean;

public class DefaultFeignConfig {
    @Bean
    public Logger.Level feignLogLevel(){
        return Logger.Level.FULL;
    }
}

        6.2 配置

        接下来,要让日志级别生效,还需要配置这个类。有两种方式:
        1)局部生效:在某个 FeignClient 中配置,只对当前 FeignClient 生效:

@FeignClient(value = "item-service", configuration = DefaultFeignConfig.class)

        2)全局生效:在 @EnableFeignClients 中配置,针对所有 FeignClient 生效:

@EnableFeignClients(defaultConfiguration = DefaultFeignConfig.class)

代码如下: 

@EnableFeignClients(basePackages = "com.hmall.api.client",defaultConfiguration = DefaultFeignConfig.class)
@MapperScan("com.hmall.item.mapper")
@SpringBootApplication
public class ItemApplication {
    public static void main(String[] args) {
        SpringApplication.run(ItemApplication.class, args);
    }
}


http://www.kler.cn/a/411141.html

相关文章:

  • 【Vue】 npm install amap-js-api-loader指南
  • 网络协议——BGP(边界网关协议)全网最详解
  • NuGet如何支持HTTP源
  • React表单联动
  • 商业物联网:拥抱生产力的未来
  • RHCSA作业2
  • 【Unity3D】创建自定义字体
  • C语言实例之9斐波那契数列实现
  • 图论入门编程
  • 安装 IntelliJ IDEA
  • 深度学习模型:循环神经网络(RNN)
  • 极狐GitLab 17.6 正式发布几十项与 DevSecOps 相关的功能【五】
  • Error: Invalid version flag: if 问题排查
  • 【DFS】个人练习-Leetcode-646. Maximum Length of Pair Chain
  • jvm核心组件介绍
  • 手搓人工智能—聚类分析(下)谱系聚类与K-mean聚类
  • E2、UML类图顺序图状态图实训
  • 计算机网络的功能
  • 银行卡 OCR 识别 API 接口的发展前景
  • 解决 java -jar 报错:xxx.jar 中没有主清单属性
  • 物联网智能项目:智能家居系统的设计与实现
  • 旋转磁体产生的场 - 实验视频资源下载
  • 【Python 3.13】新特性解读,重大改进建议升级:JIT编译、免GIL,REPL、错误处理、类型系统等多个方面
  • Win7电脑IP地址查看与变换指南
  • shiny动态生成颜色选择器并将其用于绘图
  • JVM详解:垃圾回收机制