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

微服务篇-深入了解使用 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 {@Beanpublic 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 {@Beanpublic 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);}
}

相关文章:

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

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 认识微服务 1.1 单体架构 1.2 微服务 1.3 SpringCloud 框架 2.0 服务调用 2.1 RestTemplate 远程调用 3.0 服务注册和发现 3.1 注册中心原理 3.2 Nacos 注册中心 …...

使用 Django 构建支持 Kubernetes API 测试连接的 POST 接口

文章目录 使用 Django 构建支持 Kubernetes API 测试连接的 POST 接口功能需求使用 kubectl 获取 Token命令解析输出示例 完整代码实现Kubernetes API 客户端类功能说明 Django 接口视图关键点解析 路由配置 接口测试请求示例响应结果成功错误 优化建议1. 安全性2. 错误处理3. …...

十二、正则表达式、元字符、替换修饰符、手势和对话框插件

1. 正则表达式 1.1 基本使用 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title&g…...

计算机毕业设计Python+大模型美食推荐系统 美食可视化 美食数据分析大屏 美食爬虫 美团爬虫 机器学习 大数据毕业设计 Django Vue.js

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

【后端面试总结】MySQL索引

数据库索引不只一种实现方法&#xff0c;但是其中最具代表性&#xff0c;也是我们面试中遇到最多的无疑是B树。 索引为什么选择B树 数据量很大的查找&#xff0c;是不能直接放入内存的&#xff0c;而是需要什么数据就通过磁盘IO去获得。 红黑树&#xff0c;AVL树等二叉查找树…...

[蓝桥杯 2021 省 AB2] 小平方

题目描述 小蓝发现&#xff0c;对于一个正整数 nn 和一个小于 nn 的正整数 vv&#xff0c;将 vv 平方后对 nn 取余可能小于 nn 的一半&#xff0c;也可能大于等于 nn 的一半。 请问&#xff0c;在 11 到 n−1n−1 中, 有多少个数平方后除以 nn 的余数小于 nn 的一半。 例如&…...

Jmeter测试工具的安装和使用,mac版本,jmeter版本5.2.1

Jmeter测试工具的安装和使用JSON格式请求 一、安装1、安装jdk包和设置java环境2、去官网下载Jmeter3、解压后&#xff0c;打开mac终端&#xff0c;进入apache-jmeter的bin文件开启jmeter 二、使用jmeter1、添加线程2、添加HTTP请求3、配置请求的协议、IP地址、端口号、请求方法…...

kmeans 最佳聚类个数 | 轮廓系数(越大越好)

轮廓系数越大&#xff0c;表示簇内实例之间紧凑&#xff0c;簇间距离大&#xff0c;这正是聚类的标准概念。 簇内的样本应该尽可能相似。不同簇之间应该尽可能不相似。 目的&#xff1a;鸢尾花数据进行kmeans聚类&#xff0c;最佳聚类个数是多少&#xff1f; plot(iris[,1:4…...

【纪念365天】我的创作纪念日

过去的一年 没有注意加入csdn已经有一年了。 这几天翻看小猴儿的通知才发现时间来到了一年的纪念日。稍稍思索想要将这一段时间的学习到的知识以及偶然遇到的机遇做一下总结。 上一次写纪念日是来到csdn128天的时候&#xff0c; 200天前我的学习状态是非常疯狂的。 只记得我当时…...

Opencv+ROS实现颜色识别应用

目录 一、工具 二、原理 概念 本质 三、实践 添加发布话题 主要代码 四、成果 五、总结 一、工具 opencvros ubuntu18.04 摄像头 二、原理 概念 彩色图像&#xff1a;RGB&#xff08;红&#xff0c;绿&#xff0c;蓝&#xff09; HSV图像&#xff1a;H&#xff0…...

蓝桥杯c++算法秒杀【6】之动态规划【下】(数字三角形、砝码称重(背包问题)、括号序列、异或三角:::非常典型的必刷例题!!!)

别忘了请点个赞收藏关注支持一下博主喵&#xff01;&#xff01;&#xff01;! ! ! ! &#xff01; 关注博主&#xff0c;更多蓝桥杯nice题目静待更新:) 动态规划 三、括号序列 【问题描述】 给定一个括号序列&#xff0c;要求尽可能少地添加若干括号使得括号序列变得合…...

C++设计模式(单例模式)

一、介绍 1.动机 在软件系统中&#xff0c;经常有这样一些特殊的类&#xff0c;必须保证它们在系统中只存在一个实例&#xff0c;才能确保它们的逻辑正确性、以及良好的效率。 如何绕过常规的构造器&#xff0c;提供一种机制来保证一个类只有一个实例? 这应该是类设计者的…...

前端---CSS(部分用法)

