微服务开发:断路器详解

微服务是目前业界使用的最重要的实现方面。通过使用微服务架构,开发人员可以消除他们以前在单体应用程序中遇到的许多问题。展望未来,人们开始在微服务中搜索和采用各种模式。大多数时候,新模式的产生是为了解决另一个模式中出现的常见问题。就这样,随着时间的推移,大量的模式进入了实践。您可以从这里获得完整的摘要: https://microservices.io/patterns/microservices.html

考虑到它们的范围,这些微服务模式进一步分为几类。在所有这些模式中,许多开发人员都使用了一些非常重要和流行的模式。断路器是其中之一,有助于以适当的方式管理下游服务故障。让我们了解这种模式的作用。💪

一、断路器介绍

1.1 什么是断路器模式?

您可能已经听说过我们在电子产品中发现的断路器。它的主要目的是什么?简单地说,在意想不到的情况下切断电流。与此相同,这种微服务模式也因其具有相同的性质而得名。

这种模式在服务之间进行通信时出现。让我们来看一个简单的场景。假设我们有两个服务:服务 A 和 B。服务 A 正在调用服务 B(API 调用)以获取所需的一些信息。当服务 A 调用服务 B 时,如果服务 B 由于某些基础设施中断而关闭,会发生什么?服务 A 没有得到结果,它将因抛出异常而挂起。然后另一个请求来了,它也面临同样的情况。就像这个请求线程将被阻塞/挂起,直到服务 B 出现!结果,网络资源将被耗尽,性能低下,用户体验差。级联故障也可能因此发生。

在这种情况下,我们可以使用这种断路器模式来解决问题。它为我们提供了一种在不打扰最终用户或应用程序资源的情况下处理这种情况的方法。

1.2 模式如何运作?💥

基本上,它的行为与电路断路器相同。当应用程序的远程服务调用失败次数超过给定阈值时,断路器将在特定时间段内跳闸。在此超时到期后,断路器允许有限数量的请求通过它。如果这些请求成功,则断路器将关闭并恢复正常操作。否则,如果它们失败了,超时时间将重新开始,然后像以前一样做剩下的事情。

以下是一些常见概念讲解帮助大家来理解断路器。😎

1.3 模式状态的生命周期💥

断路器模式中讨论了 3 个主要状态。他们是:

  1. CLOSED

  2. OPEN

  3. HALF OPEN

让我们简要了解一下状态……

CLOSED State

当正在交互的两个服务都启动并运行时,断路器默认关闭。断路器会持续统计远程 API 调用的次数。

OPEN State

一旦远程 API 调用失败百分比超过给定阈值,断路器就会将其状态更改为 OPEN 状态。调用微服务会立即失败,返回异常。也就是说,流量中断了。

HALF OPEN State

在 OPEN 状态停留给定的超时时间后,断路器自动将其状态变为 HALF OPEN 状态。在这种状态下,只允许有限数量的远程 API 调用通过。如果失败调用计数大于此有限数量,则断路器再次变为 OPEN 状态,流量继续中断。否则关闭断路器,流量恢复正常。

Pattern states

Pattern states

为了实际演示该模式,我将使用 Spring Boot 框架来创建微服务。并用 Resilience4j 库实现断路器。

1.4 什么 Resilience4j?

Resilience4j 是一个轻量级、易于使用的容错库,其灵感来自于 Netflix Hystrix。它提供各种功能如下:

  • 断路器 — 容错

  • 速率限制器 — 阻止太多请求

  • 时间限制器 — 调用远程操作时的限制时间

  • 重试机制 — 失败操作自动重试

  • 隔板 — 限制并发请求数

  • 缓存 — 存储远程操作的结果

在本文中,我们将基于 Spring Boot 项目来使用第一个功能。😎

二、代码讲解

2.1 创建 2️⃣ 个微服务

我将使用名为 loan-service(贷款) 和 rate-service(利率) 的两个服务来实现一个简单的服务间通信场景。

技术细节:

带有 H2 内存中 DB、JPA、Hibernate、Actuator、Resilience4j 的 Spring Boot

脚本:

贷款服务可以获取保存在数据库中的贷款,每个贷款对象都有贷款类型。根据贷款类型,有单独的利率百分比。因此,利率服务的名称包含那些利率对象的详细信息。

  • 我将从贷款服务调用利率服务,请求给定贷款类型的利率。

  • 然后我必须根据贷款类型计算贷款的总利息价值。

  • 然后我将使用从利率服务获得的利率更新所有贷款对象的利息金额。

