Spring Cloud Gateway是 Spring Cloud 生态系统中的一个 API 网关服务,用于替换由Zuul开发的网关服务,基于Spring 5.0+Spring Boot 2.0+WebFlux等技术开发,提供了网关的基本功能,例如安全、监控、埋点和限流等,旨在为微服务架构提供一种简单而有效的统一 API 路由管理方式。

1.网关路由

1.1.认识网关

        什么是网关?顾明思议,网关就是络的口。数据在网络间传输,从一个网络传输到另一网络时就需要经过网关来做数据的路由和转发以及数据安全的校验

1.2 Gateway特性

Gateway具有以下主要特性:

  1. 动态路由:能够匹配任何请求属性上的路由

  2. 断言(Predicate)和过滤器(Filter):针对特定路由的灵活配置

  3. 集成 Hystrix 断路器:提供熔断功能

  4. 服务发现集成:与 Eureka、Consul 等服务发现组件无缝集成

  5. 请求限流:支持基于多种策略的限流

  6. 路径重写:支持请求路径的重写

1.3 Gateway相关术语

路由(Route):路由是网关的基本组件,Gateway包含多个路由,每个路由包含唯一的ID(路由编号)、目标URI(即请求最终被转发到的目的地URI)、路由断言集合和过滤器集合。

断言(Predicate):实际上就是Java 8 Function Predicate的断言功能,即匹配条件,只有满足条件的请求才会被路由到目标URI。输入类型是 Spring Framework ServerWebExchange。其允许开发人员自行匹配来自HTTP请求的任何内容,例如HTTP头或参数。

过滤器(Filter):作用类似于拦截加工,对于经过过滤器的请求和响应,都可以进行修改,例如Spring Framework GatewayFilter实例,可以在发送下游请求之前或之后修改请求和响应。

2. Gateway工作流程

        当Gateway客户端向Gateway服务端发送请求时,请求首先被HttpWebHandlerAdapter提取组装成网关上下文,然后网关上下文会传递到DispatcherHandler中。DispatcherHandler是所有请求的分发处理器,主要负责分发请求对应的处理器,比如将请求分发到对应的RoutePredicateHandlerMapping(路由断言处理映射器)。路由断言处理映射器主要用于路由查找,以及找到路由后返回对应的FilterWebHandler。FilterWebHandler主要负责组装过滤器链并调用过滤器执行一系列过滤处理,然后把请求转到后端对应的代理服务处理,处理完毕之后将反馈信息

Spring Cloud Gateway 的核心流程

客户端请求 → Gateway Handler Mapping → Gateway Web Handler → 过滤器链 → 代理服务

3. Spring Cloud Gateway案例

案例说明:创建两个简单的微服务模拟服务提供者和网关

3.1 父工程

创建父工程统一管理Spring Boot、Spring Cloud和Spring Cloud Alibaba,pom.xml文件代码如下所示。

<?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"><modelVersion>4.0.0</modelVersion><groupId>com.hl</groupId><artifactId>shop</artifactId><version>1.0.0</version><packaging>pom</packaging><modules><module>order-consumer</module><module>order-provider</module></modules><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.12</version><relativePath/></parent><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>2021.0.3</spring-cloud.version><spring-cloud-alibaba.version>2021.0.4.0</spring-cloud-alibaba.version><spring-boot-web.version>2.7.12</spring-boot-web.version></properties><dependencyManagement><dependencies><!--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></dependencies></dependencyManagement><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.22</version></dependency><!--单元测试--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency></dependencies></project>

3.2 service-provider微服务——服务提供者

在父工程中创建service-provider微服务,整合Nacos注册中心,并创建一个“/hello”接口来模拟服务提供者。

① 修改pom.xml文件,追加Nacos服务发现组件spring-cloud-starter-alibaba-nacos-discovery,代码如下所示。

<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.hl</groupId><artifactId>shop</artifactId><version>1.0.0</version></parent><artifactId>order-provider</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--nacos 服务注册发现--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency></dependencies></project>

② 在service-provider微服务的src/main/resources目录下创建application.yml文件,配置服务端口号为8081、微服务名为“service-provider”、Nacos注册中心地址为“localhost:8848”,代码如下所示。