HTML画页面--》这个页面就是页面上需要的元素罗列起来&#xff0c;但是页面效果很差&#xff0c;不好看&#xff0c;为了让页面好看&#xff0c;为了修饰页面---》CSS CSS的作用&#xff1a;修饰HTML页面 用了CSS之后&#xff0c;样式和元素本身做到了分离的效果。---》降低了代…...

2024年最新版Java八股文复习

最新版本Java八股文复习&#xff0c;每天更新一篇&#xff0c;博主正在持续努力更新中~~~ 一、Java基础篇1、怎么理解面向对象&#xff1f;简单说说封装、继承、多态三大特性&#xff1f;2、多态体现在哪几个方面&#xff1f;3、面向对象的设计原则你知道有哪些吗&#xff1f;4…...

计算机毕业设计Hadoop+Spark音乐推荐系统 音乐预测系统 音乐可视化大屏 音乐爬虫 HDFS hive数据仓库 机器学习 深度学习 大数据毕业设计

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…...

MyBatis高级扩展

一、Mapper批量映射优化: 1.需求: Mapper 配置文件很多时&#xff0c;在全局配置文件中一个一个注册太麻烦&#xff0c;希望有一个办法能够一劳永逸 2.配置方式: Mybatis允许在指定Mapper映射文件时&#xff0c;只指定其所在的包: <mappers><package name"c…...

代码美学2:MATLAB制作渐变色

效果&#xff1a; %代码美学&#xff1a;MATLAB制作渐变色 % 创建一个10x10的矩阵来表示热力图的数据 data reshape(1:100, [10, 10]);% 创建热力图 figure; imagesc(data);% 设置颜色映射为“cool” colormap(cool);% 在热力图上添加边框 axis on; grid on;% 设置热力图的颜色…...

浅谈- “ 变量中 无符号 与 有符号 的 值转换 ”

在同一个表达式中&#xff0c;若同时出现 无符号变量 与 有符号变量 &#xff1a; 1、都转换为无符号类型&#xff1a;&#xff08;注&#xff1a;2^324294967296&#xff09;即unsigned int 的最大值 2、然后再运行表达式 实例&#xff1a; #include <stdio.h>char fun(…...

【AI绘画】Midjourney进阶:色调详解(上)

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AI绘画 | Midjourney 文章目录 &#x1f4af;前言&#x1f4af;Midjourney中的色彩控制为什么要控制色彩&#xff1f;为什么要在Midjourney中控制色彩&#xff1f; &#x1f4af;色调白色调淡色调明色调 &#x1f4af…...

代码管理之Gitlab

文章目录 Git基础概述场景本地修改未提交&#xff0c;拉取远程代码修改提交本地&#xff0c;远程已有新提交 GitIDEA引入Git拉取仓库代码最后位置 Git基础 概述 workspace 工作区&#xff1a;本地电脑上看到的目录&#xff1b; repository 本地仓库&#xff1a;就是工作区中隐…...

防御网络攻击的创新策略

关键要点 ● 了解各种类型的网络攻击对于组织加强防御至关重要。 ● 制定敏捷的网络安全策略可帮助企业快速应对新出现的威胁。 ● 跨行业协作和威胁情报共享可以增强整体安全性。 网络攻击威胁日益严重 网络攻击的数量和复杂程度急剧增加&#xff0c;对全球组织构成了重大…...

C++软件设计模式之组合模式概述

组合模式&#xff08;Composite Pattern&#xff09;是C软件设计模式中的一种&#xff0c;主要用于解决对象的层次结构问题。它允许你将对象组合成树形结构来表示“部分-整体”的层次结构&#xff0c;使得客户端可以统一地处理单个对象和组合对象。 主要用于解决的问题&#x…...

利用HTML5和CSS来实现一个漂亮的表格样式

利用HTML5和CSS来实现一个漂亮的表格样式 第一步&#xff1a;创建HTML结构第二步&#xff1a;添加CSS样式第三步&#xff1a;响应式设计第四步&#xff1a;加入交互效果 第一步&#xff1a;创建HTML结构 我们将用HTML创建一个基本的表格结构。代码如下&#xff1a; <!DOCT…...

Vivado程序固化到Flash

在上板调试FPGA时&#xff0c;通常使用JTAG接口下载程序到FPGA芯片中&#xff0c;FPGA本身是基于RAM工艺的器件&#xff0c;因此掉电后会丢失芯片内的程序&#xff0c;需要重新烧写程序。但是当程序需要投入使用时不能每一次都使用JTAG接口下载程序&#xff0c;一般FPGA的外围会…...

HCIA笔记3--TCP-UDP-交换机工作原理

