SpringCloud-快速通关(一)
本文是基于【雷丰阳老师:尚硅谷2025最新SpringCloud - 快速通关】进行实践操作,并对雷神的笔记做一个更详细的补充,供大家学习参考,一起加油!
视频地址:SpringCloud快速通关_教程简介_哔哩哔哩_bilibili
笔记链接:3. SpringCloud - 快速通关
资料:资料.zip(代码+课件+逻辑图)
SpringCloud-快速通关(一)
- 一、分布式基础
- 1.1、微服务
- 1.2、集群&分布式&节点
- 1.3、远程调用
- 1.4、负载均衡
- 1.5、服务注册/发现&注册中心
- 1.6、配置中心
- 1.7、服务熔断&服务降级
- 1.8、API 网关
- 二、Spring Cloud
- 2.1、简介
- 2.2、技术配置
- 2.3、版本
- 2.4、实践
- 2.4.1、建springcloud-demo项目
- 2.4.2、导依赖
- 2.4.3、建services模块
- 2.4.4、建service-order/product模块
- 三、Nacos - 注册/配置中心
- 3.1、基础入门
- 3.2、注册中心
- 3.2.1、依赖引入
- 3.2.2、整合配置
- 3.2.3、服务注册
- 3.2.4、服务发现
- 3.2.5、远程调用
- 3.2.6、负载均衡
- 3.3、配置中心
- 3.3.1、整合配置
- 3.3.2、动态刷新
- 3.3.3、NacosConfigManager 监听配置变化
- 3.3.4、数据隔离
- 3.4、小结
一、分布式基础
1.1、微服务
微服务架构风格,就像是把一个单独的应用程序开发为一套小服务,每个小服务运行在自己的进程中,并使用轻量级机制通信,通常是 HTTP API。这些服务围绕业务能力来构建, 并通过完全自动化部署机制来独立部署。这些服务使用不同的编程语言书写,以及不同数据存储技术,并保持最低限度的集中式管理。
简而言之:拒绝大型单体应用,基于业务边界进行服务微化拆分,各个服务独立部署运行。
1.2、集群&分布式&节点
集群是个物理形态,分布式是个工作方式。
只要是一堆机器,就可以叫集群,他们是不是一起协作着干活,这个谁也不知道;
《分布式系统原理与范型》定义:
- “分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”
- 分布式系统(distributed system)是建立在网络之上的软件系统。
分布式是指将不同的业务分布在不同的地方。
集群指的是将几台服务器集中在一起,实现同一业务。
例如:京东是一个分布式系统,众多业务运行在不同的机器,所有业务构成一个大型的业务集群。每一个小的业务,比如用户系统,访问压力大的时候一台服务器是不够的。我们就应该将用户系统部署到多个服务器,也就是每一个业务系统也可以做集群化;
分布式中的每一个节点,都可以做集群。 而集群并不一定就是分布式的。
节点:集群中的一个服务器
1.3、远程调用
在分布式系统中,各个服务可能处于不同主机,但是服务之间不可避免的需要互相调用,我们称为远程调用。 SpringCloud 中使用 HTTP+JSON
的方式完成远程调用
1.4、负载均衡
分布式系统中,A 服务需要调用 B 服务,B 服务在多台机器中都存在,A 调用任意一个服务器均可完成功能。 为了使每一个服务器都不要太忙或者太闲,我们可以负载均衡的调用每一个服务器,提升网站的健壮性。
常见的负载均衡算法:
- 轮询:为第一个请求选择健康池中的第一个后端服务器,然后按顺序往后依次选择,直到最后一个,然后循环。
- 最小连接:优先选择连接数最少,也就是压力最小的后端服务器,在会话较长的情况下可以考虑采取这种方式。
- 散列:根据请求源的 IP 的散列(hash)来选择要转发的服务器。这种方式可以一定程度上保证特定用户能连接到相同的服务器。如果你的应用需要处理状态而要求用户能连接到和之前相同的服务器,可以考虑采取这种方式。
1.5、服务注册/发现&注册中心
A 服务调用 B 服务,A 服务并不知道 B 服务当前在哪几台服务器有,哪些正常的,哪些服务已经下线。解决这个问题可以引入注册中心;
如果某些服务下线,我们其他人可以实时的感知到其他服务的状态,从而避免调用不可用的服务。
1.6、配置中心
每一个服务最终都有大量的配置,并且每个服务都可能部署在多台机器上。我们经常需要变更配置,我们可以让每个服务在配置中心获取自己的配置。
配置中心用来集中管理微服务的配置信息
1.7、服务熔断&服务降级
在微服务架构中,微服务之间通过网络进行通信,存在相互依赖,当其中一个服务不可用时,有可能会造成雪崩效应。要防止这样的情况,必须要有容错机制来保护服务。
1)、服务熔断
设置服务的超时,当被调用的服务经常失败到达某个阈值,我们可以开启断路保护机制,后来的请求不再去调用这个服务。本地直接返回默认的数据
2)、服务降级
在运维期间,当系统处于高峰期,系统资源紧张,我们可以让非核心业务降级运行。降级:某些服务不处理,或者简单处理【抛异常、返回 NULL、调用 Mock 数据、调用 Fallback 处理逻辑】
1.8、API 网关
在微服务架构中,API Gateway 作为整体架构的重要组件,它抽象了微服务中都需要的公共功能,同时提供了客户端负载均衡,服务自动熔断,灰度发布,统一认证,限流流控,日志统计等丰富的功能,帮助我们解决很多 API 管理难题。
二、Spring Cloud
2.1、简介
Spring Cloud是分布式系统一站式解决方案。
什么是分布式系统?
架构分:单体和分布式。集群只是一种物理形态,分布式是工作方式。
架构演进 | 单体架构 | 集群架构 | 分布式架构 |
---|---|---|---|
定义 | 所有功能模块都在一个项目里 | 单体的多服务器版本 | 一个大型应用被拆分成很多小应用分布部署在各个机器; |
优点 | 开发部署简单 | 解决大并发 | 解决了单体+集群的问题 |
缺点 | 无法应对高并发 | 问题1:模块块升级 麻烦 问题2:多语言团队 交互不通 |
基于自己的理解:分布式架构(模拟用户访问)
- 通过网关来发送各个微服务的请求(请求路由)。用
gateway
。网关需要对请求进行分发,所以要注册到注册中心。 - 将各微服务布置到各服务器,即微服务(自治) 独立部署、数据隔离、语言无关,将不同模块部署到多个服务器,每个模块都要有副本服务器。不能让每个模块只部署到一个服务器,会出现单点故障问题:如果这个服务器崩了,那应用就不能提供完整服务了
- 如果模块跨服务器之间调用会遇到什么问题?远程调用RPC。如果远程调用怎么让应用知道调用哪个服务器的微服务。此时就需要用到nacos注册中心和配置中心,注册中心有两个功能:服务注册(监控服务上下线)和服务发现(远程调用之前要发现对方在哪)。配置中心:统一管理配置文件+推送配置的变更。
Nacos+OpenFeign
- 如果模块之间调用失败导致服务调用链整体阻塞甚至雪崩,怎么办?服务熔断(快速失败机制),及时释放资源,防止资源耗尽。
Sentinal
- 如果有一个操作需要多个数据库合作,而不同数据库部署在不同服务器,这就需要用到分布式事务。
Seata
2.2、技术配置
Spring Cloud 系列:
- 官网:https://spring.io/projects/spring-cloud
- 远程调用:OpenFeign
- 网关:Gateway
Spring Cloud Alibaba 系列:
- 官网:https://sca.aliyun.com/
- 注册中心/配置中心:Nacos
- 服务保护:Sentinel
- 分布式事务:Seata
2.3、版本
2.4、实践
2.4.1、建springcloud-demo项目
先用手脚架快速搭建框架
2.4.2、导依赖
pom父模块
注意:springboot, springcloud, springcloud-alibaba的版本
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.3.4</version><relativePath/> <!-- lookup parent from repository --></parent><modelVersion>4.0.0</modelVersion><groupId>com.atguigu</groupId><artifactId>spring-cloud-demo</artifactId><version>1.0-SNAPSHOT</version><packaging>pom</packaging><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring-cloud.version>2023.0.3</spring-cloud.version><spring-cloud-alibaba.version>2023.0.3.2</spring-cloud-alibaba.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><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></dependencies></dependencyManagement></project>
2.4.3、建services模块
services模块作为管理所有service-xxx 模块的父模块
导入依赖,在service中导入nacos-discovery
依赖
<dependencies><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency>
</dependencies>
2.4.4、建service-order/product模块
注意父模块是services
三、Nacos - 注册/配置中心
3.1、基础入门
官网:https://nacos.io/zh-cn/docs/v2/quickstart/quick-start.html
Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
下载nacos的服务端:nacos server 账号密码都是nacos
安装:
-
Docker 安装
docker run -d -p 8848:8848 -p 9848:9848 -e MODE=standalone --name nacos nacos/nacos-server:v2.4.3
-
下载软件包:nacos-server-2.4.3.zip
-
启动:
startup.cmd -m standalone
-
启动成功
3.2、注册中心
3.2.1、依赖引入
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
3.2.2、整合配置
1、在 application.properties
中配置如下
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848#暂未用到配置中心功能,需要关闭配置检查
#spring.cloud.nacos.config.import-check.enabled=false
2、开启服务注册/发现功能
@EnableDiscoveryClient //核心注解
@SpringBootApplication
public class OrderMainApplication {public static void main(String[] args) {SpringApplication.run(OrderMainApplication.class, args);}}
3.2.3、服务注册
作用:将微服务注册到nacos中进行统一管理
service-order, service-product都加依赖
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
</dependencies>
service-order模块
application.properties
server.port=8000
spring.application.name=service-order
spring.cloud.nacos.server-addr=127.0.0.1:8848
- 启动类
@SpringBootApplication
public class OrderMainApplication {public static void main(String[] args) {SpringApplication.run(OrderMainApplication.class, args);}
}
service-product模块
application.properties
server.port=9000
spring.application.name=service-product
spring.cloud.nacos.server-addr=127.0.0.1:8848
- 启动类
@SpringBootApplication
public class ProductMainApplication {public static void main(String[] args) {SpringApplication.run(ProductMainApplication.class, args);}
}
效果
查看效果
访问:http://localhost:8848/nacos
可以看到服务已经注册上来;
启动集群
例如:service-order启动两个,service-product启动3个
-
order端口:8000/8001
-
product端口:9000/9001/9002
3.2.4、服务发现
服务发现的作用是:服务间的远程调用通过nacos发现对方的服务,然后进行调用,后续不用手动调,这里只要加上注解,两个API作为了解。
- 启动类加注解
@EnableDiscoveryClient
@EnableDiscoveryClient
@SpringBootApplication
public class ProductMainApplication {public static void main(String[] args) {SpringApplication.run(ProductMainApplication.class, args);}
}
- 测试类:测试类的包和启动类的包保持一致
@SpringBootTest
public class ProductApplicationTest {@AutowiredDiscoveryClient discoveryClient;@AutowiredNacosDiscoveryClient nacosDiscoveryClient;//二者效果一样,这个依赖nacos@Testpublic void discoveryClientTest(){List<String> services = discoveryClient.getServices();for (String service : services) {System.out.println("service = " + service);List<ServiceInstance> instances = discoveryClient.getInstances(service);for (ServiceInstance instance : instances) {System.out.println("instance.getHost() = " + instance.getHost());System.out.println("instance.getPort() = " + instance.getPort());}}}@Testpublic void nacosDiscoveryClientTest(){List<String> services = nacosDiscoveryClient.getServices();for (String service : services) {System.out.println("service = " + service);List<ServiceInstance> instances = nacosDiscoveryClient.getInstances(service);for (ServiceInstance instance : instances) {System.out.println("instance.getHost() = " + instance.getHost());System.out.println("instance.getPort() = " + instance.getPort());}}}
}
3.2.5、远程调用
-
新建model模块和services模块平级,实体类的统一管理
-
导入依赖
<dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><scope>annotationProcessor</scope></dependency> </dependencies>
-
实体类:com.atguigu.bean
@Data public class Order {private Long id;private BigDecimal totalAmount;private Long userId;private String nickName;private String address;private List<Product> productList; }
@Data public class Product {private Long id;private BigDecimal price;private String productName;private int num; }
-
在services的pom文件中导入model,就可以用了
<dependency><groupId>com.atguigu</groupId><artifactId>model</artifactId><version>1.0-SNAPSHOT</version> </dependency>
回到service业务类
- service-product
-
controller
@RestController public class ProductController {@AutowiredProductService productService;@GetMapping(value = "/productId/{id}")public Product getProductById(@PathVariable("id") Long productId) {Product product = productService.getProductById(productId);return product;} }
-
service
public interface ProductService {Product getProductById(Long productId); }
@Service public class ProductServiceImpl implements ProductService {@Overridepublic Product getProductById(Long productId) {Product product = new Product();product.setId(productId);product.setPrice(new BigDecimal("99"));product.setProductName("苹果-" + productId);product.setNum(11);return product;} }
-
测试:http://localhost:9000/product/2
-
- service-order
- controller
@RestController public class OrderController {@AutowiredOrderService orderService;@GetMapping(value = "/create")public Order createOrder(@RequestParam("userId") Long userId, @RequestParam("productId") Long productId) {Order order = orderService.createOrder(userId, productId);return order;} }
- service
public interface OrderService {Order createOrder(Long userId, Long productId); }
- 此处需要对service-product服务进行远程调用,稍后处理,先测试
@Service public class OrderServiceImpl implements OrderService {@Overridepublic Order createOrder(Long userId, Long productId) {Order order = new Order();order.setId(1L);//TODO 总金额order.setTotalAmount(new BigDecimal("0"));order.setUserId(userId);order.setNickName("张三");order.setAddress("火星");//TODO 远程查询商品列表order.setProductList(null);return order;} }
- 可以自动生成getter/setter方法的IDEA插件
- 测试:http://localhost:8000/create?userId=2&productId=23
- controller
完善业务类中远程调用
- service-order
- config:将RestTemplate加入到spring容器
@Configuration public class OrderConfig {@Beanpublic RestTemplate restTemplate() {return new RestTemplate();} }
- service
@Service @Slf4j public class OrderServiceImpl implements OrderService {@AutowiredDiscoveryClient discoveryClient;@AutowiredRestTemplate restTemplate;@Overridepublic Order createOrder(Long userId, Long productId) {Product product = getProductFromRemote(productId);Order order = new Order();order.setId(1L);// 总金额=价格*数量BigDecimal price = product.getPrice();//价格int num = product.getNum();//数量order.setTotalAmount(price.multiply(new BigDecimal(num)));//总价order.setUserId(userId);order.setNickName("张三");order.setAddress("火星");// 远程查询商品列表order.setProductList(Arrays.asList(product));return order;}//远程调用获取商品信息public Product getProductFromRemote(Long productId) {//1、获取到商品服务所在的所有机器IP+portList<ServiceInstance> instances = discoveryClient.getInstances("service-product");ServiceInstance instance = instances.get(0);//远程URLString url = "http://" + instance.getHost() + ":" + instance.getPort() + "/productId/" + productId;log.info("远程请求:{}", url);//2、给远程发送请求Product product = restTemplate.getForObject(url, Product.class);return product;} }
- 测试:http://localhost:8000/create?userId=2&productId=23
- config:将RestTemplate加入到spring容器
3.2.6、负载均衡
1、使用 LoadBalancerClient
-
在services模块加入依赖
<!--负载均衡--> <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId> </dependency>
-
测试
前提:只能负载均衡注册到nacos的服务@SpringBootTest public class OrderApplicationTest {@AutowiredLoadBalancerClient loadBalancerClient;@Testpublic void test() {ServiceInstance choose = loadBalancerClient.choose("service-product");System.out.println("choose.getHost()+choose.getPort() = " + choose.getHost() + ":" + choose.getPort());choose = loadBalancerClient.choose("service-product");System.out.println("choose.getHost()+choose.getPort() = " + choose.getHost() + ":" + choose.getPort());choose = loadBalancerClient.choose("service-product");System.out.println("choose.getHost()+choose.getPort() = " + choose.getHost() + ":" + choose.getPort());choose = loadBalancerClient.choose("service-product");System.out.println("choose.getHost()+choose.getPort() = " + choose.getHost() + ":" + choose.getPort());choose = loadBalancerClient.choose("service-product");System.out.println("choose.getHost()+choose.getPort() = " + choose.getHost() + ":" + choose.getPort());} }
-
效果
-
改造service-order 的
OrderServiceImpl
的远程调用product服务的方法@Service @Slf4j public class OrderServiceImpl implements OrderService {@AutowiredDiscoveryClient discoveryClient;@AutowiredRestTemplate restTemplate;@AutowiredLoadBalancerClient loadBalancerClient;@Overridepublic Order createOrder(Long userId, Long productId) {// Product product = this.getProductFromRemote(productId);Product product = this.getProductFromRemoteWithLoadBalance(productId);Order order = new Order();order.setId(1L);// 总金额=价格*数量BigDecimal price = product.getPrice();//价格int num = product.getNum();//数量order.setTotalAmount(price.multiply(new BigDecimal(num)));//总价order.setUserId(userId);order.setNickName("张三");order.setAddress("火星");// 远程查询商品列表order.setProductList(Arrays.asList(product));return order;}//阶段二:加入负载均衡public Product getProductFromRemoteWithLoadBalance(Long productId) {//1、获取到商品服务所在的所有机器IP+portServiceInstance choose = loadBalancerClient.choose("service-product");//远程URLString url = "http://" + choose.getHost() + ":" + choose.getPort() + "/productId/" + productId;log.info("远程请求:{}", url);//2、给远程发送请求Product product = restTemplate.getForObject(url, Product.class);return product;}//远程调用获取商品信息public Product getProductFromRemote(Long productId) {//1、获取到商品服务所在的所有机器IP+portList<ServiceInstance> instances = discoveryClient.getInstances("service-product");ServiceInstance instance = instances.get(0);//远程URLString url = "http://" + instance.getHost() + ":" + instance.getPort() + "/productId/" + productId;log.info("远程请求:{}", url);//2、给远程发送请求Product product = restTemplate.getForObject(url, Product.class);return product;} }
-
效果
2、使用@LoadBalanced
注解
-
config
@Configuration public class OrderConfig {@LoadBalanced //基于注解式的负载均衡@Beanpublic RestTemplate restTemplate() {return new RestTemplate();} }
-
ProductController
@RestController public class ProductController {@AutowiredProductService productService;@GetMapping(value = "/productId/{id}")public Product getProductById(@PathVariable("id") Long productId) {System.out.println("正在远程调用service-product...");Product product = productService.getProductById(productId);return product;} }
-
OrderServiceImpl
@Service @Slf4j public class OrderServiceImpl implements OrderService {@AutowiredDiscoveryClient discoveryClient;@AutowiredRestTemplate restTemplate;@AutowiredLoadBalancerClient loadBalancerClient;@Overridepublic Order createOrder(Long userId, Long productId) {// Product product = this.getProductFromRemote(productId);// Product product = this.getProductFromRemoteWithLoadBalance(productId);Product product = this.getProductFromRemoteWithLoadBalanceAnnotation(productId);Order order = new Order();order.setId(1L);// 总金额=价格*数量BigDecimal price = product.getPrice();//价格int num = product.getNum();//数量order.setTotalAmount(price.multiply(new BigDecimal(num)));//总价order.setUserId(userId);order.setNickName("张三");order.setAddress("火星");// 远程查询商品列表order.setProductList(Arrays.asList(product));return order;}//阶段三:于注解的负载均衡public Product getProductFromRemoteWithLoadBalanceAnnotation(Long productId) {//给远程发送请求;;service-product会被动态替换String url = "http://service-product/productId/" + productId;Product product = restTemplate.getForObject(url, Product.class);return product;}//阶段二:加入负载均衡public Product getProductFromRemoteWithLoadBalance(Long productId) {//1、获取到商品服务所在的所有机器IP+portServiceInstance choose = loadBalancerClient.choose("service-product");//远程URLString url = "http://" + choose.getHost() + ":" + choose.getPort() + "/productId/" + productId;log.info("远程请求:{}", url);//2、给远程发送请求Product product = restTemplate.getForObject(url, Product.class);return product;}//远程调用获取商品信息public Product getProductFromRemote(Long productId) {//1、获取到商品服务所在的所有机器IP+portList<ServiceInstance> instances = discoveryClient.getInstances("service-product");ServiceInstance instance = instances.get(0);//远程URLString url = "http://" + instance.getHost() + ":" + instance.getPort() + "/productId/" + productId;log.info("远程请求:{}", url);//2、给远程发送请求Product product = restTemplate.getForObject(url, Product.class);return product;} }
-
效果:http://localhost:8000/create?userId=2&productId=23
分别在各个service-product打印
思考:注册中心宕机,远程调用还能成功吗?
可以进行实验
实验一:五个服务启动,在nacos中有注册,但是没有执行http://localhost:8000/create?userId=2&productId=23测试,也就是没有经过远程调用,然后将nacos关闭,再调用请求测试
结论:不能调用,因为远程调用由于nacos宕机找不到地址
实验一:五个服务启动,在nacos中有注册,但是执行http://localhost:8000/create?userId=2&productId=23测试,已经经过远程调用,然后将nacos关闭,再调用请求测试
结论:可以调用,因为缓存中有地址。但如果对方服务宕机则也调不通。
原理
第一次远程调用要经过两个步骤:1.拿到nacos服务地址列表 2.给对方服务的某个地址发送请求。
第二次及后续:就会将步骤1省略,已经将地址列表放到缓存中了,即使nacos宕机也能远程调用,并且能负载均衡。
小结
- 使用 RestTemplate 可以获取到远程数据
- 必须精确指定地址和端口
- 如果远程宕机将不可用
3.3、配置中心
3.3.1、整合配置
-
services导入依赖
<!--配置中心--> <dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>
-
service-order的配置文件application.properties
导入了配置中心的依赖但是没设置(用到)配置中心就会报错,解决办法,关闭自动检查
server.port=8000 spring.application.name=service-order spring.cloud.nacos.server-addr=127.0.0.1:8848 spring.config.import=nacos:service-order.properties #暂未用到配置中心功能,需要关闭配置检查 spring.cloud.nacos.config.import-check.enabled=false
service-product
spring.application.name=service-product spring.cloud.nacos.server-addr=127.0.0.1:8848 #暂未用到配置中心功能,需要关闭配置检查 spring.cloud.nacos.config.import-check.enabled=false
-
在nacos服务端进行配置
代码测试 order: controller@RestController public class OrderController {@AutowiredOrderService orderService;@Value("${order.timeout}")String orderTimeout;@Value("${order.auto-confirm}")String orderAutoConfirm;@GetMapping("/config")public String getConfig() {return "OrderTimeout+OrderAutoConfirm = " + orderTimeout+" : " + orderAutoConfirm;}@GetMapping(value = "/create")public Order createOrder(@RequestParam("userId") Long userId, @RequestParam("productId") Long productId) {Order order = orderService.createOrder(userId, productId);return order;} }
3.3.2、动态刷新
-
@Value(“${xx}”)
获取配置 +@RefreshScope
实现自动刷新但是会产生一个问题:nacos配置中修改后,不重启服务,发请求不能自动更新修改后的数据
实时更新配置显示的办法:在@RestController
上加@RefreshScope
即可@RefreshScope//自动刷新 @RestController public class OrderController {@AutowiredOrderService orderService;@Value("${order.timeout}")String orderTimeout;@Value("${order.auto-confirm}")String orderAutoConfirm;@AutowiredOrderProperties orderProperties;@GetMapping("/config")public String config(){return "order.timeout="+orderProperties.getTimeout()+"; " +"order.auto-confirm="+orderProperties.getAutoConfirm() +";"+"order.db-url="+orderProperties.getDbUrl();} }
-
@ConfigurationProperties
无感自动刷新无需 @RefreshScope,自动绑定配置,动态更新
加com.atguigu.order.properties.OrderProperties
@Component @ConfigurationProperties(value = "order")//配置批量绑定在nacos下,可以无需@RefreshScope就能实现自动刷新 @Data public class OrderProperties {String timeout;String autoConfirm; }
service-order: controller
//@RefreshScope @RestController public class OrderController {@AutowiredOrderService orderService;// @Value("${order.timeout}")// String orderTimeout;// @Value("${order.auto-confirm}")// String orderAutoConfirm;@AutowiredOrderProperties orderProperties;@GetMapping("/config")public String getConfig() {return "OrderTimeout+OrderAutoConfirm = " + orderProperties.getTimeout() + " : " + orderProperties.getAutoConfirm();}@GetMapping(value = "/create")public Order createOrder(@RequestParam("userId") Long userId, @RequestParam("productId") Long productId) {Order order = orderService.createOrder(userId, productId);return order;} }
3.3.3、NacosConfigManager 监听配置变化
在启动类中添加ApplicationRunner
实例,是一个一次性任务,项目启动他就会执行
@SpringBootApplication
public class OrderMainApplication {public static void main(String[] args) {SpringApplication.run(OrderMainApplication.class, args);}//1、项目启动就监听配置文件变化//2、发生变化后拿到变化值//3、发送邮件@BeanApplicationRunner applicationRunner(NacosConfigManager nacosConfigManager) {
// return new ApplicationRunner() {
// @Override
// public void run(ApplicationArguments args) throws Exception {
//
// }
// }return args -> {//这个监听的服务和application.yml中naocs的配置中心有关ConfigService configService = nacosConfigManager.getConfigService();configService.addListener("service-order.properties", "DEFAULT_GROUP", new Listener() {@Overridepublic Executor getExecutor() {return Executors.newFixedThreadPool(4);}@Overridepublic void receiveConfigInfo(String s) {System.out.println("变化的配置信息:" + s);System.out.println("邮件通知....");}});System.out.println("=========");};}
}
测试效果
思考: Nacos中的数据集 和 application.properties 有相同的 配置项,哪个生效?
以配置中心为准,不然要配置中心干什么
3.3.4、数据隔离
作用:配置中心基于项目激活哪个环境标识,动态指定名称空间,动态加载指定文件和配置
推荐用法
创建几个namespace和Group等方便测试
按需加载,设置application.yml
配置文件,将application.properties
注释掉
server:port: 8000
spring:profiles:active: prodapplication:name: service-ordercloud:nacos:server-addr: 127.0.0.1:8848config:import-check:enabled: falsenamespace: ${spring.profiles.active:public}---
spring:config:import:- nacos:common.properties?group=order- nacos:database.properties?group=orderactivate:on-profile: dev---
spring:config:import:- nacos:common.properties?group=order- nacos:database.properties?group=order- nacos:haha.properties?group=orderactivate:on-profile: test---
spring:config:import:- nacos:common.properties?group=order- nacos:database.properties?group=order- nacos:hehe.properties?group=orderactivate:on-profile: prod
代码层面
OrderProperties
@Component
@ConfigurationProperties(value = "order")//配置批量绑定在nacos下,可以无需@RefreshScope就能实现自动刷新
@Data
public class OrderProperties {String timeout;String autoConfirm;String dbUrl;
}
OrderController
//@RefreshScope
@RestController
public class OrderController {@AutowiredOrderService orderService;
// @Value("${order.timeout}")
// String orderTimeout;
// @Value("${order.auto-confirm}")
// String orderAutoConfirm;@AutowiredOrderProperties orderProperties;@GetMapping("/config")public String getConfig() {return orderProperties.getTimeout() + " : " + orderProperties.getAutoConfirm() + " : " + orderProperties.getDbUrl();}@GetMapping(value = "/create")public Order createOrder(@RequestParam("userId") Long userId, @RequestParam("productId") Long productId) {Order order = orderService.createOrder(userId, productId);return order;}
}
测试效果
3.4、小结
- 多环境(public, dev, test, prod)=》用namespace管理
- 多服务(order, product)=》group
- 多配置(xxx.properties)=》具体xxx.properties
- 多配置项
参考链接:
https://blog.csdn.net/weixin_56884174/article/details/145573890
https://www.yuque.com/leifengyang/sutong/oz4gbyh5maa0rmxu#tHTwd
相关文章:
SpringCloud-快速通关(一)
本文是基于【雷丰阳老师:尚硅谷2025最新SpringCloud - 快速通关】进行实践操作,并对雷神的笔记做一个更详细的补充,供大家学习参考,一起加油! 视频地址:SpringCloud快速通关_教程简介_哔哩哔哩_bilibili …...
Ansible Playbook详解:自动化配置管理的核心
1. 引言 Ansible Playbook是Ansible自动化系统的核心,它使用YAML格式描述一系列要在远程系统上执行的任务。通过Playbook,我们可以将复杂的IT操作转化为可重复、可版本控制的代码。本文将深入探讨Playbook的结构、语法和高级特性,帮助读者掌握编写高效、可维护的Playbook的…...
【实践总结】如何编写“多角色适配”的高质量技术文档?
一份文档想要“一稿多用”?先别急着开写!先读完这篇总结,你将学会如何拆解目标、设计结构、提升可读性,让文档不再顾此失彼。 🔍 背景:一文多用,常常适得其反 在实际的软件项目中,我们往往希望通过一份设计文档,同时完成以下多个目标: ✅ 描述系统结构,便于团队成…...
Ansible 入门教程:从零开始掌握自动化运维
1. 引言 在当今快速发展的IT环境中,自动化运维已成为提高效率、减少人为错误的关键。Ansible作为一个简单yet强大的自动化工具,正受到越来越多DevOps工程师的青睐。本文将带领读者从零开始,逐步掌握Ansible的核心概念和基本用法,为自动化运维之路打下坚实基础。 2. Ansible简…...
WSL2迁移教程:如何备份和转移Ubuntu子系统到新位置
WSL2迁移教程:如何备份和转移Ubuntu子系统到新位置 文章目录 WSL2迁移教程:如何备份和转移Ubuntu子系统到新位置前言环境准备迁移步骤详解1. 查看当前WSL发行版状态2. 关闭所有WSL实例3. 导出WSL发行版4. 注销原有WSL发行版5. 导入WSL发行版到新位置6. 验…...
【备赛】eeprom
简介 EEPROM即电可擦可编程只读存储器,属于非易失存储芯片。 它能电擦除、多次编程,支持字节级操作。 掉电后数据不丢失。 蓝桥杯嵌入式的eeprom使用AT24C02,使用IIC通信协议。 驱动的函数官方已经写好,我们只需要移植并使用就…...
Pytorch torch.utils.data.dataloader.default_collate 介绍
torch.utils.data.dataloader.default_collate 是 PyTorch 中 DataLoader 默认的 collate_fn 函数,用于将一个批次的样本数据合并成张量(Tensor)或其他结构化数据格式。以下是关于 default_collate 的详细介绍: 1. 功能 default…...
Github最新AI工具汇总2025年4月份第2周
根据GitHub官方动态及开发者生态最新进展,以下是2025年4月第二周(截至4月7日)值得关注的AI工具与技术更新汇总: 1. GitHub Copilot Agent Mode全量发布 核心功能:在VS Code中启用Agent模式后,Copilot可自主…...
2013年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析
2013年-全国大学生数学建模竞赛(CUMCM)试题速浏、分类及浅析 全国大学生数学建模竞赛(China Undergraduate Mathematical Contest in Modeling)是国家教委高教司和中国工业与应用数学学会共同主办的面向全国大学生的群众性科技活动,目的在于激励学生学习数学的积极性,提高学…...
LabVIEW 开发如何降本增效
在 LabVIEW 开发领域,如何在确保项目质量的同时降低开发成本,是众多企业和开发者共同关注的焦点。这不仅关乎资源的高效利用,更影响项目的投资回报率和市场竞争力。下面,我们将从多个维度深入剖析降本策略,并结合具体案…...
云存储服务器的作用都有哪些?
云存储服务器是一种用来存储和管理企业数据信息的服务器,可以为企业与组织提供一个可靠、安全和可扩展的存储平台,能够帮助个人和企业将数据信息存储在云端,以此来实现数据信息的备份、共享和访问功能。 云存储服务器支持多个用户共同访问和共…...
可编辑33页PPT | AI智能智慧工厂厂区完全整体解决方案
荐言摘要:AI智能智慧工厂厂区完全整体解决方案是一种集成了先进的人工智能技术、工业自动化系统和创新管理理念的综合性方案,旨在提升生产效率、降低成本、实现灵活生产,并推动工厂的智能化发展。 随着技术的不断进步,工厂架构经…...
vmware虚拟机上Ubuntu或者其他系统无法联网的解决方法
一、检查虚拟机是否开启了网络服务 打开方式:控制面板->-管理工具--->服务 查找 VMware DHCP Service 和VMware NAT Service ,确保这两个服务已经启动。如下图,没有启动就点击启动。 二、设置网络类型 我们一般使用前两种多一些&…...
python中pyside6多个py文件生成exe
网上见到的教程大多数都是pyinstaller安装单个py文件,针对多个py文件的打包,鲜有人提及;有也是部分全而多的解释,让人目不暇接,本次记录自己设置一个声波捕捉界面的打包过程。 1.pycharm中调用pyinstaller打包 参考链接:https://blog.csdn.net/weixin_45793544/articl…...
P1006 [NOIP 2008 提高组] 传纸条 题解
题目传送门 前言 每次准备摸鱼时都在这道题的界面。 今天有空做做,顺便写一波题解,毕竟估值蹭蹭往下跳。 双倍经验:P1004 [NOIP 2000 提高组] 方格取数,P1006 [NOIP 2008 提高组] 传纸条。 题意简述 现有一个 m m m 行 n …...
linux下编译Websocketpp,适用x86和armv8
编译boost库 下载源文件:Version 1.79.0 编译: sudo ./bootstrap.sh sudo ./b2 install 安装websocketpp git clone https://github.com/zaphoyd/websocketpp.git cd websocketpp #进入目录 mkdir build cd build cmake .. make sudo make ins…...
skynet.dispatch 使用详解
目录 skynet.dispatch 函数详解1. 函数定义与参数2. 消息处理流程3. 使用示例示例 1:处理 Lua 协议消息示例 2:处理自定义协议消息 4. 关键机制(1) 协程与阻塞操作(2) 消息响应 5. 与 skynet.register_protocol 的协作6. 注意事项7. 典型应用场景 总结 s…...
CondaError: Run ‘conda init‘ before ‘conda activate‘
CondaError: Run conda init before conda activate,表明 Conda 环境未正确初始化,导致无法激活目标环境。以下是具体解决方案: 1. 初始化 Conda Conda 需要先初始化才能使用 activate 命令。根据Linux系统,运行以下命令初始化 B…...
从代码学习深度学习 - 序列到序列学习数据预处理 PyTorch 版
文章目录 前言一、数据读取二、文本预处理三、词元化四、构建词表五、截断和填充六、转换为张量七、数据迭代器总结前言 在深度学习领域,序列到序列(Seq2Seq)模型是一种非常重要的架构,广泛应用于机器翻译、文本摘要和对话生成等任务。在实现 Seq2Seq 模型时,数据的预处理…...
SQL:Primary Key(主键)和Foreign Key(外键)
目录 1. Key(键) 2. Index(索引) 3.Key和Index的区别 4. Primary Key(主键) 5. Foreign Key(外键) 6.主键和外键的关系 温馨提示: 闪电按钮不同的执行功能 首先&…...
ClickHouse接入prometheus监控
ClickHouse接入prometheus监控 在 ClickHouse 集群环境下(假设你有 3 台服务器),使用自带的 Prometheus 端点来监控是完全可行的。集群部署意味着你需要为每台服务器配置 Prometheus 端点,并确保 Prometheus 能够从所有节点采集数…...
轻量级UDP流量重放工具的技术实现与场景应用(C/C++代码实现)
在网络协议测试、安全攻防演练、性能调优等领域,精确控制数据包传输行为是核心需求。udp_replay作为一款专注于UDP流量的开源工具,通过简洁的设计实现了对pcap文件中UDP数据流的灵活重放。本文将从技术实现原理、核心功能亮点及典型应用场景三个维度展开…...
时序数据库 TDengine × Excel:一份数据,两种效率
在日常工作中,很多人都离不开 Excel。不论是设备运维工程师、数据分析师,还是业务人员,一份熟悉的电子表格往往就是他们的“第一张报表”。 现在,TDengine 也可以与 Excel 实现无缝连接,用户可以直接在 Excel 中查询时…...
video自动播放
文章目录 前言在iOS系统中,H5页面的自动播放功能受到了一些限制,为了提升用户体验和保护用户隐私,Safari浏览器对于自动播放的行为做了一些限制。 一、自动播放的限制二、解决方案 前言 在iOS系统中,H5页面的自动播放功能受到了一…...
如何利用AI智能生成PPT,提升工作效率与创意表现
如何利用AI智能生成PPT,提升工作效率与创意表现!在这个信息爆炸的时代,制作一份既专业又富有创意的PPT,已经不再是一个简单的任务。尤其是对于每天都需要做报告、做展示的职场人士来说,PPT的质量直接影响着工作效率和个…...
Java8+Spring Boot + Vue + Langchain4j 实现阿里云百炼平台 AI 流式对话对接
1. 引言 在本文中,我们将介绍如何使用 Spring Boot、Vue.js 和 Langchain4j,实现与 阿里云百炼平台 的 AI 流式对话对接。通过结合这些技术,我们将创建一个能够实时互动的 AI 聊天应用。 这是一个基于 Spring Boot Vue.js Langchain4j 的智…...
【scikit-learn基础】--『数据加载』之外部数据集
这是scikit-learn数据加载系列的最后一篇,本篇介绍如何加载外部的数据集。 外部数据集不像之前介绍的几种类型的数据集那样,针对每种数据提供对应的接口,每个接口加载的数据都是固定的。 而外部数据集加载之后,数据的字段和类型是…...
Redis原理:keys命令
语法: keys pattern 返回所有符合pattern的key 支持 glob-style patterns: h?llo matches hello, hallo and hxlloh*llo matches hllo and heeeelloh[ae]llo matches hello and hallo, but not hilloh[^e]llo matches hallo, hbllo, ... but not helloh[a-b]llo ma…...
4.7学习总结 可变参数+集合工具类Collections+不可变集合
可变参数: 示例: public class test {public static void main(String[] args) {int sumgetSum(1,2,3,4,5,6,7,8,9,10);System.out.println(sum);}public static int getSum(int...arr){int sum0;for(int i:arr){sumi;}return sum;} } 细节:…...
高级java每日一道面试题-2025年3月24日-微服务篇[Nacos篇]-使用Nacos如何实现配置管理?
如果有遗漏,评论区告诉我进行补充 面试官: 使用Nacos如何实现配置管理? 我回答: 在Java高级面试中讨论如何使用Nacos实现配置管理的综合回答 在Java高级面试中,关于如何使用Nacos实现配置管理,可以从以下几个方面进行全面、深入的阐述&am…...
Exce格式化批处理工具详解:高效处理,让数据更干净!
Exce格式化批处理工具详解:高效处理,让数据更干净! 1. 概述 在数据分析、报表整理、数据库管理等工作中,数据清洗是不可或缺的一步。原始Excel数据常常存在格式不统一、空值、重复数据等问题,影响数据的准确性和可用…...
CExercise_06_1指针和数组_1查找数组的最大值和最小值
题目: 查找数组的最大值和最小值,但要将最大值作为返回值返回,最小值则依靠传入的指针完成赋值。 要求不能使用"[]"运算符。 函数的声明如下: int max_min(int *arr, int len, int *pmin); 关键点 1) * 运算符用于解引用…...
redis中的hash
Redis中的hash是什么 Hash: 哈希,也叫散列,是一种通过哈希函数将键映射到表中位置的数据结构,哈希函数是关键,它把键转换成索引。 Redis Hash(散列表)是一种 field-value pairs(键值对&#x…...
【学习笔记】李沐斯坦福21秋季:实用机器学习中文版
这里写自定义目录标题 数据处理数据获取数据标注数据清洗特征工程 数据处理 数据获取 爬虫 实际工作中大部分都是从数据库里取数 数据标注 只有一小部分有标签 大部分无标签的话 半监督学习:没标注数据和有标注数据共同使用 做法1:半监督学习 基于有标签的小部分…...
UE5学习笔记 FPS游戏制作43 UI材质
文章目录 实现目标制作UI材质使用UI材质 实现目标 把图片变为灰色 制作UI材质 右键新建一个材质 左侧细节栏,材质域改为用户界面,混合模式改为半透明 此时输出节点应该有两个属性 在内容浏览器里找到要用的图片,然后向上拖动到材质标题…...
QT控件 修改QtTreePropertyBrowser自定义属性编辑器源码,添加第一列标题勾选,按钮,右键菜单事件等功能
头阵子遇到一个需要修改QtTreePropertyBrowser控件的需求,QT开发做这么久了,这个控件倒是第一次用,费了点时间研究,在这里做个简单的总结。 QtTreePropertyBrowser控件 是 Qt 解决方案 (Qt Solutions) 中的一个组件,用…...
MFC工具栏CToolBar从专家到小白
CToolBar m_wndTool; //创建控件 m_wndTool.CreateEx(this, TBSTYLE_FLAT|TBSTYLE_NOPREFIX, WS_CHILD | WS_VISIBLE | CBRS_FLYBY | CBRS_TOP | CBRS_SIZE_DYNAMIC); //加载工具栏资源 m_wndTool.LoadToolBar(IDR_TOOL_LOAD) //在.rc中定义:IDR_TOOL_LOAD BITMAP …...
Golang 项目平滑重启
引言 平滑重启(Graceful Restart)技术作为一种常用的解决方案,通过允许新进程接管而不中断现有的请求,确保了系统的稳定运行和业务连续性。同时目前公司的服务重启绝大部分也都适用的 go 的平滑重启技术。 本部分将对平滑重启的…...
Vue2 插槽 Slot
提示:插槽的目的是让我买原来的设备具备更多的扩展性。 文章目录 前言在组件中定义插槽(子组件视角)1. 默认插槽2. 具名插槽(带名称的插槽)3. 作用域插槽(带数据的插槽) 使用插槽(父…...
关于sqlsugar实体多层List映射的问题
如上图所示,当一个主表(crm_fina_pay_req)的子表list<文件附件关系表>( List<crm_fina_payreq_evidofpay_relation> )中,还包含有sysfile(SysFile SysFiles)类型的文件信…...
使用stm32cubeide stm32f407 lan8720a freertos lwip 实现udp client网络数据转串口数据过程详解
1前言 项目需要使用MCU实现网络功能,后续确定方案stm32f407 外接lan8720a实现硬件平台搭建,针对lan8720a也是用的比较多的phy,网上比较多的开发板,硬件上都是选用了这个phy,项目周期比较短,选用了这个常用…...
LangChain4j(4):预设角色(系统消息SystemMessage)
1 预设角色(系统消息SystemMessage) 基础大模型是没有目的性的, 你聊什么给什么,但是如果我们开发的事一个智能票务助手, 我需要他以一个票务助手的角色跟我对话, 并且在我跟他说”退票”的时候, 让大模型一定要告诉我…...
自然语言处理利器NLTK:从入门到核心功能解析
文章目录 一、NLP领域的基石工具包二、NLTK核心模块全景解析1 数据获取与预处理2 语言特征发现3 语义与推理 三、设计哲学与架构优势1 四维设计原则2 性能优化策略 四、典型应用场景1 学术研究2 工业实践 五、生态系统与未来演进 一、NLP领域的基石工具包 自然语言工具包&…...
常见接口协议介绍
1. I2C(Inter-Integrated Circuit) 定义:两线制串行总线(SDA数据线 SCL时钟线),支持主从模式多设备通信。特点: 地址机制:每个设备有唯一地址,主设备通过地址选择从设备…...
宝塔面板使用CDN 部署后获取真实客户端 IP教程
在宝塔面板环境中配置 CDN 加速服务后,服务器日志默认记录的是 CDN 节点 IP,这给网站流量分析带来不便。本文将为您提供多种解决方案,帮助您在 CDN 生效的同时获取真实访客 IP。 一、Nginx 配置调整方案 日志格式优化 在宝塔面板中打开 Ngi…...
生鲜果蔬便利店实体零售门店商城小程序
——线上线下融合赋能社区零售新生态 随着新零售模式的深化和消费者需求的升级,生鲜果蔬便利店亟需通过数字化工具实现经营效率与用户体验的双重提升。结合线下实体门店与线上商城的一体化小程序,成为行业转型的核心工具。以下从功能模块、运营策略及行…...
C++(初阶)(十)——vector模拟实现
vector vector构造尾插(删)和扩容inert(插入)迭代器失效erase(删除)resize(调整空间)深浅拷贝迭代器拷贝和赋值(v2(v1)和v1 v3)多个数据插入迭代器区间初始化…...
利用解析差异SSRF + sqlite注入 + waf逻辑漏洞 -- xyctf 2025 fate WP
本文章附带TP(Thinking Process)! #!/usr/bin/env python3 # 导入所需的库 import flask # Flask web框架 import sqlite3 # SQLite数据库操作 import requests # HTTP请求库 import string # 字符串处理 import json # JSON处理app flask.Flask(__name__) # 创建Flask应…...
VScode无法激活conda虚拟环境,不显示虚拟环境名称
在VScode中终端中激活环境时出现下面的情况 PS F:\Model\stMMR-main> conda activate env_mamba usage: conda-script.py [-h] [--no-plugins] [-V] COMMAND ... conda-script.py: error: argument COMMAND: invalid choice: activate (choose from clean, compare, config…...
vscode Colipot 编程助手
1、登录到colipot,以github账号,关联登录 点击【continue】按钮,继续。 点击【打开Visual Studio Code】,回到vscode中。 2、问一下11? 可以看出,很聪明,一下子就算出来了。 3、帮我们写一个文件…...