Project setup

Project setup

由于费率服务是独立的,我将首先实现费率服务的基本功能。

使用 POM 文件下方提供的依赖项创建一个新的 Spring Boot 项目。我将其命名为费率服务。https://github.com/SalithaUCSC/spring-boot-circuit-breaker/blob/main/rate-service/pom.xml

Controller:
@RestController
@RequestMapping("api")
public class RateController {@Autowiredprivate RateService rateService;@GetMapping(path = "/rates/{type}")public ResponseEntity<Rate> getRateByType(@PathVariable("type") String type) {return ResponseEntity.ok().body(rateService.getRateByType(type));}
}
Service:
@Service
public class RateService {@Autowiredprivate RateRepository repository;public Rate getRateByType(String type) {return repository.findByType(type).orElseThrow(() -> new RuntimeException("Rate Not Found: " + type));}
}
Repository:
@Repository
public interface RateRepository extends JpaRepository<Rate, Integer> {Optional<Rate> findByType(String type);
}
Entity:
@Builder
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "rates")
public class Rate {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)Integer id;String type;@Column(name = "rate")Double rateValue;
}
Configuration:
server:port: 9000
spring:application:name: rate-servicedatasource:url: jdbc:h2:mem:cb-rate-dbusername: rootpassword: 123driverClassName: org.h2.Driverjpa:database-platform: org.hibernate.dialect.H2Dialecthibernate:ddl-auto: create-droph2:console:enabled: true
启动类:主类将在服务即将到来时添加两种类型的贷款利率。
@SpringBootApplication
public class RateServiceApplication {@Autowiredprivate RateRepository rateRepository;public static void main(String[] args) {SpringApplication.run(RateServiceApplication.class, args);}@PostConstructpublic void setupData() {rateRepository.saveAll(Arrays.asList(Rate.builder().id(1).typ并检查我们需要的 APIe("PERSONAL").rateValue(10.0).build(),Rate.builder().id(2).type("HOUSING").rateValue(8.0).build()));}
}

现在我们可以启动 rate-service 并检查我们需要的 API。转到 http://localhost:9000/api/rates/PERSONAL 并查看结果。你应该得到这个回应。

{"id": 1,"type": "PERSONAL","rateValue": 10}

2.2 贷款服务添加断路器

现在我需要实施贷款服务。 loan-service 内部需要断路器,因为它正在调用 rate-service。因此,需要 Resilience4j 库。我需要检查断路器的状态。为此,我需要在贷款服务中启用 Actuator。

使用 POM 文件下方提供的依赖项创建一个新的 Spring Boot 项目。我将其命名为贷款服务。 https://github.com/SalithaUCSC/spring-boot-circuit-breaker/blob/main/loan-service/pom.xml

让我们为贷款服务添加基本功能。

Controller:
@RestController
@RequestMapping("api")
public class LoanController {@Autowiredprivate LoanService loanService;@GetMapping(path = "/loans")public ResponseEntity<List<Loan>> getLoansByType(@RequestParam("type") String type) {return ResponseEntity.ok().body(loanService.getAllLoansByType(type.toUpperCase()));}}
Repository:
public interface LoanRepository extends JpaRepository<Loan, Integer> {List<Loan> findByType(String type);
}
DTO:这用于转换来自费率服务 API 调用的响应。因为它是 Rate 的类型。同rate-service Rate实体类(只是省略了ORM相关的东西)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class InterestRate {Integer id;String type;Double rateValue;
}
Entity:
@Builder
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "loans")
public class Loan {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)Integer id;String type;Double amount;Double interest;
}
启动类:
  • 主类将在服务即将到来时添加 3 个贷款对象。利息金额已设置为零,因为我们后来通过远程调用 rate-service 对其进行了更新。

  • 我们需要一个 RestTemplate 类的 Bean 来执行远程 API 调用。如果您不知道,请从此处阅读: https://salithachathuranga94.medium.com/rest-template-with-spring-boot-e2001a8219e6

@SpringBootApplication
public class LoanServiceApplication {@Autowiredprivate LoanRepository loanRepository;public static void main(String[] args) {SpringApplication.run(LoanServiceApplication.class, args);}@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}@PostConstructpublic void setupData() {loanRepository.saveAll(Arrays.asList(Loan.builder().id(1).type("PERSONAL").amount(200000.0).interest(0.0).build(),Loan.builder().id(2).type("HOUSING").amount(6000000.0).interest(0.0).build(),Loan.builder().id(3).type("PERSONAL").amount(100000.0).interest(0.0).build()));}
}
Service:

这是我们执行远程调用的最重要的地方。我们需要在利率服务中使用 RestTemplate: http://localhost:9000/api/rates/{type} 调用此 API 以获取贷款类型的百分比。然后我们计算利息金额为贷款金额*(利率/100)并更新贷款利息金额。

@Service
public class LoanService {@Autowiredprivate LoanRepository loanRepository;@Autowiredprivate RestTemplate restTemplate;private static final String SERVICE_NAME = "loan-service";private static final String RATE_SERVICE_URL = "http://localhost:9000/api/rates/";public List<Loan> getAllLoansByType(String type) {HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);HttpEntity<InterestRate> entity = new HttpEntity<>(null, headers);ResponseEntity<InterestRate> response = restTemplate.exchange((RATE_SERVICE_URL + type),HttpMethod.GET, entity,InterestRate.class);InterestRate rate = response.getBody();List<Loan> loanList = new ArrayList<>();if (rate != null) {loanList = loanRepository.findByType(type);for (Loan loan : loanList) {loan.setInterest(loan.getAmount() * (rate.getRateValue() / 100));}}return loanList;}
}
Configuration:
server:port: 8000
spring:application:name: loan-servicedatasource:url: jdbc:h2:mem:cb-loan-dbusername: rootpassword: 123driverClassName: org.h2.Driverjpa:database-platform: org.hibernate.dialect.H2Dialecthibernate:ddl-auto: create-droph2:console:enabled: true
management:endpoint:health:show-details: alwaysendpoints:web:exposure:include: healthhealth:circuitbreakers:enabled: true

我们需要在执行器暴漏断路器详细信息(暴漏端点)。稍后我们将在此处添加断路器配置。目前,不需要。

现在我们可以启动 rate-service 并检查我们需要的 API。转到 http://localhost:8000/api/loans?type=personal 并查看结果。你应该得到这个回应。

[
{"id": 1,"type": "PERSONAL","amount": 200000,"interest": 20000}, 
{"id": 3,"type": "PERSONAL","amount": 100000,"interest": 10000}
]

2.3 添加回退方法💥

现在我们必须用注释来丰富我们的 Loan 服务方法。它被称为 “@CircuitBreaker”。在这里,SERVICE_NAME 被视为“贷款服务”。然后我们必须提供一个 fallbackMethod。这样做的目的是当下游服​​务(速率服务)无法响应时默认调用它。

@CircuitBreaker(name = SERVICE_NAME, fallbackMethod = "getDefaultLoans")
public List<Loan> getAllLoansByType(String type) {...............
}

我已经设置了当费率服务没有响应时默认返回空列表的方法。

您可以设置此方法以显示错误消息,而不发送空消息。你可以返回这样的东西 — “Rate service is not responding.请求失败!”。发送空数组或一组默认数据不是理想的方式。因为这会给用户带来困惑。但是您必须确保这两种方法都返回相同类型的数据。在我的例子中:两种方法都返回列表!

public List<Loan> getDefaultLoans(Exception e) {return new ArrayList<>();
}

2.4 添加断路器配置💥

让我们添加 Resilience4j 断路器配置。将此添加到贷款服务中的 application.yml。

resilience4j:circuitbreaker:instances:loan-service:registerHealthIndicator: truefailureRateThreshold: 50minimumNumberOfCalls: 5automaticTransitionFromOpenToHalfOpenEnabled: truewaitDurationInOpenState: 5spermittedNumberOfCallsInHalfOpenState: 3slidingWindowSize: 10slidingWindowType: COUNT_BASED
  • failureRateThreshold — 失败阈值的预期百分比。我将其设置为 50%。这意味着,当失败的远程调用总数 % 等于或大于 50% 时,断路器将处于活动状态以停止进一步的请求。

  • minimumNumberOfCalls — 决定启用断路器的失败百分比的 API 调用总数的最小值。我将其设置为 5。假设前 5 个 API 调用中有 3 个 API 调用失败。这意味着 failureRateThreshold = (3/5) * 100 = 60%。

  • automaticTransitionFromOpenToHalfOpenEnabled — 我已将其设置为 true。当转换的正确时间到来时,它会自动将 OPEN 状态转换为 HALF OPEN 状态

  • waitDurationInOpenState — 从 OPEN 状态进入 HALF OPEN 状态之前的超时时间。 5 秒后,断路器就将更改状态。

  • permittedNumberOfCallsInHalfOpenState — 在 HALF OPEN 状态下应发送的 LIMITED API 调用数。我将其设置为 3。因此,在 3 次 API 调用之后,如果失败,则断路器将再次进入 OPEN 状态。否则断路器将关闭,因为 rate-service 已启动。

  • slidingWindowType:我在这里设置了类型以根据请求计数保持断路器行为。

