Nacos配置

news/发布时间2024/9/20 5:35:56

目录

启动nacos

项目步骤

Nacos服务分级存储模型​编辑

服务跨域集群调用问题

NacosRule负载均衡

服务实例的权重设置

环境隔离-namespace

Nacos环境隔离

Nacos和Eureak对比

临时实例和非临时实例

Ncaos与Eureka的共同点

Nacos与Eureka的区别

Nacos配置管理

统一配置管理

实现

总结(将配置交给Nacso管理的步骤)

热更新

多环境配置共享

步骤

多环境配置优先级

Nacos集群搭建

1.集群结构图

2.搭建集群

2.1.初始化数据库

2.2.下载nacos

2.3.配置Nacos

2.4.启动

2.5.nginx反向代理

2.6. 优化

总结

HTTP客户端Feign

1.RestTemplate方法调用存在的问题

Feign的介绍

定义和使用Feign客户端

Feign的使用步骤

自定义Feign的配置

自定义Feign的配置

方式一:配置文件方式

方式二:Java代码配置

总结

Feign的性能优化

Feign地城的客户端实现

因为优化Feign的性能主要包括:

Feign的性能优化-连接池配置

Feign添加HttpClient的支持:

总结

Feign的最佳实践

方式一(继承)

方式二(抽取):

实现

当定义的FeignClient不在SpringBootApplication的扫描包范围时,这些FeignClient无法使用。有两种方式解决:

总结

总结

统一网关Gateway

为什么需要网关

网关功能

网关的技术实现

总结

gateway快速入门

搭建网关

总结

断言工厂

网关路由可以配置的内容包括

断言工厂

spring提供了11种基本的Predicate工厂​编辑

实例

测试1

测试2

过滤器工厂

总结

全局过滤器

总结

过滤器执行顺序

总结

跨域问题

总结


启动nacos

D:\Student\SpringCloudAlibabadown\nacos\bin\startup.cmd

个人配置9001端口

项目步骤

  1. 在父项目确定alibaba.cloud版本。

<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>
  1. 在子项目(或者需要使用的项目中)添加nacos包

    <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><version>2.2.5.RELEASE</version>
    </dependency>

  2. 在配置文件中配置添加nacos

    cloud:nacos:server-addr: localhost:9001

    成功实现

Nacos服务分级存储模型

服务跨域集群调用问题

服务调用尽可能选择本地集群的服务,跨集群调用延迟较高 本地集群不可访问,再去访问其他集群

  1. Nacos服务分级存储模型

    1. 一级是服务,列入userservice

    2. 二级是集群,例如杭州和上海

    3. 三级是实例,例如杭州机房的某台部署了userserviec的服务器

  2. 如何设置实例的集群属性

    1. 修改application.yml文件,添加spring.cloud.nacos.discovry.cluster -name属性即可如下:

      cloud:nacos:server-addr: localhost:9001 # nacos地址discovery: cluster-name: SH # 集群名称,代指杭州

NacosRule负载均衡

修改客户端的application.yml

cloud:nacos:server-addr: localhost:9001 # nacos地址discovery:cluster-name: SH # 集群名称,代指杭州

在客户端中设置负载均衡的IRule未NacosRule,这个规则优先会寻找与自己同集群的服务:

userservice:ribbon:NFLoadbalancerClassName: com.alibaba.cloud.nacos.ribbon.NacosRule

注意将项目的权重都设置为1

  1. NacosRule负载均衡策略

    1. 优先选着同集群服务实例列表

    2. 本地集群找不到提供者,才回去其他集群寻找,并且会报警告

    3. 确定了可用实力列表后,在采用随机负载均衡挑选实例

服务实例的权重设置

  1. 实例的权重控制

    1. Nacos控制台可以设置实例的权重值,0~1之间

    2. 同集群内的多个实例,权重越高北访问的频率越高

    3. 权重设置为0则完全不会被访问

环境隔离-namespace

Nacos中服务存储和数据存储的最外层都是一个名为namespace的东西,用来做最外层隔离

  1. 在Nacos控制台可以创建namespace,用来隔离不同环境

  2. 然后填写一个新的命名空间信息(不填写id,则UUID自动生成id)

  3. 保存后会在控制台看到这个命名空间的id:

  4. 修改需要配置的项目的application.yml,添加namespace:

