Nacos学习(二)——继承Feign与Config中心
目录
一、集成Feign
(一)基础用法
1.添加openfeign依赖
2. 开启openFeign注解扫描
3.创建ProviderService接口
4.修改ConsumerController
(二)OpenFeign日志配置
(三)参数传递
1.参数传递的问题
2.参数传递的方式
2.1URL路径传参
2.2URL上拼接参数
2.3body传参
二、Config中心
1.bootstrap方式
1.1pom.xml
1.2新增bootstrap.properties
1.3在nacos中,增加一个配置
1.4新建接口
1.5重启consumer-service
2.spring.config.import方式(推荐)
2.1注释掉bootstrap依赖并删除bootstrap.properties文件
2.2application.properteis中,增加配置
2.3重启consumer-service
3.动态刷新
4.加载指定文件
4.1Group
4.1.1克隆配置
4.1.2修改application.properties
4.1.3重启consumer-service服务,刷新浏览器
4.2Namespace
4.2.1新建两个命名空间
5.使用Mysql
5.1nacos-mysql.sql
5.2修改conf下的application.properties文件
5.3保存后重启nacos
书接上文《Nacos学习(一)——基本介绍、安装与负载均衡策略》
一、集成Feign
(一)基础用法
feign本质是对 Http请求封装,使服务之间的调用更简单。
1.添加openfeign依赖
修改consumer-service服务的pom.xml文件:
<!-- openfeign 也是放在调用方-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2. 开启openFeign注解扫描
@SpringBootApplication
@EnableFeignClients // 开启openFeign注解扫描
public class ConsumerApplication {public static void main(String[] args) {SpringApplication.run(ConsumerApplication.class,args);}
}
3.创建ProviderService接口

@FeignClient(name = "provider-service")
public interface ProviderService {@GetMapping("/provider")String provider();
}
就是将红框里的方法,复制到ProviderService中,并改为抽象方法

这段代码定义了一个名为 ProviderService 的 Feign 客户端接口,用于调用名为 provider-service 的服务。该接口包含一个方法 provider,通过 GET 请求访问 /provider 路径,并返回一个字符串。
Feign 客户端被称为“代理”的原因在于它使用了代理模式。具体来说:
- 动态代理:Feign 通过动态代理机制生成接口的实现类。在运行时,当你调用 ProviderService 接口的方法时,实际上是由 Feign 生成的代理对象来处理请求。
- 远程调用透明化:代理对象负责将方法调用转换为 HTTP 请求发送到目标服务,并将响应结果转换为方法的返回值。对于开发者而言,这种远程调用是透明的,就像调用本地方法一样简单。
因此,Feign 客户端被称为“代理”,因为它充当了本地服务与远程服务之间的中介角色,简化了远程服务调用的过程。
4.修改ConsumerController
添加下面的代码:
@Autowired
private ProviderService providerService;@GetMapping("/balancer2")
public String balancer2() {return providerService.provider();
}
重启consumer-service服务,访问该接口,采用的是provider的随机权重

(二)OpenFeign日志配置
注意:凡是带有default的,都表示全局配置。
配置日志,可以让我们看到远程调用时的一些详细情况
日志配置有 2 种:
- 全局配置:feign.client.config.default.属性名
- 局部配置:feign.client.config.服务名.属性名
如果同时存在,以 局部配置 为主,修改配置文件:
# feign日志级别,可选值包括BASIC、HEADERS、FULL或NONE,用于请求和响应的日志输出级别
# NONE:不记录日志
# BASIC:记录方法、URL、HTTP状态、响应时间等,适用于生产环境
# HEADERS:在BASIC的基础上,额外记录请求和响应头信息
# FULL: 记录请求和响应的所有数据,适用于开发环境
feign.client.config.default.loggerLevel=full#如果想让feign的日志生效,还需要设置springboot的日志级别
# 格式:logging.level.<FeignClient所在类包名>=debug
logging.level.com.xiaoai.service=debug
# 如果只想让某一个feign客户端生效,那么:logging.level.<FeignClient类全路径>=debug#springboot的日志级别
logging.level.root=DEBUG
最终的配置文件,consumer-service的application.properties:
server.port=8888
spring.application.name=consumer-service
#nacos的地址
spring.cloud.nacos.discovery.server-addr=192.168.157.102:8848
spring.cloud.nacos.discovery.ip=192.168.0.16
# 指定springboot的日志级别
logging.level.root=debug
# 指定feign的日志级别
feign.client.config.default.logger-level=full
# 指定调用的provider-service服务的日志级别
logging.level.com.javatest.service.ProviderService=debug
注意:debug级别的日志太多,启动有报错不需要理会。