启动这两个服务。现在转到贷款服务,输入监控端点 URL:http://localhost:8000/actuator/health。断路器的详细信息会在响应中突出显示。

{"status": "UP","components": {"circuitBreakers": {"status": "UP","details": {"loan-service": {"status": "UP","details": {"failureRate": "-1.0%","failureRateThreshold": "50.0%","slowCallRate": "-1.0%","slowCallRateThreshold": "100.0%","bufferedCalls": 1,"slowCalls": 0,"slowFailedCalls": 0,"failedCalls": 0,"notPermittedCalls": 0,"state": "CLOSED"}}}},......................................}
}
  • bufferedCalls — 从贷款服务到利率服务的总 API 调用

  • failedCalls - 从贷款服务到利率服务的失败 API 调用总数

  • failureRate — (failedCalls/bufferedCalls) * 100%

2.5 测试断路器💥

我们必须遵循一些有序的步骤才能准确地看到变化。在每一步中,我们都必须查看监控端点,并通过更改其状态查看断路器的行为方式。开始!💪

  • 启动两个微服务。贷款服务在 8000 上运行,利率服务在 9000 上运行。

  • 现在点击此 API 2 次:http://localhost:8000/api/loans?type=personal。然后去检查监控端点 http://localhost:8000/actuator/health。现在 bufferedCalls 计数已按预期更新为 2。由于费率服务已启动,断路器仍处于关闭状态。

{"loan-service": {"status": "UP","details": {"failureRate": "-1.0%","failureRateThreshold": "50.0%","slowCallRate": "-1.0%","slowCallRateThreshold": "100.0%","bufferedCalls": 2,"slowCalls": 0,"slowFailedCalls": 0,"failedCalls": 0,"notPermittedCalls": 0,"state": "CLOSED"}}
}
  • 现在停止费率服务!然后点击贷款服务 API URL 3次:http://localhost:8000/api/loans?type=personal。你应该得到一个我们设置为后备的空数组!这将使 bufferedCalls 计数为 5(前 2 个和这个 3)。同时,failedCalls 计数更新为 3。现在 failureRate 变为 60%( (3/5) * 100% )。然后它已经超过了我们的阈值:50%。😀然后断路器将其状态更改为 OPEN!😍

{"loan-service": {"status": "CIRCUIT_OPEN","details": {"failureRate": "60.0%","failureRateThreshold": "50.0%","slowCallRate": "0.0%","slowCallRateThreshold": "100.0%","bufferedCalls": 5,"slowCalls": 0,"slowFailedCalls": 0,"failedCalls": 3,"notPermittedCalls": 0,"state": "OPEN"}}
}
  • 然后等待 5 秒钟。它应该在 5 秒后转换为半开状态,根据我们的配置,我们将 waitDurationInOpenState 设置为 5s 这是超时时间。在这段时间之后,请求计数也将被重置。

{"loan-service": {"status": "CIRCUIT_HALF_OPEN","details": {"failureRate": "-1.0%","failureRateThreshold": "50.0%","slowCallRate": "-1.0%","slowCallRateThreshold": "100.0%","bufferedCalls": 0,"slowCalls": 0,"slowFailedCalls": 0,"failedCalls": 0,"notPermittedCalls": 0,"state": "HALF_OPEN"}}
}
  • 在 HALF OPEN 状态下,有限数量的请求将被允许通过。在我们的例子中,它在配置中为 3,相关值已设置为 permittedNumberOfCallsInHalfOpenState: 3。

由于 rate-service 仍然关闭,只需再次尝试 loan-service API 3次!http://localhost:8000/api/loans?type=personal 发生了什么事? 3次调用全部失败!那么 failureRate 就是 100%。我们的断路器将再次打开。

{"loan-service": {"status": "CIRCUIT_OPEN","details": {"failureRate": "100.0%","failureRateThreshold": "50.0%","slowCallRate": "0.0%","slowCallRateThreshold": "100.0%","bufferedCalls": 3,"slowCalls": 0,"slowFailedCalls": 0,"failedCalls": 3,"notPermittedCalls": 0,"state": "OPEN"}}
}
  • 超时 5 秒后,它将再次变为半开状态!使用执行器再次检查。你应该得到一个用于贷款服务 API 调用的空数组...

  • 现在开始收费服务!😎然后再次尝试此 API 3次:http://localhost:8000/api/loans?type=personal 发现断路器已关闭!😍因为成功执行了预期的有限 API 调用计数。