spring:datasource:url: jdbc:mysql://localhost:3306/cloud_order?useSSL=falseusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driverapplication:name: orderservice #服务名称cloud:nacos:server-addr: localhost:9001discovery:cluster-name: SC # 集群名称,代指杭州namespace: e371f002-c878-4ceb-8339-5e605150395e #命名空间
  1. Nacos环境隔离

    1. namespace用来做环境隔离

    2. 每个namespace都是唯一id

    3. 不同的namespace下的服务不可见

Nacos和Eureak对比

临时实例

临时实例如果健康状态为false时会被剔除,但非临时实例不会被剔除,而是等待实例恢复健康

临时实例和非临时实例

服务注册到Nacos时,可以选择注册为临时实例或非临时实例,通过下面的配置来设置(ephemeral为ture时临时实例,为false时非临时实例):

cloud:nacos:server-addr: localhost:9001discovery:cluster-name: SC # 集群名称,代指杭州namespace: e371f002-c878-4ceb-8339-5e605150395e #命名空间ephemeral: false #是否临时节点

即使健康为false时也不会停止实例

  1. Ncaos与Eureka的共同点

    1. 都支持服务注册和服务拉取

    2. 都支持服务提供者心跳方式做健康检测

  2. Nacos与Eureka的区别

    1. Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式

    2. 临时实例的心跳不正常会被剔除,非临时实例则不会被剔除

    3. Nacos支持服务列表变更的消息推送模式,服务列表更新更及时

    4. Nacos集群默认采用AP方式,当集群中存在非临时实例时,采用cp模式;Eureka采用AP方式

Nacos配置管理

统一配置管理

配置更改热更新

  1. 在Nacos中添加配置信息:

  2. 在弹出的表单中填写配置信息:

原配置获取的步骤如下:

nacos加入流程

实现

  1. 引入Nacos的配置管理客户端依赖:

    <!--nacos配置管理依赖-->
    <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId><version>2.2.5.RELEASE</version>
    </dependency>

  2. 在项目的resource目录添加一个bootstrap.yml文件,这个文件是引导文件,优先级高于application.yaml:

    spring:application:name: userserviceprofiles:active: dev #激活环境cloud:nacos:server-addr: localhost:9001 #nacso地址config:file-extension: yaml #配置文件后缀

  3. 我们在项目的controller中做测试看看有没有配置成功:

    @Value("${pattern.dateformat}")
    private String dateFormat;@GetMapping("now")
    public String now() {return "当前时间:" + LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateFormat));
    
    }

总结(将配置交给Nacso管理的步骤)

  1. 在Nacos中添加配置文件

  2. 在微服务中引入nacos的config依赖

  3. 在微服务中添加bootstrap.yml,配置nacos地址,当前环境,服务名称,文件后缀民。这些决定了程序启动时去nacos读取哪个文件

热更新

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

  1. 方式一:在@Value注入的变量所在类上添加注解@RefreshScope

    @Slf4j
    @RestController
    @RequestMapping("/user")
    @RefreshScope
    public class UserController {@Value("${pattern.dateformat}")private String dateFormat;

  2. 方式二:使用@ConfigurationProperties注解

    1. 新建一个类

      @Data
      @Component
      @ConfigurationProperties(prefix = "pattern")
      public class PatternProperties {private String dateformat;
      }

    2. 属性注入实现

          @Autowiredprivate PatternProperties properties;//    @Value("${pattern.dateformat}")
      //    private String dateFormat;@GetMapping("now")public String now() {return "当前时间:" + LocalDateTime.now().format(DateTimeFormatter.ofPattern(properties.getDateformat()));}

多环境配置共享

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

  1. [spring.application.name]-[spring.profiles.active].yaml,例如:uservice-dev.yaml

  2. [spring.application.name].yaml,例如:userservice.yaml

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

步骤

这里有两个环境

添加配置

端口8001在public中,8002,8004在dev中分别是两个环境,分别东鞥获取到envSharedValue的值。实现了不同环境共享了配置文件

多环境配置优先级

服务名-profile.yaml > 服务名.yaml > 本地配置

Nacos集群搭建

1.集群结构图

官方给出的Nacos集群图:

其中包含3个nacos节点,然后一个负载均衡器代理3个Nacos。这里负载均衡器可以使用nginx。

我们计划的集群结构:

三个nacos节点的地址:

节点ipport
nacos1192.168.150.18845
nacos2192.168.150.18846
nacos3192.168.150.18847

2.搭建集群

搭建集群的基本步骤:

  • 搭建数据库,初始化数据库表结构

  • 下载nacos安装包

  • 配置nacos

  • 启动nacos集群

  • nginx反向代理

2.1.初始化数据库

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

官方推荐的最佳实践是使用带有主从的高可用数据库集群,主从模式的高可用数据库可以参考传智教育的后续高手课程。

这里我们以单点的数据库为例来讲解。

首先新建一个数据库,命名为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');

2.2.下载nacos

nacos在GitHub上有下载地址:Tags · alibaba/nacos · GitHub,可以选择任意版本下载。

本例中才用1.4.1版本:

2.3.配置Nacos

将这个包解压到任意非中文目录下,如图:

目录说明:

  • bin:启动脚本

  • conf:配置文件

进入nacos的conf目录,修改配置文件cluster.conf.example,重命名为cluster.conf:

然后添加内容:

127.0.0.1:8845
127.0.0.1.8846
127.0.0.1.8847

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

spring.datasource.platform=mysqldb.num=1db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user.0=root
db.password.0=123

2.4.启动

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

然后分别修改三个文件夹中的application.properties,

nacos1:

server.port=8845

nacos2:

server.port=8846

nacos3:

server.port=8847

然后分别启动三个nacos节点:

startup.cmd

2.5.nginx反向代理

找到课前资料提供的nginx安装包:

解压到任意非中文目录下:

修改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;}
}