server:port: 8081
spring:application:name: service-provideprofiles:active: devcloud:nacos:server-addr: localhost:8848 # nacos地址

③ 按照Spring Boot规范创建项目启动类ServiceProviderApplication,在该启动类上追加@EnableDiscoveryClient注解(该注解表示向Nacos注册中心注册微服务),开启服务注册与发现功能,代码如下所示。

package com.hl;
import com.hl.config.OpenFeignLoggerConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication
@EnableFeignClients
public class ServiceProviderApplication{public static void main(String[] args) {SpringApplication.run(ServiceProviderApplication.class, args);}
}

④ 创建ProviderController类,在该类上追加@RestController注解,在该类中定义一个hello()方法,返回“hello”及传进来的实参name。

import org.springframework.web.bind.annotation.GetMapping; 
import org.springframework.web.bind.annotation.RequestParam; 
import org.springframework.web.bind.annotation.RestController; @RestController 
public class ProviderController {@GetMapping("/hello")     public String hello(@RequestParam String name) {return "hello " + name + "!";     } 
} 

3.3 service-gateway微服务——网关

创建微服务service-gateway,并整合到Nacos注册中心。

① 修改pom.xml文件,追加Nacos服务发现组件spring-cloud-starter-alibaba-nacos-discovery及Gateway依赖spring-cloud-starter-gateway,修改后的pom.xml文件代码如下所示。

<?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"><modelVersion>4.0.0</modelVersion><parent><groupId>com.hl</groupId><artifactId>shop</artifactId><version>1.0.0</version></parent><artifactId>service-gateway</artifactId> <properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--nacos 服务注册发现--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!--负载均衡器--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><!--添加 Gateway依赖--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency></dependencies></project>

② 在service-gateway微服务的src/main/resources目录下创建application.yml文件,配置服务端口号为8001、微服务名为“service-gateway、Nacos注册中心地址为“localhost:8848”,spring.cloud.gateway.discovery.locator.enabled为true开启Gateway服务发现,即Gateway将使用服务发现来动态路由请求,application.yml代码如下所示。

server:   port: 8001 
spring:   application:     name: service-gateway   cloud:     nacos:       discovery:         server-addr: localhost:8848     gateway:       discovery:         locator:           enabled: true 

③ 按照Spring Boot规范创建项目启动类ServiceGatewayApplication,在该启动类上追加@EnableDiscoveryClient注解,开启服务注册与发现功能,代码如下所示。

@SpringBootApplication 
@EnableDiscoveryClient 
public class ServiceGatewayApplication {     public static void main(String[] args) {   SpringApplication.run(ServiceGatewayApplication.class, args);     } 
} 

3.4 测试Gateway路由转发

        在IDEA工具中启动两个微服务:service-provider和service-gateway。启动Nacos,访问http://localhost:8848/nacos,选择“服务管理”的“服务列表”,可发现service-provider和service-gateway微服务实例,说明微服务已成功注册到了Nacos注册中心

        通过Gateway端口号8001及服务名“service-provider”访问服务接口,即访问http://localhost: 8001/service-provider/hello?name=gateway,其中显示了“hello gateway”。至此基于网关实现了路由转发。

4. Gateway过滤器工厂

路由规则的定义语法如下:

spring:cloud:gateway:routes:- id: itemuri: lb://item-servicepredicates:- Path=/items/**,/search/**filters:             - AddRequestHeader=X-Request-red, blue

四个属性含义如下:

  • id:路由的唯一标示

  • predicates:路由断言,其实就是匹配条件

  • filters:路由过滤条件

  • uri:路由目标地址,lb://代表负载均衡,从注册中心获取目标微服务的实例列表,并且负载均衡选择一个访问。

        过滤器允许以某种方式修改传入的HTTP请求或传出的HTTP响应。Gateway内置丰富的过滤器,例如AddRequestHeader、AddRequestParameter、AddResponseHeader、RemoveRequestHeader、StripPrefix、RewritePath、LoadBalancerClientFilter

4.1 AddRequestHeaderGatewayFilterFacotry

        顾明思议,就是添加请求头的过滤器,可以给请求添加一个请求头并传递到下游微服务。

使用的使用只需要在application.yaml中这样配置:

spring:cloud:gateway:routes:- id: test_routeuri: lb://test-servicepredicates:-Path=/test/**filters:- AddRequestHeader=key, value # 逗号之前是请求头的key,逗号之后是value

如果想要让过滤器作用于所有的路由,则可以这样配置:

spring:cloud:gateway:default-filters: # default-filters下的过滤器可以作用于所有路由- AddRequestHeader=key, valueroutes:- id: test_routeuri: lb://test-servicepredicates:-Path=/test/**

5. Gateway路由断言工厂

        Gateway包括很多路由断言,当HTTP请求进入Gateway之后,由于实际工作中Gateway中存在多个路由,因此路由断言会根据配置的路由规则对请求进行断言匹配,若匹配成功则从相应路由转发。

名称

说明

示例

After

是某个时间点后的请求

- After=2037-01-20T17:42:47.789-07:00[America/Denver]

Before

是某个时间点之前的请求

- Before=2031-04-13T15:14:47.433+08:00[Asia/Shanghai]

Between

是某两个时间点之前的请求

- Between=2037-01-20T17:42:47.789-07:00[America/Denver], 2037-01-21T17:42:47.789-07:00[America/Denver]

Cookie

请求必须包含某些cookie

- Cookie=chocolate, ch.p

Header

请求必须包含某些header

- Header=X-Request-Id, \d+

Host

请求必须是访问某个host(域名)

- Host=**.somehost.org,**.anotherhost.org

Method

请求方式必须是指定方式

- Method=GET,POST

Path

请求路径必须符合指定规则

- Path=/red/{segment},/blue/**

Query

请求参数必须包含指定参数

- Query=name, Jack或者- Query=name

RemoteAddr

请求者的ip必须是指定范围

- RemoteAddr=192.168.1.1/24

weight

权重处理

5.1 Header路由断言

        Header路由断言有两个参数:Header名称(name)和正则表达式形式的值(value)。该路由断言用于匹配具有给定名称且值与正则表达式匹配的HTTP头。

spring:cloud:gateway:default-filters: # default-filters下的过滤器可以作用于所有路由- AddRequestHeader=key, valueroutes:- id: test_routeuri: lb://test-servicepredicates:             - Header=X-Request-Id, \d+

6. 动态路由

        路由规则是网关的核心内容,配置在应用的属性配置文件中,服务启动的时候将路由规 则加载到内存中,这属于静态路由方式。网关的路由配置全部是在项目启动时由org.springframework.cloud.gateway.route.CompositeRouteDefinitionLocator在项目启动的时候加载,并且一经加载就会缓存到内存中的路由表内(一个Map),不会改变。也不会监听路由变更,所以我们无法利用配置热更新来实现路由更新。

        可采用 Nacos 实现动态路由,把路由更新规则保存在分布式配置 中心 Nacos 中,通过 Nacos 的监听机制,动态更新每个实例的路由规则。因此,我们必须监听Nacos的配置变更,然后手动把最新的路由更新到路由表中。

6.1 监听Nacos配置变更

在Nacos官网中给出了手动监听Nacos配置变更的SDK:https://nacos.io/zh-cn/docs/sdk.html

监听配置:

如果希望 Nacos 推送配置变更,可以使用 Nacos 动态监听配置接口来实现。

public void addListener(String dataId, String group, Listener listener)

请求参数说明:

参数名

参数类型

描述

dataId

string

配置 ID,保证全局唯一性,只允许英文字符和 4 种特殊字符("."、":"、"-"、"_")。不超过 256 字节。

group

string

配置分组,一般是默认的DEFAULT_GROUP。

listener

Listener

监听器,配置变更进入监听器的回调函数。

示例代码:

String serverAddr = "{serverAddr}";
String dataId = "{dataId}";
String group = "{group}";
// 1.创建ConfigService,连接Nacos
Properties properties = new Properties();
properties.put("serverAddr", serverAddr);
ConfigService configService = NacosFactory.createConfigService(properties);
// 2.读取配置
String content = configService.getConfig(dataId, group, 5000);
// 3.添加配置监听器
configService.addListener(dataId, group, new Listener() {@Overridepublic void receiveConfigInfo(String configInfo) {// 配置变更的通知处理System.out.println("recieve1:" + configInfo);}@Overridepublic Executor getExecutor() {return null;}
});

这里核心的步骤有2步:

  • 创建ConfigService,目的是连接到Nacos

  • 添加配置监听器,编写配置变更的通知处理逻辑

第一步:

        由于我们采用spring-cloud-starter-alibaba-nacos-config自动装配,因此ConfigService已经在com.alibaba.cloud.nacos.NacosConfigAutoConfiguration中自动创建好了:

NacosConfigManager中是负责管理Nacos的ConfigService的,具体代码如下:

因此,只要我们拿到NacosConfigManager就等于拿到了ConfigService

第二步:

        编写监听器。虽然官方提供的SDK是ConfigService中的addListener,不过项目第一次启动时不仅仅需要添加监听器,也需要读取配置,因此建议使用的API是这个:

String getConfigAndSignListener(

        String dataId, // 配置文件id

        String group, // 配置组,走默认

        long timeoutMs, // 读取配置的超时时间

        Listener listener // 监听器

) throws NacosException;

        既可以配置监听器,并且会根据dataId和group读取配置并返回。我们就可以在项目启动时先更新一次路由,后续随着配置变更通知到监听器,完成路由更新。

6.2 更新路由

        Gateway 提供了修改路由的接口 RouteDefinitionWriter,只有通过这个接口才能修改动态路由。

package org.springframework.cloud.gateway.route;import reactor.core.publisher.Mono;/*** @author Spencer Gibb*/
public interface RouteDefinitionWriter {/*** 更新路由到路由表,如果路由id重复,则会覆盖旧的路由*/Mono<Void> save(Mono<RouteDefinition> route);/*** 根据路由id删除某个路由*/Mono<Void> delete(Mono<String> routeId);}