{"loan-service": {"status": "UP","details": {"failureRate": "-1.0%","failureRateThreshold": "50.0%","slowCallRate": "-1.0%","slowCallRateThreshold": "100.0%","bufferedCalls": 0,"slowCalls": 0,"slowFailedCalls": 0,"failedCalls": 0,"notPermittedCalls": 0,"state": "CLOSED"}}
}

自此,我们完成了断路器的测试工作。是不是很神奇?😎它正在按预期工作!

完整的源代码可以在这个 GitHub 存储库中找到:https://github.com/SalithaUCSC/spring-boot-circuit-breaker

最后感谢大家阅读,希望这篇文章能为你提供价值。公众号【waynblog】分享技术干货、开源项目、实战经验、高效开发工具等,您的关注将是我的更新动力😘。

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

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

相关文章

指针(二)

这里写目录标题 字符指针字符指针与常量字符串的区别&#xff1a; 指针数组数组指针两者的区别&#xff1a;&数组名 &#xff0c;sizeof(arr)数组指针的使用数组参数&#xff0c;指针参数一维数组传参整型数组&#xff1a;整型指针数组&#xff1a; 一级指针传参二级指针传…

基于单片机自动饮料混合机控制系统设计

**单片机设计介绍&#xff0c;基于单片机自动饮料混合机控制系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机自动饮料混合机控制系统设计是一个涉及多个领域的复杂项目&#xff0c;包括单片机技术、传感器技术…

SQL手工注入漏洞测试(Access数据库)-墨者

———靶场专栏——— 声明&#xff1a;文章由作者weoptions学习或练习过程中的步骤及思路&#xff0c;非正式答案&#xff0c;仅供学习和参考。 靶场背景&#xff1a; 来源&#xff1a; 墨者学院 简介&#xff1a; 安全工程师"墨者"最近在练习SQL手工注入漏洞&#…

用例图是什么?用什么工具绘制?

在软件工程中&#xff0c;用例图属于UML&#xff08;Unified Modeling Language&#xff09;的一种图形模型&#xff0c;是一个交流需求和设计的重要工具。 用例图主要用来展示软件系统功能需求和相关角色之间的交互方式。它描述了一个系统如何与外界进行交互&#xff0c;表示…

MYSQL全语法速查(含示例)

文章目录 1.从简单的查询开始查找所有记录(SELECT *)查找记录中的所有登录名(SELECT)查找登录名为admin的密码(WHERE)查找电话号码非空的记录(IS NOT NULL)查找所在城市为北京或者用户名字是李四的记录(OR)查找所在城市为北京并且用户名字是张三的记录(AND)查找用户名字是李四或…

强化学习第1天:强化学习概述

☁️主页 Nowl &#x1f525;专栏《机器学习实战》 《机器学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 ​​ 文章目录 介绍 强化学习要素 强化学习任务示例 环境搭建&#xff1a;gym 基本用法 环境信息查看 创建智能体 过程可视化 完整代码 结语…

有线传输介质

目录 1、双绞线 &#xff08;1&#xff09;无屏蔽双绞线 UTP(Unshielded Twisted Pair) &#xff08;2&#xff09;屏蔽双绞线 STP (Shielded Twisted Pair) &#xff08;3&#xff09;布线标准EIA/TIA-568-&#xff21; &#xff08;4&#xff09;双绞线的特点 2、同轴电…

变频电机的负载曲线核对

1.问题导入 月初偶然接触到一个很奇怪的现象&#xff0c;一款变频电机在各个档位下的输入线电流&#xff0c;如果负载不变&#xff0c;无论怎样切换变频器输出频率&#xff0c;电流会保持近乎恒定。这个特性让我感觉很好奇。直觉的理解&#xff0c;因为频率变化&#xff0c;而…

Linux指令学习

目录 1.ls指令 2.pwd命令 3.cd 指令 4. touch指令 5.mkdir指令 6.rmdir指令 && rm 指令 7.man指令 8.cp指令 9.mv指令 10.cat指令 11.more指令 12.less指令 13.head指令 14.find指令&#xff1a; -name 15.grep指令 16.zip/unzip指令&#xff1a; 17.tar…

