【SpringCloud】Eureka的使用

3. Eureka

3.1 Eureka 介绍

Eureka主要分为两个部分:

EurekaServer:

作为注册中心Server端,向微服务应用程序提供服务注册,发现,健康检查等能力。

EurekaClient:

服务提供者,服务启动时,会向 EurekaServer 注册自己的信息 (IP,端口,服务信息
等),Eureka Server 会存储这些信息。

3.2 搭建 Eureka 服务

Eureka 是一个单独的服务,所以咱们要手动搭建出 Eureka 服务器。

这里使用父子项目来搭建 Eureka 服务,先创建一个 spring-cloud-demo 的父项目:

在这里插入图片描述

后续所有的项目创建都在这个父项目中创建子项目。

在这里插入图片描述

直接复制下面 spring-cloud-demo 的 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>org.example</groupId><artifactId>spring-cloud-demo</artifactId><version>1.0-SNAPSHOT</version><packaging>pom</packaging><modules></modules><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.6</version><relativePath/> <!-- lookup parent from repository --></parent><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><java.version>17</java.version><spring-cloud.version>2022.0.3</spring-cloud.version></properties><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies><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>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis.version}</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>${mysql.version}</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter-test</artifactId><version>${mybatis.version}</version><scope>test</scope></dependency></dependencies></dependencyManagement>
</project>

pom.xml 关键部分解析:

  1. <modules>
    定义子模块(当前为空),用于多模块项目管理。所有子模块需在此声明,Maven 会按顺序构建。
  2. <parent>
    继承 Spring Boot 的默认配置(如插件、依赖管理),版本为 3.1.6,简化项目配置。
  3. <properties>
    统一定义变量,便于维护版本:
    • Java 版本:17
    • Spring Cloud:2022.0.3
  4. <dependencies>
    当前仅引入 Lombok(代码简化工具),<optional>true</optional> 表示不传递依赖给子模块。
  5. <dependencyManagement>
    统一管理依赖版本,子模块引用时无需指定版本:
    • 引入 Spring Cloud 全家桶的版本控制
    • 锁定 MyBatis 和 MySQL 驱动版本
    • 测试用 MyBatis 依赖(仅测试范围生效)

记得删除掉父工程的 src 目录,因为后续不会在父工程中写代码。

有了上述操作,咱们的父工程就创建好了,接下来开始创建子工程。

下面开始在父工程底下创建一个子模块,也就是用这个子模块去搭建 Eureka 服务:

在这里插入图片描述

创建子模块项目名为 eureka-server:
在这里插入图片描述

此时点击 Create 后,就会发现 spring-cloud-demo 目录下出现了 eureka-server 子项目,同时在父项目的 pom.xml 中的 modules 里出现了咱们子模块的名字

在这里插入图片描述

在子项目 eureka-server 的 pom.xml <dependencies> </dependencies> 中引入 eureka-server 依赖:

<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>

在子项目 eureka-server 的 pom.xml <project> </project> 加入项目构件插件

<build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins>
</build>

记得点击右上角 maven 的刷新,或者打开 maven 面板点击 Reload ALL Maven Project 按钮重新加载下依赖。

由于创建的子项目是一个空的项目,所以需要手动创建好对应的包和子模块的启动类:

EurekaServerApplication.class 代码如下:

package com.zlcode.eureka;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication.class, args);}
}

编写配置文件,这里需要手动在 resoureces 中创建该项目的配置文件 papplication.yml

# Eureka相关配置
# Eureka 服务
server:port: 10010
spring:application:name: eureka-server
eureka:instance:hostname: localhostclient:# 表示是否从Eureka Server获取注册信息,默认为true.因为这是一个单点的Eureka Server,# 不需要同步其他的Eureka Server节点的数据,这里设置为falsefetch-registry: false# 表示是否将自己注册到Eureka Server,默认为true.由于当前应用就是Eureka Server,故而设置为false.register-with-eureka: falseservice-url:# 设置Eureka Server的地址,查询服务和注册服务都需要依赖这个地址defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

有了上述的操作,就能执行 eureka-server 项目中的 main 方法了。

在浏览器中输入 http://127.0.0.01:10010 就能发现此时 eureka-server 已经成功启动了。

在这里插入图片描述