而后在浏览器访问:http://localhost/nacos即可。

代码中application.yml文件配置如下:

spring:cloud:nacos:server-addr: localhost:80 # Nacos地址

2.6. 优化

  • 实际部署时,需要给做反向代理的nginx服务器设置一个域名,这样后续如果有服务器迁移nacos的客户端也无需更改配置.

  • Nacos的各个节点应该部署到多个不同服务器,做好容灾和隔离

总结

集群搭建步骤:

  1. 搭建mysql集群搭建并初始化数据库表

  2. 下载解压nacos

  3. 修改集群配置(节点信息),数据库配置

  4. 分别启动多个nacos结点

  5. nginx反向代理

HTTP客户端Feign

1.RestTemplate方法调用存在的问题

先来看我们以前利用RestTemplate发起远程调用的代码:

String url = "http://userservice/user/"+order.getUserId();
User user = restTemplate.getForObject(url, User.class);

存在下面的问题:

  1. 代码可读性差,编程体验不统一

  2. 参数复杂URL难以维护

Feign的介绍

Feign是一个声明式的http客户端,官方地址:GitHub - OpenFeign/feign: Feign makes writing java http clients easier其作用就是帮助我们优雅的实现http请求的发送,解决上面提到的问题。

定义和使用Feign客户端