(三)参数传递
1.参数传递的问题
@RestController
public class ProviderController {@Value("${server.port}")private String port;@GetMapping("/provider")public String provider(String username) {return "provider-service:" + port + "------" + username;}
}
openFeign默认支持spring mvc 注解,调用接口时,如果传递参数,也要加上对应的注解,比如:
@FeignClient(name = "provider-service")
public interface ProviderService {@GetMapping("/provider")String provider(@RequestParam String username);
}
修改ConsumerController中的接口:
@Autowired
private ProviderService providerService;@GetMapping("/balancer2")
public String balancer2(String username) {return providerService.provider(username);
}
重启consumer-service和provider-service集群,浏览器url输入参数:

如果没有 RequestParam 注解,结果:

这是因为,底层把参数加到 body 中,比如:


同时,因为openfeign底层用的是jdk的原生http工具,在HttpURLConnection中如果body不是空,会把get请求转换为post请求,所以提示 405 状态码。
而使用 RequestParam 注解后,会把参数拼到 url 上,比如:

2.参数传递的方式
2.1URL路径传参
调用方服务代码:
@RestController
public class ConsumerController {@Autowiredprivate ProviderService providerService;/*** 使用URL路径传参* @param username* @return*/@GetMapping("/balancer3")public String balancer3(String username) {return providerService.getport(username);}}
@FeignClient(name = "provider-service")
public interface ProviderService {/*** URL路径传参* @param username* @return*/@GetMapping("/getport/{username}")String getport(@PathVariable String username);
}
被调用方接收参数:
@RestController
public class ProviderController {@Value("${server.port}")private String port;/*** 接收URL路径传参* @param username* @return*/@GetMapping("/getport/{username}")public String getport(@PathVariable String username) {return "getport:" + port + "------" + username;}
}
2.2URL上拼接参数
ConsumerController:
@RestController
public class ConsumerController {@Autowiredprivate ProviderService providerService;/*** URL上拼接参数方式一:零散参数* http://localhost:8888/balancer2?username=rose&age=19* @param username* @return*/@GetMapping("/balancer2")public String balancer2(String username, Integer age) {return providerService.provider(username, age); // 传递的零散参数是指这里}/*** URL上拼接参数方式二:传递对象* http://localhost:8888/getUser?username=jack&age=22* http://localhost:8888/getUser?username=%E5%BC%A0%E4%B8%89&age=29* %E5%BC%A0%E4%B8%89 是URL编码* @param user* @return*/@GetMapping("/getUser")public String getUser(User user) {return providerService.provider(user); // 传递的对象是指这里}/*** URL上拼接参数方式三:传递Map* http://localhost:8888/getMap?username=john&age=22* http://localhost:8888/getMap?username=%E5%BC%A0%E4%B8%89&age=22* @param user* @return*/@GetMapping("/getMap")public String getMap(User user) {Map<String, Object> map = new HashMap<>();map.put("username", user.getUsername());return providerService.provider(map); // 传递的Map是指这里}
}
ProviderService:
@FeignClient(name = "provider-service")
public interface ProviderService {/*** URL上拼接参数方式一:零散参数** @param username* @return*/@GetMapping("/provider")String provider(@RequestParam String username, @RequestParam Integer age);/*** URL上拼接参数方式二:传递对象* @param user* @return @SpringQueryMap注解只能修饰一个参数* @SpringQueryMap注解会将对象打散,以?的形式拼接,以&分割*/@GetMapping("/provider")String provider(@SpringQueryMap User user);/*** URL上拼接参数方式三:传递Map** @param map* @return*/@GetMapping("/provider")String provider(@RequestParam Map<String, Object> map);
}
被调用的服务的ProviderController:
@RestController
public class ProviderController {@Value("${server.port}")private String port;/*** 接收URL上拼接参数三种方式** @param username* @return*/@GetMapping("/provider")public String provider(String username) {return "provider:" + port + "------" + username;}
}
注意:
ProviderService和ProviderController中的接口是意义对应的,一般是将ProviderController中的请求方式和方法复制到ProviderService中,去掉方法体和public,变成抽象方法。
我这里没有对应是因为ProviderService中使用了方法重载。
2.3body传参
使用 RequestBody 注解 或 无任何注解时,会把参数放到 body 中,比如:
ConsumerController:
@GetMapping("/testBody")
public String testBody(User user) {return providerService.providerBody(user);
}
ProviderService:
@GetMapping("/providerBody") // 改为@PostMapping也可以
String providerBody(User user);
被调用方ProviderController:
@PostMapping("/providerBody")
String providerBody(@RequestBody User user) {return "providerBody:" + port + "------" + user.getUsername() + "--------" + user.getAge();
}
浏览器请求:

二、Config中心
nacos 除了用于服务注册,还可以作为配置中心。
1.bootstrap方式
1.1pom.xml
修改 consumer-service 中的 pom.xml,增加下面的依赖:
<!-- nacos 配置中心 -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency><!-- bootstrap 依赖,2.4之前的springboot,并不需要单独依赖 这里使用的springboot版本是2.6.11,所以要手动添加-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
1.2新增bootstrap.properties
consumer-service中:
#从Nacos上获取配置文件
# 配置中心地址 这里的ip是nacos部署的机器ip
spring.cloud.nacos.config.server-addr=192.168.157.102:8848
注意:bootstrap.properties文件的优先级比application.properties文件的优先级高很多。因此,SpringBoot启动时,会先加载bootstrap.properties,后加载application.properties。
为了让日志少打印,将springboot的日志级别改为info,下面的两个日志级别配置就不会生效了。

1.3在nacos中,增加一个配置


1.4新建接口
@RestController
public class ConfigController {@Value("${hero.name}")private String hero;@GetMapping("/hero")public String hero() {return "hello, " + hero;}
}
1.5重启consumer-service
重启 consumer 后浏览器访问:

2.spring.config.import方式(推荐)
2.1注释掉bootstrap依赖并删除bootstrap.properties文件

2.2application.properteis中,增加配置
spring.cloud.nacos.config.server-addr=192.168.157.102:8848
#格式:nacos:dataId
spring.config.import=nacos:${spring.application.name}
application.properteis中的完整配置如下:
server.port=8888
spring.application.name=consumer-service
#指定了 Nacos 服务器的地址和端口
spring.cloud.nacos.discovery.server-addr=192.168.157.102:8848
# 指定当前应用在注册到 Nacos 时使用的 IP 地址
spring.cloud.nacos.discovery.ip=192.168.0.16spring.cloud.nacos.config.server-addr=192.168.157.102:8848
#格式:nacos:dataId
spring.config.import=nacos:${spring.application.name}# 指定springboot的日志级别
logging.level.root=info
# 指定feign的日志级别
feign.client.config.default.logger-level=full
# 指定调用的provider-service服务的日志级别
logging.level.com.javatest.service.ProviderService=debug
2.3重启consumer-service
重启 consumer 后浏览器访问:

3.动态刷新
如果想要实时刷新配置,必须添加@RefreshScope
@RestController
@RefreshScope // 实时刷新配置,在哪里使用nacos的配置,就在里使用@RefreshScope
public class ConfigController {@Value("${hero.name}")private String hero;@GetMapping("/hero")public String hero() {return "hello, " + hero;}
}
重启consumer-service,nacos修改配置:


刷新浏览器:新的配置能够自动加载

4.加载指定文件
4.1Group
4.1.1克隆配置




4.1.2修改application.properties
添加下面的配置:
spring.cloud.nacos.config.server-addr=192.168.157.102:8848
#格式:nacos:dataId
spring.config.import=nacos:${spring.application.name}# 当data ID相同时,指定配置的分组
spring.cloud.nacos.config.group=DEV_GROUP
4.1.3重启consumer-service服务,刷新浏览器

如果想要访问PROD_GROUP:
application.properties:
# 当data ID相同时,指定配置的分组
spring.cloud.nacos.config.group=PROD_GROUP
重启consumer-service服务,刷新浏览器

4.2Namespace
4.2.1新建两个命名空间



命名空间创建完成后,配置管理页面就会出现:

继续克隆,并且选择对应的命名空间:


修改两个命名空间中的配置:




修改application.properties文件:
添加想要获取的命名空间:
spring.cloud.nacos.config.server-addr=192.168.157.102:8848#格式:nacos:dataId
spring.config.import=nacos:${spring.application.name}# 当data ID相同时,指定配置的分组
spring.cloud.nacos.config.group=DEV_GROUP
spring.cloud.nacos.config.namespace=5479b5a2-5124-4b28-ba5e-88d10cdc6da0
重启consumer-service,刷新浏览器:

注意:如果Nacos上的配置不使用properties,而是使用yaml,需要修改application.properties文件。

# 当data ID相同时,指定配置的分组
spring.cloud.nacos.config.group=DEV_GROUP
spring.cloud.nacos.config.namespace=5479b5a2-5124-4b28-ba5e-88d10cdc6da0
spring.cloud.nacos.config.file-extension=yaml
5.使用Mysql
nacos默认使用嵌入式数据库(derby)实现数据的存储,不方便观察数据存储的情况
但它同时支持mysql,官方文档:Nacos支持三种部署模式
5.1nacos-mysql.sql
在mysql中新建一个数据库

执行这个sql脚本:



5.2修改conf下的application.properties文件

在文件的最后一行添加数据库配置:
spring.datasource.platform=mysqldb.num=1
db.url.0=jdbc:mysql://mysql所在的机器ip:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&serverTimezone=UTC
db.user=用户名
db.password=密码
5.3保存后重启nacos
重启nacos,会发现之前的配置都没有了,就证明切换成的mysql,比如:

在mysql中可以查看到:



tenant_id表示命名空间:

相关文章:
Nacos学习(二)——继承Feign与Config中心
目录 一、集成Feign (一)基础用法 1.添加openfeign依赖 2. 开启openFeign注解扫描 3.创建ProviderService接口 4.修改ConsumerController (二)OpenFeign日志配置 (三)参数传递 1.参数传递的问题 2.参数传递的方式 2.1URL路径传参 2.2URL上拼接参数 2.3body传参 …...
计算机网络安全之一:网络安全概述
1.1 网络安全的内涵 随着计算机和网络技术的迅猛发展和广泛普及,越来越多的企业将经营的各种业务建立在Internet/Intranet环境中。于是,支持E-mail、文件共享、即时消息传送的消息和协作服务器成为当今商业社会中的极重要的IT基础设施。然而࿰…...
未来SLAM的研究方向和热点
SLAM(Simultaneous Localization and Mapping)是同时定位与地图构建的缩写,指的是机器人或设备在一个未知环境中一边进行自我定位,一边构建出环境的地图。SLAM广泛应用于机器人、自动驾驶、无人机等领域,涉及多个研究方…...
DuodooBMS源码解读之 purchase_change 模块
采购变更模块用户使用手册 一、模块概述 本扩展模块主要用于处理采购变更相关业务,包括采购变更单的创建、展示以及将采购变更信息导出为 Excel 文件等功能。以下将详细介绍该模块的具体使用方法。 二、模块功能及使用方法 (一)采购变更单…...
uniapp中引入Vant Weapp的保姆级教学(包含错误处理)
废话不多说,直接上方法,网上的教学好多都是错误的 1.安装vant weapp 在Hbuilder的终端,输入以下代码 npm install vant/weapp -S --production 2.新建wxcomponents文件夹 在项目的跟目录新建一个“wxcomponents’文件夹,与app.…...
Effective C++ 读书笔记(十二)
条款三十四:区分接口继承和实现继承 public继承由两部分组成:函数接口继承和函数实现继承。这两者的差异很像函数声明和函数定义之间的差异。 作为类的设计者,我们有时希望派生类只继承成员函数的接口(也就是函数声明࿰…...
【卡梅德生物】构建噬菌体文库与噬菌体展示文库构建服务新探索
在生命科学与生物技术快速发展的当下,抗体文库构建、构建噬菌体文库以及噬菌体展示文库构建服务在生物医药研发领域中占据着举足轻重的地位。它们不仅是基础研究的重要工具,更是推动抗体药物开发、疾病诊断技术进步的关键力量。 构建噬菌体文库是整个技…...
【JavaScript】《JavaScript高级程序设计 (第4版) 》笔记-Chapter19-表单脚本
十九、表单脚本 表单脚本 JavaScript 较早的一个用途是承担一部分服务器端表单处理的责任。虽然 Web 和 JavaScript 都已经发展了很多年,但 Web 表单的变化不是很大。由于不能直接使用表单解决问题,因此开发者不得不使用JavaScript 既做表单验证…...
C++STL容器之map
1.介绍 map是 C 标准模板库(STL)中的一个关联容器,用于存储键值对(key-value pairs)。map中的元素是按照键(key)进行排序的,并且每个键在容器中是唯一的。map通常基于红黑树…...
基于Nanopi duo2的WiFi智能摄像头
1.固件包烧录 https://wiki.friendlyelec.com/wiki/index.php/NanoPi_Duo2/zh#.E8.BF.9E.E6.8E.A5WiFi 固件包链接以及烧录工具都在上面链接中 烧录过程 使用读卡器将SD卡插入到电脑,然后打开烧录工具 2.通过串口工具连接板子使其连接WiFi 对应的串口工具,就是这个HyperT…...
Java 内存区域详解
1 常见面试题 1.1 基本问题 介绍下Java内存区域(运行时数据区)Java对象的创建过程(五步,建议能够默写出来并且要知道每一步虚拟机做了什么)对象的访问定位的两种方式(句柄和直接指针两种方式)…...
MyBatis框架详解与核心配置解读
目录 前言 一、MyBatis框架概述 1.1 什么是MyBatis 1.2 MyBatis的优点 二、MyBatis的使用入门与案例 2.1 MyBatis核心配置文件(mybatis-config.xml) 2.2 XML映射文件(UserMapper.xml) 三、MyBatis的常用注解及其用法 3.1…...
Windows 快速搭建C++开发环境,安装C++、CMake、QT、Visual Studio、Setup Factory
安装C 简介 Windows 版的 GCC 有三个选择: CygwinMinGWmingw-w64 Cygwin、MinGW 和 mingw-w64 都是在 Windows 操作系统上运行的工具集,用于在 Windows 环境下进行开发和编译。 Cygwin 是一个在 Windows 上运行的开源项目,旨在提供类Uni…...
GO系列-IO 文件操作
os io 判断文件是否存在 func fileExist(filePath string) (bool, error) {_, err : os.Stat(filePath)if err nil {return true, nil}if os.IsNotExist(err) {return false, nil}return false, &CheckFileExistError{filePath} } 读取文件内容 func readFileContext(…...
Unity Excel导表工具转Lua文件
思路介绍 借助EPPlus读取Excel文件中的配置数据,根据指定的不同类型的数据配置规则来解析成对应的代码文本,将解析出的字符串内容写入到XXX.lua.txt文件中即可 EPPlus常用API //命名空间 using OfficeOpenXml;//Excel文件路径 var fileExcel new File…...
Helix——Figure 02发布通用人形机器人控制的VLA:一组神经网络权重下的快与慢双系统,让两个机器人协作干活
前言 过去一周,我花了很大的心思、力气,把deepseek的GRPO、MLA算法的代码解析通透,比如GRPO与PPO的详细对比,再比如MLA中,图片 公式 代码的一一对应 2.20日晚,无意中刷到figure 02发布Helix的一个演示视频…...
汽车自动驾驶辅助L2++是什么?
自动驾驶辅助级别有哪些? 依照SAE(SAE International,Society of Automotive Engineers国际自动机工程师学会)的标准,大致划分为6级(L0-L5): L0人工驾驶:即没有驾驶辅助…...
进程的介绍--进程状态/切换
1.冯 • 诺依曼体系结构 1.1 体系结构 冯•诺依曼结构也称普林斯顿结构,是一种将程序指令存储器和数据存储器合并在一起的存储器结构。数学家冯•诺依曼提出了计算机制造的三个基本原则,即采用二进制逻辑、程序存储执行以及计算机由五个部分组成&#x…...
goby(蓝队红队版)扫描工具扫描使用时候报错解决方法
1.Goby 是一款开源的网络安全扫描工具,主要用于漏洞扫描、资产发现和信息收集。它旨在帮助安全研究人员、渗透测试人员和红队成员自动化和简化网络漏洞扫描过程。Goby 提供了多种功能,能够在大量的目标中高效地识别出潜在的安全漏洞。 2.今天在官网下载…...
Word文档中插入的图片不能完整显示
在在Word文档中插入图片,只显示图片最下面的一小部分。 将“固定值”更改为“单倍行距”...
模电知识点总结(6)
1.选取频率高于1000Hz的信号时,可选用高通滤波器;抑制50Hz的交流干扰时,可选用带阻滤波器如果希望抑制500Hz以下的信号,可选用高通滤波器。 2.有用信号频率高于1000Hz,可选用高通滤波器;希望抑制50Hz的交流…...
Linux操作系统4-进程间通信4(共享内存原理,创建,查看,命令)
上篇文章:Linux操作系统4-进程间通信3(基于管道的进程池设计)-CSDN博客 本篇Gitee代码:myLerningCode/l24 橘子真甜/Linux操作系统与网络编程学习 - 码云 - 开源中国 (gitee.com) 本篇重点:使用共享内存来实现两个进程…...
Grok 使用指南
文章来源:Grok 漫游指南 | xAI Docs 欢迎!在本指南中,我们将引导您了解使用 xAI API 的基础知识。 #第 1 步:创建 xAI 帐户 您需要一个 xAI 帐户才能访问 xAI API。在此处注册帐户。 创建账户后,您需要为其加载积分…...
使用Ubuntu搭建Java部署环境
White graces:个人主页 🙉专栏推荐:Java入门知识🙉 🐹今日诗词:小舟从此逝,江海寄余生🐹 ⛳️点赞 ☀️收藏⭐️关注💬卑微小博主🙏 ⛳️点赞 ☀️收藏⭐️关注💬卑微小…...
MATLAB学习之旅:从入门到基础实践
在当今科技飞速发展的时代,MATLAB作为一款强大的数学软件,犹如一把神奇的钥匙,能够打开众多领域的大门。无论是工程计算、数据分析,还是算法开发、可视化呈现,MATLAB都展现出了无与伦比的魅力。今天,就让我们踏上这段奇妙的MATLAB学习之旅,从最基础的部分开始,逐步探索…...
蓝桥杯核心内容
核心内容 数学 质数与筛质数,分解质因数 分解质因数 所有的数都可以写成有限个数相乘质数:可以写成1✖本身(如131✖13)合数:ab1✖...✖bn-》把乘数里面是合数的再分(如b3是合数-》b3c1✖c2)进…...
C/C++ | 每日一练 (2)
💢欢迎来到张胤尘的技术站 💥技术如江河,汇聚众志成。代码似星辰,照亮行征程。开源精神长,传承永不忘。携手共前行,未来更辉煌💥 文章目录 C/C | 每日一练 (2)题目参考答案封装继承多态虚函数底…...
金融时间序列【量化理论】
业界常用的技术分析指标都与价格本身有关,而时间序列分析由于对数据平稳性的要求常常是基于收益率这样更加偏稳定的数据(收益率由于会涨停和跌停每天最多10%) 平稳性: 强平稳性:随时间变化,各个统计特征都…...
未来AI方向落地场景:小语言模型,super_private_agent
未来AI方向落地场景:小语言模型,super_private_agent 目录 未来AI方向落地场景:小语言模型,super_private_agent小语言模型super - private - agent(注重隐私的智能代理)碳基生命和硅基生命交互界面面向agent的专用交互协议和数据接口从web平台经济到网络平台举例说明社交…...
快速入门——第三方组件element-ui
学习自哔哩哔哩上的“刘老师教编程”,具体学习的网站为:10.第三方组件element-ui_哔哩哔哩_bilibili,以下是看课后做的笔记,仅供参考。 第一节 组件间的传值 组件可以有内部Data提供数据,也可由父组件通过prop方式传…...