这里更新的路由,也就是RouteDefinition,包含下列常见字段:

  • id:路由id

  • predicates:路由匹配规则

  • filters:路由过滤器

  • uri:路由目的地

将来我们保存到Nacos的配置也要符合这个对象结构,将来我们以JSON来保存,格式如下:

{"id": "item","predicates": [{"name": "Path","args": {"_genkey_0":"/items/**", "_genkey_1":"/search/**"}}],"filters": [],"uri": "lb://item-service"
}

以上JSON配置就等同于:

spring:cloud:gateway:routes:- id: itemuri: lb://item-servicepredicates:- Path=/items/**,/search/**

6.3 .实现动态路由

首先引入依赖:

<!--统一配置管理-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--加载bootstrap-->
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>

然后在Nacos控制台添加路由,路由文件名为gateway-routes.json,类型为json

[{"id": "item","predicates": [{"name": "Path","args": {"_genkey_0":"/items/**", "_genkey_1":"/search/**"}}],"filters": [],"uri": "lb://item-service"}
]

然后在网关gatewayresources目录创建bootstrap.yaml文件,内容如下:

server:port: 8080 # 端口
spring:application:name: gatewaycloud:nacos:server-addr: localhostconfig:file-extension: yamlshared-configs:- dataId: gateway-routes.json # 动态路由配置

然后,在gateway中定义配置监听器:

package com.hmall.gateway.route;import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.hmall.common.utils.CollUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteLoader {private final RouteDefinitionWriter writer;private final NacosConfigManager nacosConfigManager;// 路由配置文件的id和分组private final String dataId = "gateway-routes.json";private final String group = "DEFAULT_GROUP";// 保存更新过的路由idprivate final Set<String> routeIds = new HashSet<>();@PostConstructpublic void initRouteConfigListener() throws NacosException {// 1.注册监听器并首次拉取配置String configInfo = nacosConfigManager.getConfigService().getConfigAndSignListener(dataId, group, 5000, new Listener() {@Overridepublic Executor getExecutor() {return null;}@Overridepublic void receiveConfigInfo(String configInfo) {updateConfigInfo(configInfo);}});// 2.首次启动时,更新一次配置updateConfigInfo(configInfo);}private void updateConfigInfo(String configInfo) {log.debug("监听到路由配置变更,{}", configInfo);// 1.反序列化List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo, RouteDefinition.class);// 2.更新前先清空旧路由// 2.1.清除旧路由for (String routeId : routeIds) {writer.delete(Mono.just(routeId)).subscribe();}routeIds.clear();// 2.2.判断是否有新的路由要更新if (CollUtils.isEmpty(routeDefinitions)) {// 无新路由配置,直接结束return;}// 3.更新路由routeDefinitions.forEach(routeDefinition -> {// 3.1.更新路由writer.save(Mono.just(routeDefinition)).subscribe();// 3.2.记录路由id,方便将来删除routeIds.add(routeDefinition.getId());});}
}

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

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