1. tcp协议 可靠的连接 1.1 报文格式 1.2 三次握手 1.3 四次挥手 为什么TIME_WAIT需要2MSL的等待时间&#xff1f; &#xff08;a&#xff09; 为了实现可靠的关闭 &#xff08;b&#xff09;为了让过期的报文在网络上消失 对于(a), 假设host发给server的last ack丢了。 ser…...

计算机网络的功能

目录 信息交换 资源共享 分布式处理 可靠性增强 集中管理 信息交换 计算机网络最基本的功能之一是允许不同设备之间的数据通信。这包括电子邮件的发送和接收、即时消息的传递、文件传输等。通过网络&#xff0c;用户可以轻松地与全球各地的其他人进行沟通和协作。 信息交…...

Redis设计与实现第14章 -- 服务器 总结(命令执行器 serverCron函数 初始化)

14.1 命令请求的执行过程 一个命令请求从发送到获得回复的过程中&#xff0c;客户端和服务器都需要完成一系列操作。 14.1.1 发送命令请求 当用户在客户端中输入一个命令请求的时候&#xff0c;客户端会把这个命令请求转换为协议格式&#xff0c;然后通过连接到服务器的套接字…...

多输入多输出 | Matlab实现TCN-GRU时间卷积神经网络结合门控循环单元多输入多输出预测

多输入多输出 | Matlab实现TCN-GRU时间卷积神经网络结合门控循环单元多输入多输出预测 目录 多输入多输出 | Matlab实现TCN-GRU时间卷积神经网络结合门控循环单元多输入多输出预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 多输入多输出 | Matlab实现TCN-GRU时间卷积…...

windows安全中心,永久卸载工具分享

使用方法 2024Goby红队版工具分享&#xff0c;附2024年漏洞POC下载 下载链接&#xff1a; https://pan.quark.cn/s/4fc2712a2afc一路回车&#xff0c;选项Y即可 耐心等待几秒种&#xff0c;自动重启 此时打开windows安全中心&#xff0c;已经完全不能使用了&#xff0c;响应…...

《安富莱嵌入式周报》第346期:开源2GHz带宽,12bit分辨率,3.2Gsps采样率示波,开源固件安全分析器, 开源口袋电源,开源健康测量,FreeCAD

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频&#xff1a; https://www.bilibili.com/video/BV1TYBhYKECK/ 《安富莱嵌入式周报》第346期&#xff1a;开源2GHz带…...

网站建设提示DNA错误/小程序开发公司哪里强

PMML是一种通用的配置文件&#xff0c;只要遵循标准的配置文件&#xff0c;就可以在Spark中训练机器学习模型&#xff0c;然后再web接口端去使用。目前应用最广的就是基于Jpmml来加载模型在javaweb中应用&#xff0c;这样就可以实现跨平台的机器学习应用了。 训练模型 首先在sp…...

手机网站开发 教程/seo就是搜索引擎广告

温习一下这些天学习的CLR编程&#xff0c;存储过程&#xff0c;函数。 编写CLR的存储过程&#xff0c;运行起来的效率&#xff0c;果然比普通的SQL语句&#xff0c;存储过程或是函数均高。以后专案需求&#xff0c;或是执行效率较高的SQL&#xff0c;得写成CLR程序&#xff0c;…...

新品发布会朋友圈文案/seo常用工具网站

AJAX Asynchronous Javascript And XML是 "异步Javascript和XML"。即使用 Javascript 语言与服务器进行异步交互&#xff0c;传输的数据为XML。 同步交互&#xff1a;客户端发出一个请求后&#xff0c;需要等待服务器响应结束后&#xff0c;才能发出第二个请求&#…...

山西网站建设费用/今天的新闻摘抄

前言 今天讲解一下Android平台下ListView控件的开发&#xff0c;在本篇博客中&#xff0c;将介绍ListView的一些常用属性、方法及事件&#xff0c;还会讲解ListView在开发中常用的几种方式&#xff0c;以及使用不通用的适配器Adapter定制个性的View视图用于ListView的展示。 Li…...

深圳论坛网站设计哪家公司好/竞价推广网络推广运营

我们先用一个小表来&#xff0c;来说明一下&#xff0c;oracle执行计划该注意哪些地方。 hrORCL> set autotrace traceonly hrORCL> select * from t;模糊比较两条sql的优劣时&#xff0c;建议先查看以下两个值&#xff1a; Cost (%CPU)&#xff1a;cpu代价&#xff0c;…...

驻马店做网站的公司/seo的工具有哪些

viewpager.getChildCount() 非常easy误解成viewpager子页面的size。它和getCount还是有差别的 getChildCount() 是表示当前可见页size 比方&#xff1a;Viewpager总共3页 当到第一页时候可见页面为2&#xff08;在滑动过程&#xff0c;可见第一张和第二张&#xff09;&#xff…...