Windows驱动中使用数字签名验证控制设备访问权限

1. 背景 在一般的驱动开发时&#xff0c;创建了符号链接后在应用层就可以访问打开我们的设备并进行通讯。 但我们有时候不希望非自己的进程访问我们的设备并进行交互&#xff0c;虽然可以使用 IoCreateDeviceSecure 来创建有安全描述符的设备&#xff0c;但大数的用户账户为了方…

二叉树的右视图[中等]

优质博文&#xff1a;IT-BLOG-CN 一、题目 给定一个二叉树的 根节点root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。 示例 1: 输入: [1,2,3,null,5,null,4] 输出: [1,3,4] 示例 2: 输入: [1,null,3] 输出…

西工大计算机学院计算机系统基础实验一(函数编写11~14)

稳住心态不要慌&#xff0c;如果考试周冲突的话&#xff0c;可以直接复制这篇博客和上一篇博客西工大计算机学院计算机系统基础实验一&#xff08;函数编写1~10&#xff09;-CSDN博客最后的代码&#xff0c;然后直接提交&#xff0c;等熬过考试周之后回过头再慢慢做也可以。 第…

如何做好软文推广的选题?媒介盒子分享常见套路

选题是软文推广的重中之重&#xff0c;主题选得好&#xff0c;不仅能够戳到用户&#xff0c;提高转化率&#xff0c;还能让各位运营的写作效率大幅度提升&#xff0c;今天媒介盒子就来和大家分享软文选题的常见套路&#xff0c;助力各位品牌进行选题。 一、 根据产品选题 软文…

【AI-Fix】解决地图展示包leafmap在Jupyter NoteBook中地图不显示的问题

1. 问题描述 新创建的环境想使用leafmap在Jupyter中进行地图展示&#xff0c;结果发现运行完成之后不显示&#xff0c;不论怎么重启都没有办法显示出来&#xff0c;以经验来看&#xff0c;多半是缺了包了。 于是去leafmap的官方文档查找原因&#xff0c;一开始并没有发现什么问…

C++ 拷贝构造函数

目录 拷贝构造函数概述 拷贝构造函数特性 拷贝构造函数概述 当我们定义好一个类&#xff0c;不做任何处理时&#xff0c;编译器会自动生成以下6个默认成员函数&#xff1a; 默认成员函数&#xff1a;如果用户没有手动实现&#xff0c;则编译器会自动生成的成员函数。 同样&…

JavaWeb(十)

一、JavaWeb概述 Web&#xff1a;全球广域网&#xff0c;也称为万维网(www)&#xff0c;能够通过浏览器访问的网站。 JavaWeb&#xff1a;使用 Java技术进行web互联网开发。 二、JavaWeb 技术栈 2.1、B/S 架构 B/S 架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器…

解决找不到msvcr120.dll无法执行代码的4个方法,快来看看解决方法!

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中最常见的就是“缺少xxx.dll文件”。而msvcr120.dll就是其中之一。那么&#xff0c;msvcr120.dll到底是什么呢&#xff1f;它又有什么作用呢&#xff1f;本文将从多个方面对msvcr120.dll进行详细的解析…

华为鸿蒙爆发真实力!原生应用媲美iOS,使用流畅度将提升20至30%

随着华为鸿蒙原生应用开发计划的启动&#xff0c;一场席卷全球的科技浪潮正在涌动。鸿蒙生态的快速发展&#xff0c;吸引了无数企业和开发者的关注&#xff0c;他们纷纷拥抱这个新兴的生态系统&#xff0c;共同构建一个更加繁荣的鸿蒙世界。 华为鸿蒙原生应用开发计划引爆全球…

【电路笔记】-交流电路中的电阻器

交流电路中的电阻器 文章目录 交流电路中的电阻器1、概述2、交流电路中的电阻器示例 13、交流电路中的电阻器示例2 电阻器也可用于交流电源&#xff0c;其中消耗的电压、电流和功率以有效值给出。 1、概述 在之前的文章中&#xff0c;我们研究了电阻器及其连接&#xff0c;并使…

Leetcode刷题笔记题解(C++):BM11 链表相加(二)

思路&#xff1a;先对两个链表进行反转&#xff0c;反转求和注意进位运算&#xff0c;求和完成之后再进行反转得到结果 /*** struct ListNode {* int val;* struct ListNode *next;* ListNode(int x) : val(x), next(nullptr) {}* };*/ #include <cstddef> class Soluti…