3.3 创建cook服务和waiter服务

接下来再来创建两个子项目,分别是 厨师(cook) 和 服务员(waiter),厨师需要让服务员上菜。

创建厨师服务和服务员服务跟创建 Eureka 项目一致,创建的流程这里就省略了,也就是在 spring-cloud-demo 目录下创建厨师子模块和服务员子模块。

### 3.3.1 cook-service 模块配置代码

cook-service 的 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>org.example</groupId><artifactId>spring-cloud-demo</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>cook-service</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><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

cook-service 的 application.yml 文件如下:

server:port: 8080
spring:application:name: cook-service # 添加服务器名称
#Eureka Client
eureka:client:service-url:# eureka 地址defaultZone: http://127.0.0.1:10010/eureka/

cook-service 的 启动类 文件如下:

package com.zlcode.cook;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class CookServiceApplication {public static void main(String[] args) {SpringApplication.run(CookServiceApplication.class, args);}
}

3.3.2 waiter-service 模块配置代码

waiter-service 的 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>org.example</groupId><artifactId>spring-cloud-demo</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>waiter-service</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><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

waiter-service 的 application.yml 文件如下:

server:port: 9090
spring:application:name: waiter-service # 添加服务器名称
#Eureka Client
eureka:client:service-url:# eureka 地址defaultZone: http://127.0.0.1:10010/eureka/

waiter-service 的 启动类 文件如下:

package com.zlcode.waiter;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class WaiterServiceApplication {public static void main(String[] args) {SpringApplication.run(WaiterServiceApplication.class, args);}
}

3.3.3 cook 实体类

将 CookInfo 创建在 cookie-service/*/cook/model/目录下:

package com.zlcode.cook.model;import lombok.Data;@Data
public class CookInfo {private Integer cookId;private String cookieName;
}

3.3.4 waiter 实体类

将 WaiterInfo 创建在 waiter-service/*/waiter/model/目录下:

package com.zlcode.waiter.model;import lombok.Data;@Data
public class WaiterInfo {private Integer waiterId;private String waiterName;
}

3.4 服务注册

启动咱们的 waiter-service 和 cook-service 项目,就能自动的进行 eureka 的服务注册了,因为咱们在 .yml 已经配置好了 eureka 的地址。
在这里插入图片描述

启动 waiter 和 cook 后,刷新 http://127.0.0.1:10010 就能发现:

在这里插入图片描述

通过上面可以看到,已经把 cook-service 和 waiter-service 注册到咱们部搭建的 eureka-server 服务中了。

上述这样的操作,咱们就称作为服务注册。

由于 cook-service 想通过 eureka-server 去发现 waiter-service 所以,也要让 cook-service 自己在 eureka 中注册,这样一来 cook-service 就可以从 eureka-server 中去发现 waiter-service 服务。

3.5 服务发现

前面咱们说,厨师想通过喊服务员名字来让服务员上菜,但是呢它并不知道当前哪些服务员是能提供服务的,于是便需要向 eureka-server 去获取可用服务列表,于是厨师就不需要关注服务员叫什么了。

咱们对 cook-service 和 waiter-service 分别创建一个 controller 包,在 cook 的 controller 包中新建 CookController类,在 waiter 的 controller 中新建 WaiterController 类,此处咱们就不新建 Service 层 和 Mapper 层了,这里只是为了学习服务发现,所以使用一层演示就足够了。

对于 waiter 服务来说,就提供一个接口,这个接口就是执行一个模拟的任务:

package com.zlcode.waiter.controller;import jakarta.websocket.server.PathParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/waiter")
@Slf4j
public class WaiterController {@RequestMapping("/up")public String up(@PathParam("content") String content) {log.info("正在执行: " + content);return "执行: " + content + "成功!";}
}

上述 waiter 就提供了 /waiter/up 这个接口,比如传递的 content 为 “给55桌上红烧肉”,这个请求就会打印一下这个content,然后再模拟返回结果。下面咱们来使用 postman 测试这个接口的可用性:

在这里插入图片描述

这里可用发现 waiter 服务的 up 接口成功返回了预期的值,同时在 waiter 的控制台也能看到:

在这里插入图片描述

调用 waiter 的 up 方法后,成功的模拟执行了上菜操作!