相关文章

[数据结构]#6 树

树是一种非线性的数据结构&#xff0c;它由节点组成&#xff0c;并且这些节点之间通过边连接。树的每个节点可以有一个或多个子节点&#xff0c;并且有一个特殊的节点叫做根节点&#xff08;没有父节点&#xff09;。树在计算机科学中应用广泛&#xff0c;尤其是在数据库索引、…

车辆网络安全规定之R155与ISO/SAE 21434

随着科技的不断进步&#xff0c;车辆已经从传统的机械装置演变为高度智能化的移动终端。现代汽车不仅配备了先进的驾驶辅助系统&#xff08;ADAS&#xff09;、车载信息娱乐系统&#xff08;IVI&#xff09;&#xff0c;还具备联网功能&#xff0c;能够实现远程诊断、自动驾驶、…

Go语言实战案例-合并多个文本文件为一个

以下是《Go语言100个实战案例》中的 文件与IO操作篇 - 案例21&#xff1a;合并多个文本文件为一个 的完整内容&#xff0c;适用于初学者学习文件读取与写入的综合运用。&#x1f3af; 案例目标使用 Go 语言将指定目录下的多个 .txt 文件&#xff0c;合并成一个新的总文件。&…

基坑渗压数据不准?选对渗压计能实现自动化精准监测吗?

一、渗压监测的背景 渗压计是一种专门用于测量构筑物内部孔隙水压力或渗透压力的传感器&#xff0c;适用于长期埋设在水工结构物或其它混凝土结构物及土体内&#xff0c;以测量结构物或土体内部的渗透&#xff08;孔隙&#xff09;水压力。 在水利工程中&#xff0c;大坝、水库…

Linux网络:阿里云轻量级应用服务器配置防火墙模板开放端口

1.问题介绍在使用Udp协议或其他协议进行两台主机或同一台主机通信时&#xff0c;常常会出现bind成功&#xff0c;但是在客户端向服务端发送数据后&#xff0c;服务端无响应的情况&#xff0c;如果使用轻量级应用服务器&#xff0c;大概率是服务器的端口因为防火墙未对公网IP开放…

《 Spring Boot整合多数据源:分库业务的标准做法》

&#x1f680; Spring Boot整合多数据源&#xff1a;分库业务的标准做法 文章目录&#x1f680; Spring Boot整合多数据源&#xff1a;分库业务的标准做法&#x1f50d; 一、为什么需要多数据源支持&#xff1f;&#x1f4a1; 典型业务场景⚙️ 二、多数据源集成方案对比&#…

前端ApplePay支付-H5全流程实战指南

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档前言近期公司开展关于苹果支付的相关业务&#xff0c;与之前不同的是&#xff0c;以前后台直接获取第三方Wallet封装好的接口获取支付地址&#xff0c;H5页面直接跳转使用Appl…

Flink窗口:解锁流计算的秘密武器

Flink 窗口初识在大数据的世界里&#xff0c;数据源源不断地产生&#xff0c;形成了所谓的 “无限数据流”。想象一下&#xff0c;网络流量监控中&#xff0c;每一秒都有海量的数据包在网络中穿梭&#xff0c;这些数据构成了一个无始无终的流。对于这样的无限数据流&#xff0c…

Java排序算法之<希尔排序>

目录 1、希尔排序介绍 1.1、定义 1.2、核心思想 2、希尔排序的流程 第 1 轮&#xff1a;gap 4 第 2 轮&#xff1a;gap 2 第 3 轮&#xff1a;gap 1 3、希尔排序的实现 4、时间复杂度分析 5、希尔排序的优缺点 6、适用场景 前言 希尔排序&#xff08;Shell Sort&…

c++加载qml文件