使用Feign的步骤如下:

  1. 引入依赖:

    <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
  2. 在order-service的启动类添加注解开启Feign的功能:

    @EnableFeignClients
  3. 编写Feign客户端(包主启动类里):

    @FeignClient("userservice")
    public interface UserClient {@GetMapping("/user/{id}")User findById(@PathVariable("id")  Long id);
    

    主要基于SpringMVC的注解来声明远程调用的信息,比如:

    1. 服务名称:userservice

    2. 请求方式:GET

    3. 请求路径:/user/{id}

    4. 请求参数:Long id

    5. 返回值类型:User

  4. 使用Feign客户端代替RestTemplate

    @Autowired
    private UserClient userClient;public Order queryOrderById(Long orderId) {
    // 1. 查询订单
    Order order = orderMapper.findById(orderId);
    // 2.Feign远程调用
    User user = userClient.findById(order.getUserId());
    // 3.封装user到order
    order.setUser(user);
    // 根据id查询订单并返回
    return order;

Feign的使用步骤

  1. 引入依赖

  2. 添加@EnableFeignClients注解

  3. 编写FeignClient接口

  4. 编写FeignClient中定义的方法代替RestTemplate

自定义Feign的配置

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

类型作用说明
feign.Logger.Level修改日志级别包含四种不同的基别:None,Basic,Headers,Full
feign.codec.Decoder响应结果的解析器http远程调用的结果做解析,例如解析json字符串为json字符串为java对象
feign.codec.Encoder请求参数编码将请求参数编码,便于通过http请求发送
feign.Contract请求参数编码将请求参数编码,便于通过http请求发送
feign.Retryer失败重机制请求失败的重试机制,默认式没有,不过会使用Ribbon的重试

一般我们需要配置的就是日志级别。

自定义Feign的配置

方式一:配置文件方式

  1. 全局生效:

    #feign:
    feign:client:config:default: #默认配置loggerLevel: FULL #日志级别
    #      - TRACE:追踪级别的日志,输出最详细的日志信息。 - DEBUG:调试级别的日志,输出详细的日志信息。 - INFO:信息级别的日志,输出一般性的日志信息。 - WARN:警告级别的日志,输出可能表示潜在问题的日志信息。 - ERROR:错误级别的日志,输出发生的错误信息。 - OFF:完全关闭该 logger 输出日志。
    

  2. 局部生效

    feign:client:config:
    #      default: #默认配置
    #        loggerLevel: FULL #日志级别
    #      - TRACE:追踪级别的日志,输出最详细的日志信息。 - DEBUG:调试级别的日志,输出详细的日志信息。 - INFO:信息级别的日志,输出一般性的日志信息。 - WARN:警告级别的日志,输出可能表示潜在问题的日志信息。 - ERROR:错误级别的日志,输出发生的错误信息。 - OFF:完全关闭该 logger 输出日志。userservice: #指定服务名称loggerLevel: FULL

方式二:Java代码配置

需要线声明一个bean

package cn.itcast.order.config;import feign.Logger;
import org.springframework.context.annotation.Bean;/*** @ClassName DefaultFeignConfiguration* @Author AndyWu* @Date 2024-01-03 19:59* @Motto 学不死就往死里学* @Version 1.0*/public class DefaultFeignConfiguration {@Beanpublic Logger.Level logger(){return Logger.Level.BASIC;}
}
  1. 而后如果是全局配置,则把它放到@EnableFeignClients这个注解中:

    @EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
  2. 如果是局部配置,则把它放到@FeignClient这个注解中

    @FeignClient(value = "uservice",configuration = FeignClientProperties.FeignClientConfiguration.class)

总结

Feign的日志配置:

  1. 方式一是配置文件,feign.client.config.xxx.loggerLevel

    1. 如果xxx是default则代表全局

    2. 如果xxx是服务名称,列入userservice则代表服务

  2. 方式二是Java代码配置Logger.Level这个Bean

    1. 如果在@EnableFeignClients注解声明则代表全局

    2. 如果在@FeignClient注解中声明则代表某服务

Feign的性能优化

Feign地城的客户端实现

  1. URLConnection:默认实现,不支持连接池

  2. Apache HttpClient:支持连接池

  3. OKHttp:支持连接池

因为优化Feign的性能主要包括:

  1. 使用连接池代替默认的URLConnection

  2. 日志级别,最好用basic或none

Feign的性能优化-连接池配置

Feign添加HttpClient的支持:

  1. 引入依赖:

    <!--引入HttpClient依赖-->
    <dependency><groupId>io.github.openfeign</groupId><artifactId>feign-httpclient</artifactId>
    </dependency>
  2. 配置连接池:

    feign:httpclient:enabled: true #开启feign的httpclientmax-connections: 200 #最大连接数max-connections-per-route: 50 #每个路由最大连接数

总结

Feign的优化

  1. 日志基别尽量用basic

  2. 使用HttpClient或OKHttp代替URLConnection

    1. 引入fegn-httpClient依赖

    2. 配置文件开启httpClient功能,设置连接池参数

Feign的最佳实践

方式一(继承)

给消费者的FeignClient和提供者的controller定义统一的父接口作为标准。(spring官方不推荐,因为紧耦合)

方式二(抽取):

将FeignClient抽取为独立模块,并且把接口有关的pojo,默认的Feign配置都放到这个模块中,提供给所有消费者使用(问题:可能只需要几个接口但引入依赖,把所有接口全部引入进来了)

实现

实现最佳实现方式二的步骤如下:

  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所在包(全部扫描)

@EnableFeignClients(basePackages = "cn.itcast.feign.clients")

方式二:指定FeignClient字节码(部分扫描,精准定位)

@EnableFeignClients(clients = {UserClient.class})

完整的代码

@EnableFeignClients(clients = {UserClient.class},defaultConfiguration = DefaultFeignConfiguration.class)

总结

不同包的FeignClient的导入有两种方式:

  1. 在@EnableFeignClients注解中添加basePackages,指定FeignClient所在的包

  2. 在@EnableFeignClients注解中添加clients,指定具体FeignClient的字节码

总结

  1. 让controller和FeignClient继承同一接口

  2. 将FeignClient,POJO,Feign的默认配置都定义到一个项目中,供所有消费者使用

统一网关Gateway

为什么需要网关

网关功能

  1. 身份认证和权限校验

  2. 服务路由,负载均衡

  3. 请求限流

网关的技术实现

在spring cloud中网关的实现包括两种:

  1. gateway

  2. zuul

Zuul是基于Servlet的实现,属于阻塞式编程。而spring cloud Gateway则是基于spring5中提供的WebFlux,属于响应式编程的实现,具备更好的性能。

总结

网关的作用:

  1. 对用户请求的身份认证,权限校验

  2. 将用户请求路由到微服务,并实现负载均衡

  3. 对用户请求做限流

gateway快速入门

搭建网关

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

    <!--网关依赖-->
    <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId>
    </dependency><!--服务发现依赖-->
    <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><version>2.2.5.RELEASE</version>
    </dependency>
  2. 编写路由配置及nacos地址

    必须在同一个环境下,不能一个是测试环境一个是运行环境

    server:port: 10010 #服务端口
    spring:application:name: gateway #服务名称cloud:nacos:server-addr: localhost:9001 #nacos地址discovery:cluster-name: SC # 集群名称,代指杭州namespace: e371f002-c878-4ceb-8339-5e605150395e #命名空间gateway:routes:- id: user-service #路由iduri: lb://userservice #服务地址predicates:- Path=/user/** #路由规则,判断路径是否以/user开通,如果符合就会代理到userservice里去- id: order-serviceuri: lb://orderservicepredicates:- Path=/order/**
    #          filters:
    #            - StripPrefix=1 #去除前缀
     

总结

网关搭建步骤:

  1. 创建项目,引入nacos服务发现和gateway依赖

  2. 配置application.yaml,包括服务基本信息,nacos地址,路由

路由配置包括

  1. 路由id:路由的唯一标识

  2. 路由目标(uri):路由的目标地址,http代表固定地址,lb代表根据服务名负载均衡

  3. 路由断言(predicates):判断路由的规则,

  4. 路由过滤器(filters):对请求或响应做处理

断言工厂

路由断言工厂Route Predicate Factory

网关路由可以配置的内容包括

  1. 路由id:路由唯一标示

  2. uri:路由目的地,支持lb和http两种

  3. predicates:路由断言,判断请求是否符合要求,符合则转发到路由目的地

  4. filters:路由过滤器,处理请求或响应

断言工厂

  1. 我们在配置文件中写断言规则只是字符串,这些字符串会被PredicateFactory读取并处理,转变为路由判断的条件

  2. 例如Path=/user/**是按照路径匹配,这个规则是由

    org.springframework.cloud.gateway.handler.predicate.PathRoutePredicateFactory类来处理的

  3. 像这样的断言工厂在spring cloudGateway还有十几个

spring提供了11种基本的Predicate工厂

实例

测试1

yaml中添加断言

gateway:routes:- id: user-service #路由iduri: lb://userservice #服务地址predicates:- Path=/user/** #路由规则,判断路径是否以/user开通,如果符合就会代理到userservice里去- id: order-serviceuri: lb://orderservicepredicates:- Path=/order/**- After=2031-01-01T12:00:00.000+08:00[Asia/Shanghai] #时间过滤

不符合

测试2

在yaml中添加

gateway:routes:- id: user-service #路由iduri: lb://userservice #服务地址predicates:- Path=/user/** #路由规则,判断路径是否以/user开通,如果符合就会代理到userservice里去- id: order-serviceuri: lb://orderservicepredicates:- Path=/order/**- Before=2031-01-01T12:00:00.000+08:00[Asia/Shanghai] #时间过滤

符合

过滤器工厂

路由过滤器gatewayFilter

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

给gateway中修改application.yaml文件,给userservice的路由添加过滤器:

gateway:routes:- id: user-service #路由iduri: lb://userservice #服务地址predicates:- Path=/user/** #路由规则,判断路径是否以/user开通,如果符合就会代理到userservice里去filters:- AddRequestHeader=Truth,Itcast is freaking aowsome! #添加请求头

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

    gateway:routes:- id: user-service #路由iduri: lb://userservice #服务地址predicates:- Path=/user/** #路由规则,判断路径是否以/user开通,如果符合就会代理到userservice里去
#          filters:
#            - AddRequestHeader=Truth,Itcast is freaking aowsome! #添加请求头- id: order-serviceuri: lb://orderservicepredicates:- Path=/order/**- Before=2031-01-01T12:00:00.000+08:00[Asia/Shanghai] #时间过滤default-filters:- AddRequestHeader=Truth,Itcast is freaking aowsome! #添加请求头

总结

  1. 过滤器的作用是什么?

    1. 对路由的请求或响应做加工处理,比如添加请求头

    2. 配置在路由下的过滤器只对当前路由的请求生效

  2. defaultFiters的作用是什么?

    1. 对所有路由都生效的过滤器

全局过滤器

全局过滤器GlobalFilter

全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与GatewayFilter的作用一样。

区别在于GatewayFilter通过配置定义,处理逻辑固定。而GlobalFiter的逻辑需要自己写代码实现。

定义方式是实现GlobalFiter接口

1.自定义类,实现GlobalFilter接口,添加@Order注解:

@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//1.获取请求头中的tokenServerHttpRequest request = exchange.getRequest();MultiValueMap<String, String> params = request.getQueryParams();//2.获取参数中的authorization 参数String auth = params.getFirst("authorization");//3.判断参数是否有等于adminif ("admin".equals(auth)){//4.是,放行return chain.filter(exchange);}//5.否,拦截//5.1.设置状态码exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);//5.2.拦截请求return exchange.getResponse().setComplete();}//@Order(-1)@Overridepublic int getOrder() {return -1;}
}

失败

成功

总结

  1. 全局过滤器的作用是什么?

    1. 对所有路由都生效的过滤器,并且可以自定义处理逻辑

  2. 实现全局过滤器的步骤?

    1. 实现GlobalFilter接口

    2. 添加@Order注解或实现Ordered接口

    3. 编写处理逻辑

过滤器执行顺序

请求进入网关碰到三类过滤器:当前路由的过滤器,DefaultFilter,GlobalFilter

请求路由后,会将当前路由过滤器和DefaultFilter,GlobalFilter,合并到一个过滤器链(集合)中,排序后依次执行每个过滤器

  1. 每一个过滤器都必须指定一个int类型的order值,order值越小,优先级越高,执行顺序越靠前。

  2. GlobalFilter通过实现Ordered接口,或者添加@Order注解来指定order值,由我们自己指定

  3. 路由过滤器和defaultFilter的order由spring指定,默认是按照声明顺序从1递增。

  4. 当过滤器的order值一样时,会按照defaultFilter > 路由过滤器 > GlobalFiter的顺序执行

总结

路由过滤器,defaultFilter,全局过滤器的执行顺序?

  1. order值越小,优先级越高

  2. 当order值一样是,顺序时defaultFilter最先,然后是局部的路由过滤器,最后是全局过滤器

跨域问题

跨域:域名不一致就是跨域,主要包括:

  1. 域名不同:www.taobao.com和www.taobao.org和www.jd.com和miaosha.js.com

  2. 域名相同,端口不同:localhost:8080和localhost:8081

跨域问题:浏览器禁止请求的发起者与服务端发生跨域ajax请求,请求被浏览器拦截的问题

解决方案:CORS (CORS是Cross-Origin Resource Sharing的缩写,跨域资源分享。在Web开发中,由于浏览器的同源策略限制,JavaScript不能从一个域名下的网页向其他域名下的网页请求资源,但是CORS提供了实现跨域请求的标准解决方案。通过在服务器端设置响应头部信息,允许指定的源访问资源,从而实现跨域请求。这样可以实现不同域名之间的数据交互,为Web开发提供了更多的灵活性和扩展性。)

跨域问题解决:

spring:cloud:gateway:globalcors: # 全局的跨域处理add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题corsConfigurations:'[/**]':allowedOrigins: # 允许哪些网站的跨域请求- "http://localhost:8090"- "http://www.leyou.com"allowedMethods: # 允许的跨域ajax的请求方式- "GET"- "POST"- "DELETE"- "PUT"- "OPTIONS"allowedHeaders: "*" # 允许在请求中携带的头信息allowCredentials: true # 是否允许携带cookiemaxAge: 360000 # 这次跨域检测的有效期

总结

CORS跨域要配置的参数包括哪几个?

  1. 允许哪些域名跨域?

  2. 允许哪些请求方式?

  3. 允许哪些哪些请求方式?

  4. 是否允许使用cookie?

  5. 有效期是多久?

感谢!各位道友阅读

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.bcls.cn/qmgD/9925.shtml

如若内容造成侵权/违法违规/事实不符,请联系编程老四网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

我承认,我低估鸿蒙了 !

2019年&#xff0c;鸿蒙刚出来的时候&#xff0c;我心里是有点犯嘀咕的&#xff0c;虽然很支持国产操作系统&#xff0c;但是我知道&#xff0c;开发操作系统也许不难&#xff0c;但是建立一个全新的生态太难了&#xff01; 如果操作系统中缺乏应用程序&#xff0c;就不会有人…

排序——希尔排序

希尔排序 希尔排序步骤 希尔排序的核心还是插入排序&#xff0c;但是把插入排序分成两部分&#xff0c;1.预排序2.插入排序。先对原数组进行预排序&#xff0c;使数组接近有序&#xff08;让更大的数字和更小的数字更快的分配到两边&#xff09;&#xff0c;然后再对已经接近有…

模拟算法题练习(二)(DNA序列修正、无尽的石头)

目录 &#xff08;一、DNA序列修正&#xff09; 问题分析 方法实现 时间复杂度和空间复杂度分析 &#xff08;二、无尽的石头&#xff09; &#xff08;一、DNA序列修正&#xff09; 问题描述 在生物学中&#xff0c;DNA序列的相似性常被用来研究物种间的亲缘关系。现在我…

MySQL深入——22

kill不掉的语句 在MySQL当中有两个kill命令一个是kill query 线程id表示中止这个线程当中正在执行的语句&#xff0c;另外一个是 kill Connection线程id表示断开这个连接。 在使用MySQL时&#xff0c;使用kill命令之后看show processlist显示的command列为killed&#xff0c;…

《最新出炉》系列初窥篇-Python+Playwright自动化测试-34-处理https 安全问题或者非信任站点-下篇

1.简介 这一篇宏哥主要介绍playwright如何在IE、Chrome和Firefox三个浏览器上处理不信任证书的情况&#xff0c;我们知道&#xff0c;有些网站打开是弹窗&#xff0c;SSL证书不可信任&#xff0c;但是你可以点击高级选项&#xff0c;继续打开不安全的链接。举例来说&#xff0c…

自动化测试摸索:python+selenium+pytest(持续更新.....)

一、环境搭建 1、python 安装 下载链接&#xff1a;Python Releases for Windows | Python.org 自己选择合适的版本下载 当下载完毕时&#xff0c;找到该安装程序&#xff1a;python-3.12.2-amd64.exe文件&#xff0c;双击启动安装向导。 为了防止C:盘文件因系统故障或者无…

CDN原理探究

来源于百度&#xff1a; https://baike.baidu.com/item/%E5%86%85%E5%AE%B9%E5%88%86%E5%8F%91%E7%BD%91%E7%BB%9C/4034265?frge_ala 通过上图&#xff0c;我们可以了解到&#xff0c;使用了CDN缓存后的网站的访问过程变为&#xff1a; 用户向浏览器提供要访问的域名&#xff…

unsigned详讲(干货满满)

前言&#xff1a;过年偷懒了(●ˇ∀ˇ●)&#xff0c;但是年后开学了一定要恢复学习状态&#xff0c;在复习加继续学习的途中&#xff0c;我发现对于unsigned关键字的掌握并不是很熟练&#xff0c;于是翻阅了各个大佬的博客以及书籍&#xff0c;总结了对于unsigned的一些知识点…

pip降级在pycharm中

PyCharm依赖于"–build-dir"参数安装第三方库&#xff0c;但该参数在最新的23.0版pip中已删除 解决办法就是降级pip&#xff0c;PyCharm中选择File&#xff0c;找到编译器&#xff0c;点击pip&#xff0c;勾选对应版本即可 或者在cmd中执行运行python -m pip install…

大语言模型推理加速技术:计算加速篇

原文&#xff1a;大语言模型推理加速技术&#xff1a;计算加速篇 - 知乎 目录 简介 Transformer和Attention 瓶颈 优化目标 计算加速 计算侧优化 KVCache Kernel优化和算子融合 分布式推理 内存IO优化 Flash Attention Flash Decoding Continuous Batching Page…

Redis冲冲冲——事务支持,AOF和RDB持久化

目录 引出Redis事务支持&#xff0c;AOF和RDB持久化1、Redis的事务支持2、Redis的持久化 Redis冲冲冲——缓存三兄弟&#xff1a;缓存击穿、穿透、雪崩缓存击穿缓存穿透缓存雪崩 总结 引出 Redis冲冲冲——事务支持&#xff0c;AOF和RDB持久化 Redis事务支持&#xff0c;AOF和…

Mybatis批量更新对象数据的两种方法

说明&#xff1a;遇到一次需要批量修改对象的场景。传递一个对象集合&#xff0c;需要根据对象ID批量修改数据库数据&#xff0c;使用的是MyBatis框架。查了一些资料&#xff0c;总结出两种实现方式。 创建Demo 首先&#xff0c;创建一个简单的Demo&#xff1b; &#xff08…

K8S存储卷与PV,PVC

一、前言 Kubernetes&#xff08;K8s&#xff09;中的存储卷是用于在容器之间共享数据的一种机制。存储卷可以在多个Pod之间共享数据&#xff0c;并且可以保持数据的持久性&#xff0c;即使Pod被重新调度或者删除&#xff0c;数据也不会丢失。 Kubernetes支持多种类型的存储卷…

C/C++ 迷宫游戏

游戏介绍 这个迷宫探险游戏有以下功能&#xff1a; 探险&#xff1a;选择该选项后&#xff0c;玩家会进入地下迷宫进行探险。在随机事件中&#xff0c;可能会遇到陷阱、发现金币或者什么都没有发生。陷阱会使玩家失去一定的生命值&#xff0c;金币可以增加玩家的金币数量。 休…

C++——内存管理(new和delete)详解

目录 C/C内存管理 案例&#xff1a;变量在内存中到底会在哪&#xff1f; New和delete Operator new和operator delete函数 New和delete的原理 对内置类型 对自定义类型 定位new New/delete和malloc/free的区别 C/C内存管理 C/C内存管理分布图&#xff1a;&#xff08;从…

2024牛客寒假算法基础集训营4

目录 A.柠檬可乐 B.左右互博 C.冬眠 D.守恒 E.漂亮数组 F.来点每日一题 G.数三角形&#xff08;easy&#xff09; A.柠檬可乐 阅读理解题&#xff0c;依照题目直接模拟即可 void solve(){int a,b,k; cin>>a>>b>>k;if(a>k*b) cout<<"go…

【Java】基本数据类型、包装类与字符串间的转换 例题

写在前面&#xff1a; 关于这道题&#xff0c;初见感觉有点cpu烧坏了&#xff0c;准确来说是看了网上的一些讲解都感觉不尽人意。自己整理了一下&#xff0c;希望能帮助到大家。 题目&#xff1a; 如下两个题目输出结果相同吗&#xff1f;各是什么。 Object o1 true ? new…

Java毕业设计-基于springboot开发的Web社区医院管理服务系统-毕业论文+答辩PPT(有源代码)

文章目录 前言一、毕设成果演示&#xff08;源代码在文末&#xff09;二、毕设摘要展示1.开发说明2.需求分析3、系统功能结构 三、系统实现展示1、系统功能模块2、管理员功能模块3、用户功能模块4、医生功能模块 四、毕设内容和源代码获取总结 Java毕业设计-基于springboot开发…

CGI程序与ShellShock漏洞

CGI是什么&#xff1f; CGI&#xff08;通用网关接口&#xff0c;Common Gateway Interface&#xff09;程序是一种用于在Web服务器上执行动态内容的技术。与服务器上普通的后端代码相比&#xff0c;CGI程序有几个区别&#xff1a; 执行环境&#xff1a; CGI程序在服务器上作为…

从CPU缓存结构到原子操作

一、CPU缓存结构 1.1 CPU的多级缓存 因为CPU的计算速度非常快&#xff0c;但内存的访问速度相对较慢。因此&#xff0c;如果CPU每次都要从内存读取数据&#xff0c;会造成大量的等待时间&#xff0c;降低整体性能。 通过引入多级缓存&#xff0c;可以在CPU和内存之间建立数据…
推荐文章