接下来咱们看一下 cook 提供了哪个接口:

package com.zlcode.cook.controller;import jakarta.websocket.server.PathParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.List;@RestController
@RequestMapping("/cook")
public class CookController {@Autowiredprivate DiscoveryClient discoveryClient;@RequestMapping("/ok")public String ok(@PathParam("content")String content) {// 通过 discoveryClient 从 eureka-server 获取服务列表List<ServiceInstance> instances = discoveryClient.getInstances("waiter-service");String uri = instances.get(0).getUri().toString(); // 拿到服务列表的第一个 ip:端口号// ----------------------------------------------------------// 这里咱们拿到了 waiter 的 ip 地址和端口号// 也就是知道了服务员的名字,那么要如何告诉服务员你需要让他上菜呢?// 当然现实中可用喊一嗓子,但在代码中呢?// ---------------------------------------------------------return "";}
}

此时这里就可用通过 discoveryClient.getInstances 实例列表,此处是获取名字为 waiter-service 的服务列表,获取后,通过 instances.get(0).getUri().toString(); 获取这个实例的 ip 和 端口号。

为什么这里可能会有多个实例呢?别忘记了,把同一个项目换成不同的端口号,分别运行,这就是两个服务,同时这两个服务都进行服务注册,此时 eureka 上就会有两个这样的服务了,只是对应的端口号不同,如果端口号相同,但是ip不同,也就是在不同的主机上,这样也是 ok 的。

但是这里只启动了一个 waiter-service 服务,所以咱们取第 0 个就ok了。

ip 和端口号是拿到了,可是如何调用 waiter-service 服务提供的 up 接口呢?

其实也很简单,既然都拿到ip端口号了,直接使用 ip+端口号/waiter/up?content=“xxx” 这个 url 给 waiter 发一个 http 请求就ok了,但是使用 js 发 http 请求相信都会,但是在 Java 中如何给发送 http 请求呢?

这里可用使用 Spring 提供的 RestTemplate 类,通过这个可用发送一个 http 请求,但是注意了!!!

想认识 RestTemplate 就得知道什么是 Rest。

REST(Representational State Transfer),表现层资源状态转移。

简单来说:REST描述的是在网络中Client和Server的⼀种交互形式,REST本身不实用,实用的是如何设计RESTfulAPI(REST风格的网络接口)接口类似于:

GET/blog/{blogId}:查询博客
DELETE/blog/{blogId}:删除博客

而 RestTemplate 是Spring提供,封装HTTP调⽤,并强制使用RESTful风格。它会处理HTTP连接和关闭,只需要使用者提供资源的地地和参数即可。

所以要想使用这个 RestTemplate 进行 http 请求,先得把咱们 waiter 服务的 up 接口改成 Rest 风格的接口:

package com.zlcode.waiter.controller;import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/waiter")
@Slf4j
public class WaiterController {@RequestMapping("/up/{content}")public String up(@PathVariable("content") String content) {log.info("正在执行: " + content);return "执行: " + content + "成功!";}
}

接下来在 cook-service 项目中先定义 RestTemplate,把这个对象交给 Spring 容器管理,在 cook 目录下创建 config 目录,在这个目录下创建一个 BeanConfig 类,在这个类中定义好咱们要用的 RestTemplate 就 OK 了。

package com.zlcode.cook.config;import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;@Configuration
public class BeanConfig {@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}

接下来修改 CookConroller 的 ok 接口:

package com.zlcode.cook.controller;import jakarta.websocket.server.PathParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;import java.util.List;@RestController
@RequestMapping("/cook")
public class CookController {@Autowiredprivate DiscoveryClient discoveryClient;@Autowiredprivate RestTemplate restTemplate;// 咱们的 cook 里面的接口可以不遵循 Rest 规范,// 只要保证使用 restTemplate 调用的接口遵守 Rest 规范就ok了@RequestMapping("/ok")public String ok(@PathParam("content")String content) {// 通过 discoveryClient 从 eureka-server 获取服务列表List<ServiceInstance> instances = discoveryClient.getInstances("waiter-service");String uri = instances.get(0).getUri().toString(); // 拿到服务列表的第一个 ip:端口号// 通过 restTemplate 给 waiter-service 发送 http 请求String url = uri + "/waiter/up/{content}";// 第一个参数是请求 url, // 第二个参数是这个请求的返回值类型的class对象, // 第三个参数是占位符对应的值String resp = restTemplate.getForObject(url, String.class, content);return "调用成功, 已收到 waiter 的响应: " + resp;}
}

此时咱们此处的代码,就是 cook 厨师,通过 eureka 注册中心获取到服务列表,拿到第一个服务的 ip和端口,通过这个 ip 和 端口 拼接上完整的接口路由,带上参数,就实现了远程方法调用了。

此处如果服务员离职了,来了个新的服务员,对于厨师来说,没有任何影响,厨师只需要关注注册中心有哪些服务列表就行了。

3.6 服务注册和发现的注意点

List<ServiceInstance> instances = discoveryClient.getInstances("waiter-service");
String uri = instances.get(0).getUri().toString(); // 拿到服务列表的第一个 ip:端口号
String url = uri + "/waiter/up/{content}";
String resp = restTemplate.getForObject(url, String.class, content);

上面代码是服务发现和远程调用的重要代码。

上面的 discoveryClient.getInstances(“waiter-service”) 这里方法的形参,waiter-service 就像是给这个服务取了一个名字,比如传菜的都叫做服务员,只要名字叫 waiter-service 的服务,都能获取到,那么注册中心是如何知道每个服务的名字呢?

在这里插入图片描述

观察 waiter-service 的 spring.application.name 的值是 waiter-server,注册中心就是通过这个 name 来区分的,所以也就是有可能出现如下的情况:

服务A 的名字:waiter-service 这个服务只提供了 test 接口
服务B 的名字:waiter-service 这个服务只提供了 hello 接口

由于服务 AB 启动时都会进行服务注册,那么问题来了,通过discoveryClient.getInstances(“waiter-service”) 会拿到两个实例,也就是可以获取两个服务的 ip 和 端口号,假设 服务C 想调用 test 接口,而服务C 只知道 name 为 waiter-service 的服务提供了 test 接口,但是服务C不知道的是:AB都叫 test-service,但是服务B没有提供 test 接口。

如果此时 C 通过 instances.get(0).getUri().toString();,拿到的是服务B的ip和端口,此时再通过 restTemplate 进行调用 test 接口,那问题就大了!!

也就是说,如果统称为服务员,那么必须都得具备传菜的接口服务。

所以对于这里的 spring.application.name 的值,要保证相同的 name 它所提供的服务(接口)要是一致的!

在这里插入图片描述

现在咱们就来复现上面这种情况,先创建 B/hello 和 A/test 接口,并且这两个服务都叫做 waiter-service。

AController:

package com.zlcode.waiter.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class AController {@RequestMapping("test")public String test () {return "成功调用了 服务A 的 test 接口";}
}

BController:

package com.zlcode.waiter.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class BController {@RequestMapping("/hello")public String hello() {return "成功调用了 服务B 的 hello 接口";}
}

启动这两个服务A和服务B,服务A的端口为9091,服务B的端口为9092,此时可以发现 服务A 只提供了 test 接口,服务B 只提供了 hello 接口。

在这里插入图片描述

此时启动服务A和服务B,都发现已经成功使用 waiter-service 这个名字进行服务注册了。

然后使用服务C去获取 waiter-service 对应的服务列表,调用下这两个服务的 test 接口:

package com.zlcode.cook.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;@Slf4j
@RestController
@RequestMapping("/C")
public class CController {@Autowiredprivate RestTemplate restTemplate;@Autowiredprivate DiscoveryClient discoveryClient;@RequestMapping("/run")public void run() {List<ServiceInstance> instances = discoveryClient.getInstances("waiter-service");for (ServiceInstance instance : instances) {String uri = instance.getUri().toString();log.info("获取到服务器地址:" + uri);String url = uri + "/test";try {String resp = restTemplate.getForObject(url, String.class);log.info(uri + " 调用服务器 test 接口成功! resp: " + resp);} catch (Exception e) {e.printStackTrace();log.error("服务器: " + uri + "没有提供 test 接口.");}}}
}

上述就是服务C,咱们给它运行在 8080 端口上,然后调用 127.0.0.1/C/run 这个接口后,他就会从注册中心获取 waiter-service 服务信息,此时能拿到两个,9091 端口是提供了 test 接口服务的,而 9092 则没有提供 test 接口服务。

在 postman 调用 127.0.0.1/C/run 观察项目打印日志:

在这里插入图片描述

果然不出所料,没有提供 test 接口的服务B就会报 404 错误。所以现在你理解了服务名的重要性了吗?

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

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

相关文章

前端知识点---window.location.assign() 和 window.location.href 的区别(javascript)

window.location.assign() 和 window.location.href 的主要区别&#xff1a; 读取和设置 window.location.href&#xff1a;既可以读取当前 URL&#xff0c;也可以通过赋值更改 URL。 window.location.assign()&#xff1a;只能用于跳转到新的 URL&#xff0c;不能读取当前地…

OpenCV图像拼接(3)图像拼接类cv::detail::MultiBandBlender

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::detail::MultiBandBlender 是 OpenCV 中用于图像拼接&#xff08;stitching&#xff09;模块的一个类&#xff0c;主要用于将多张重叠的图像…

王者荣耀服务器突然崩了

就在刚刚王者荣耀服务器突然崩了 #王者荣耀崩了#的话题毫无预兆地冲上热搜&#xff0c;许多玩家发现游戏登录界面反复弹出异常提示&#xff0c;匹配成功后卡在加载界面&#xff0c;甚至出现对局数据丢失的情况。根据官方公告&#xff0c;目前技术团队已在全力抢修服务器 #王者…

【JavaScript】JavaScript Promises实践指南

【JavaScript】JavaScript Promises实践指南 你了解JavaScript中的Promises吗&#xff1f;这是一个很多人一开始就放弃的主题&#xff0c;但我会尽量让它变得尽可能简单。 1. “Promise”到底是什么&#xff1f; “Promise”是异步编程中的一个基本概念&#xff0c;特别是在J…

计算机视觉总结

以下是针对上述问题的详细解答,并结合代码示例进行说明: 1. 改进YOLOv5人脸检测模块,复杂光照场景准确率从98.2%提升至99.5% 优化具体过程: 光照补偿:在数据预处理阶段,采用自适应光照补偿算法,对图像进行实时增强,以减少光照变化对人脸检测的影响。数据增强:在训练…

ExpTimerApcRoutine函数分析之作用是ActiveTimerListHead里面移除定时器_etimer

第一部分&#xff1a; VOID ExpTimerApcRoutine ( IN PKAPC Apc, IN PKNORMAL_ROUTINE *NormalRoutine, IN PVOID *NormalContext, IN PVOID *SystemArgument1, IN PVOID *SystemArgument2 ) /* Routine Description: This function is the special …

算法分析与设计 专题三

目录 一、实验目的 二、实验内容 三、问题分析与求解 四、AC源代码、截图 五、实验小结 一、实验目的 1、了解贪心算法的分析过程&#xff0c;学会用贪心算法解决一些具体的问题。 2、了解广度优先算法和深度优先算法。 二、实验内容 1992 当然&#xff0c;我们的收藏中…

1688商品详情接口:深度解析与应用实践

在电商领域&#xff0c;1688作为中国领先的B2B平台&#xff0c;拥有海量的商品信息。对于开发者、商家和数据分析师来说&#xff0c;获取1688商品的详细信息是实现数据分析、竞品研究、自动化管理和精准营销的重要手段。本文将详细介绍1688商品详情接口的使用方法、技术细节以及…

每日算法-250328

记录今天学习和解决的LeetCode算法题。 92. 反转链表 II 题目 思路 本题要求反转链表中从 left 到 right 位置的节点。我们可以采用 头插法 的思路来反转指定区间的链表。 具体来说&#xff0c;我们首先定位到 left 位置节点的前一个节点 prev。然后&#xff0c;从 left 位置…

C语言中的位域:节省内存的标志位管理技术

位域&#xff08;Bit-field&#xff09; 是 C 语言中的一种特性&#xff0c;允许在结构体&#xff08;struct&#xff09;中定义占用特定位数的成员变量。通过位域&#xff0c;可以更精细地控制内存的使用&#xff0c;尤其是在需要存储多个布尔值或小范围整数时&#xff0c;可以…

【AI编程学习之Python】第一天:Python的介绍

Python介绍 简介 Python是一种解释型、面向对象的语言。由吉多范罗苏姆(Guido van Rossum)于1989年发明,1991年正式公布。官网:www.python.org Python单词是"大蟒蛇”的意思。但是龟叔不是喜欢蟒蛇才起这个名字,而是正在追剧:英国电视喜剧片《蒙提派森的飞行马戏团》(Mo…

【openstack系列】虚拟化技术

OpenStack 是一个开源的云计算管理平台,它本身并不直接提供虚拟化技术,而是通过集成不同的虚拟化解决方案来管理和编排计算、存储和网络资源。OpenStack 的核心优势在于其灵活性和可扩展性,支持多种虚拟化技术(Hypervisor),使企业可以根据需求选择合适的底层虚拟化方案。…

保姆级教程:Vue3 + Django + MySQL 前后端联调(PyCharm+VSCode版)

一、环境准备与验证 这里为减少篇幅&#xff0c;默认大家都安装好了这些软件。不会下载安装的&#xff0c;教程也很多&#xff0c;这里不再做赘述。话不多说&#xff0c;咱们开始&#xff1a; 1. 安装验证 确保已安装以下软件并验证版本&#xff1a; # 验证Node.js node -v…

Spring Data审计利器:@LastModifiedDate详解!!!

&#x1f552; Spring Data审计利器&#xff1a;LastModifiedDate详解&#x1f525; &#x1f31f; 简介 在数据驱动的应用中&#xff0c;记录数据的最后修改时间是常见需求。Spring Data的LastModifiedDate注解让这一过程自动化成为可能&#xff01;本篇带你掌握它的核心用法…

洛谷题单1-P1001 A+B Problem-python-流程图重构

题目描述 输入两个整数 a,b&#xff0c;输出它们的和&#xff08;∣a∣,∣b∣≤109&#xff09;。 输入格式 两个以空格分开的整数。 输出格式 一个整数。 输入输出样例 输入 20 30输出 50方式-print class Solution:staticmethoddef oi_input():"""从…

CCF CSP 第33次(2024.03)(2_相似度计算_C++)(字符串中字母大小写转换+哈希集合)

CCF CSP 第33次&#xff08;2024.03&#xff09;&#xff08;2_相似度计算_C&#xff09; 题目背景&#xff1a;题目描述&#xff1a;输入格式&#xff1a;输出格式&#xff1a;样例1输入&#xff1a;样例1输出&#xff1a;样例1解释&#xff1a;样例2输入&#xff1a;样例2输出…

Windows .gitignore文件不生效的情况排查

概述 今天下班在家里捣腾自己的代码&#xff0c;在配置.gitignore文件忽略部分文件的时候&#xff0c;发现死活不生效 问题根源 经过一通分析和排查才发现&#xff0c;是.gitignore文件的编码错了&#xff0c;刚开始还没注意到&#xff0c;因为是在Windows下开发&#xff0c…

Uniapp自定义TabBar组件全封装实践与疑难问题解决方案

前言 在当前公司小程序项目中&#xff0c;我们遇到了一个具有挑战性的需求&#xff1a;根据不同用户身份动态展示差异化的底部导航栏&#xff08;TabBar&#xff09; 。这种多角色场景下的UI适配需求&#xff0c;在提升用户体验和实现精细化运营方面具有重要意义。 在技术调研…

四川省汽车加气站操作工备考题库及答案分享

1.按压力容器的设计压力分为&#xff08; &#xff09;个压力等级。 A. 三 B. 四 C. 五 D. 六 答案&#xff1a;B。解析&#xff1a;按压力容器的设计压力分为低压、中压、高压、超高压四个压力等级。 2.缓冲罐的安装位置在天然气压缩机&#xff08; &#xff09;。 A. 出口处 …

2025年- G27-Lc101-542. 01 矩阵--java版

1.题目描述 2.思路 总结&#xff1a;用广度优先搜索&#xff0c;首先要确定0的位置&#xff0c;不为0的位置&#xff0c;我们要更新的它的值&#xff0c;只能往上下左右寻找跟它最近的0的位置。 解题思路 我们用 BFS&#xff08;广度优先搜索&#xff09;求解&#xff0c;因为 …