这里展示了c加载qml文件的三种方式以及qml文件中根节点的访问准备在创建工程的初期&#xff0c;遇到了一个问题&#xff0c;cmake文件以前都是系统自动生成的&#xff0c;不需要我做过多的操作修改&#xff0c;但是&#xff0c;加载qml的程序主函数是需要用到QGuiApplication&a…

007TG洞察:GPT-5前瞻与AI时代竞争力构建:技术挑战与落地路径

最近&#xff0c;GPT-5 即将发布的消息刷爆了科技圈&#xff0c;更让人期待的是&#xff0c;GPT-6 已经悄悄启动训练了&#xff0c;OpenAI 的奥特曼表示对未来1-2年的模型充满信心&#xff0c;预测AI将进化为能够发现新知识的“AI科学家”。面对日益强大的通用AI&#xff0c;企…

Windows下编译OpenVDB

本文记录在Windows下编译OpenVDB的流程。 零、环境 操作系统Windows 11VS Code1.92.1Git2.34.1MSYS2msys2-x86_64-20240507Visual StudioVisual Studio Community 2022CMake3.22.1 一、编译 1.1 下载 git clone https://github.com/AcademySoftwareFoundation/openvdb.git …

react 内置hooks 详细使用场景,使用案例

useState场景&#xff1a;组件中管理局部状态&#xff0c;如表单值、开关、计数器等。const [count, setCount] useState(0); return <button onClick{() > setCount(count 1)}>Click {count}</button>;useEffect 场景&#xff1a;组件挂载时执行副作用&#…

从0到1学Pandas(九):Pandas 高级数据结构与操作

目录一、探秘多级索引1.1 创建多级索引1.2 多级索引操作1.3 索引转换二、探索 Panel 与 xarray2.1 Panel 数据结构2.2 xarray 库2.3 高维数据操作三、时间序列高级应用3.1 时区处理3.2 时间序列重采样与频率转换3.3 时间序列分解与预测四、数据透视与重塑高级技巧4.1 复杂透视表…

C# 图像转换实战:Bitmap 转 BitmapSource 的 2 种方法

C# 图像转换实战:Bitmap 转 BitmapSource 的 2 种方法 引言 两种转换方法的完整实现 1. 基于GDI句柄的直接转换 (ToBitmapSourceFast) 2. 基于内存流的编码转换 (ToBitmapSourceSafe) 方法对比与选型指南 避坑指南 GDI句柄泄漏问题 图像显示不完整 多线程访问图像引发异常 不同…

Spring Boot 整合 Spring MVC:自动配置与扩展实践

Spring MVC 作为 Java Web 开发的核心框架&#xff0c;在传统 SSM 项目中需要大量 XML 配置&#xff08;如 DispatcherServlet、视图解析器等&#xff09;。而 Spring Boot 通过 "自动配置" 特性&#xff0c;简化了 Spring MVC 的整合过程&#xff0c;同时保留了灵活…

print(“\033[31m红\033[32m绿\033[34m蓝\033[0m默认色“)

可以让python的终端字体有着不一样的颜色。代码&#xff1a;print("\033[31m红\033[32m绿\033[34m蓝\033[0m默认色")效果&#xff1a;

LNMP-zblog分布式部署

一、准备3台主机&#xff08;rocky8&#xff09;下载相应服务[rootnginx ~]# yum install -y nginx nfs-utils[rootphp ~]# yum install -y nfs-utils php-mysqlnd php php-fpm[rootmysql ~]# yum install -y mysql-server二、挂载php端[rootphp ~]# vim /etc/exports [rootphp…

常见代码八股

1. 利用梯度下降法&#xff0c;计算二次函数yx^2x4的最小值 def target_function(x):return x ** 2 x 4def gradient(x):return 2*x 1x_init 10 x x_init steps 100 lr 0.1 for i in range(100):x x - lr*gradient(x)print(f"最小值 f(x) {target_function(x):.4f…

【深入底层】C++开发简历4+4技能描述6

简历书写 熟悉C的封装、继承、多态&#xff0c;STL常用容器&#xff0c;熟悉C11的Lambda表达式、智能指针等&#xff0c;熟悉C20协程语法&#xff0c;具有良好的编码习惯与文档能力。 回答思路 这里是基本上就是要全会&#xff0c;考察的问题也很固定&#xff0c;stl这块可以定…