解放代码:识别与消除循环依赖的实战指南

目录

一、对循环依赖的基本认识

(一)代码中形成循环依赖的说明

(二)无环依赖的原则

二、识别和消除循环依赖的方法

(一)使用JDepend识别循环依赖

使用 Maven 集成 JDepend

分析报告识别循环依赖

(二)消除循环依赖的三大方法思考

提取中介者

转移业务逻辑

采用回调接口

三、案件实战分析

(一)具体案列介绍

HealthRecord 类

HealthTask 类

循环依赖的产生

(二)具体解决方案一:提取中介者

提取中介者的实现

简化的 HealthTask 类

测试用例示例

(三)具体解决方案二:转移业务逻辑

转移业务逻辑的实现

改造后的 HealthRecord 类

改造后的 HealthTask 类

测试用例示例

(四)具体解决方案三:采用回调接口

使用回调接口的实现

HealthLevelHandler 接口的定义

改造后的 HealthTask 类

改造后的 HealthRecord 类

测试用例示例

参考书籍、文献和链接等


本文讨论软件开发中常见的循环依赖问题及其解决方法。首先介绍了循环依赖在代码中的形成原因,并提出了避免循环依赖的基本原则。其次,详细介绍了使用工具如JDepend来识别项目中的循环依赖,并通过具体案例分析了三种消除循环依赖的方法:提取中介者、转移业务逻辑和采用回调接口。每种方法都结合了实际的代码改造示例和测试用例,帮助读者理解和应用这些技术以优化自己的软件架构和设计。主要思想的编排思路来自极客时间《如何有效识别和解决代码中存在的循环依赖问题?》,当然也有其他的参考和自身的一些思考和优化。

一、对循环依赖的基本认识

循环依赖是指两个或多个模块或对象彼此之间相互依赖形成闭环,如 A 依赖 B,B 又依赖 A。这就像是两个人互相拉着对方,无法确定谁先开始走。

循环依赖最大的问题是,在运行时,可能会导致无限递归、栈溢出或者对象创建循环等问题,因为每个类的构造函数都试图创建依赖的对象,形成了一个死锁。所以一般情况下我们都希望在编译时,编译器就可能会报告循环依赖错误或无法解析的问题。

(一)代码中形成循环依赖的说明

循环依赖是指两个或多个模块、类、或组件之间相互依赖形成闭环。这种情况可能导致编译错误、运行时错误,甚至导致系统崩溃或无法正常工作。随着系统复杂性的增加,循环依赖问题可能会变得更加严重和难以检测。

简单来说,假设当前只有存在两个类A和类B,这个时候的识别还是较简单的,但如果此时在增加C,那么这个时候其可能产生依赖的情况就会很多了,比如如下的三种情况:

显然我们平时的系统中不会只是三个类这么简单,在多类情况下这种依赖问题就会不断放大(随着业务发展只会不断扩大),比如简单的依赖会变为如下依赖:

现实中,随着类和模块数量的增加,系统中的依赖关系会变得复杂,容易形成循环依赖,不仅增加了系统的复杂性和维护难度,还可能导致运行时错误和系统不稳定。因此,在设计和实现系统时,应尽量避免循环依赖,并采取合适的解决策略来管理依赖关系。

(二)无环依赖的原则

无环依赖原则(ADP)规定,在系统的依赖关系图中,不应该存在任何依赖环。换句话说,一个模块或组件的依赖链中不应出现环形依赖结构。这样,任何一个模块的变更不会导致循环依赖的问题,从而避免了系统的复杂性和难以维护性。

也就是基本原则要求如下:

  • 在软件设计中,模块之间的依赖关系可以用图来表示,节点表示模块,边表示依赖关系。无环依赖原则要求这个图必须是一个有向无环图(DAG)。
  • 通过确保依赖关系是无环的,可以防止系统中出现依赖的闭环,避免模块之间的强耦合。这样,修改一个模块不会引发对其依赖模块的连锁反应。

二、识别和消除循环依赖的方法

识别和消除循环依赖是软件开发中的一个重要任务,可以通过重构代码、引入中介者模式、使用接口和依赖注入,以及遵循设计原则等方法来实现。借助 Maven Enforcer Plugin、Madge、Deptrac、JDepend、PyDepGraph 和 SonarQube 等开源工具,可以更高效地检测和管理项目中的依赖关系,从而提高代码的可维护性和可扩展性。

(一)使用JDepend识别循环依赖

JDepend 是一个用于分析 Java 包之间依赖关系的工具。它能够生成报告,帮助开发者理解项目的架构和依赖关系,并识别可能的设计问题,如循环依赖。JDepend 提供了关于包的耦合度、内聚性、抽象度和稳定性等方面的信息,从而帮助改进代码质量和系统结构。可以从 JDepend 的官方网站 下载 JDepend,并将 JDepend 集成到构建工具中,例如 Maven 或 Gradle,以便在构建过程中自动分析依赖关系。

使用 Maven 集成 JDepend

在Maven 项目的 pom.xml 文件中添加 JDepend 插件:

<project><!-- 其他配置 --><build><plugins><plugin><groupId>org.codehaus.mojo</groupId><artifactId>jdepend-maven-plugin</artifactId><version>2.0-beta-2</version><executions><execution><goals><goal>generate</goal></goals></execution></executions></plugin></plugins></build>
</project>

然后,运行以下命令来执行 JDepend 分析:

mvn jdepend:generate

分析报告识别循环依赖

JDepend 生成的报告包括以下几个方面:

  • 包的稳定性:度量包的变化频率,越不稳定的包越容易发生变化。
  • 包的抽象度:度量包的抽象程度,抽象包通常包含更多的接口和抽象类。
  • 包的耦合度:度量包之间的依赖关系。
  • 循环依赖:检测包之间是否存在循环依赖。

一旦生成 JDepend 报告就可以在报告中查找是否存在循环依赖,循环依赖通常会被标记为 “Cycles” 或 “Dependency Cycles”:

(二)消除循环依赖的三大方法思考

提取中介者

通过引入一个独立的中介者类来管理和协调其他类之间的交互,从而避免直接的循环依赖。

适用于需要集中管理复杂依赖关系的场景,可以有效地降低类之间的耦合度,增强系统的可维护性和灵活性。

转移业务逻辑

将涉及循环依赖的业务逻辑转移到一个独立的类或模块中,从而解除类之间的直接依赖关系。

适用于可以重构业务逻辑的场景,通过模块化设计提高系统的可理解性和可维护性。

采用回调接口

通过定义接口来抽象依赖关系,使类之间的依赖通过接口进行交互,从而避免直接的循环依赖。

适用于需要解耦具体实现的场景,可以增强系统的扩展性和灵活性。

三、案件实战分析

(一)具体案列介绍

在医疗健康类系统中,每个用户都有一份健康档案,记录着他们当前的健康状况(以健康等级表示)和一系列健康任务。用户每天可以通过完成医生指定的任务来获得健康积分。健康积分的计算取决于用户的当前等级,不同等级下完成同一个任务获得的积分不同。同时,用户的健康等级也取决于他们当前需要完成的任务数量,任务越多说明越不健康,等级也就越低。

针对这个场景,我们可以抽象出两个类:HealthRecordHealthTask

HealthRecord

HealthRecord 类代表健康档案,包含一个 HealthTask 列表以及添加 HealthTask 的方法。这个类还包含一个获取健康等级的方法,该方法根据任务数量来判断用户的健康等级。

import java.util.ArrayList;
import java.util.List;public class HealthRecord {private List<HealthTask> tasks = new ArrayList<HealthTask>();public Integer getHealthLevel() {// 根据健康任务数量来判断健康等级// 任务越多说明越不健康,健康等级就越低if (tasks.size() > 5) {return 1;}if (tasks.size() < 2) {return 3;}return 2;}public void addTask(String taskName, Integer initialHealthPoint) {HealthTask task = new HealthTask(this, taskName, initialHealthPoint);tasks.add(task);}public List<HealthTask> getTasks() {return tasks;}
}

HealthTask

HealthTask 类代表健康任务,它包含对 HealthRecord 的引用,并实现了一个计算任务所能获得积分的方法,这个方法需要使用 HealthRecord 中的健康等级信息。

public class HealthTask {private HealthRecord record;private String taskName;private Integer initialHealthPoint;public HealthTask(HealthRecord record, String taskName, Integer initialHealthPoint) {this.record = record;this.taskName = taskName;this.initialHealthPoint = initialHealthPoint;}public Integer calculateHealthPointForTask() {// 计算该任务所能获取的积分需要等级信息// 等级越低积分越高,以鼓励多做任务Integer healthPointFromHealthLevel = 12 / record.getHealthLevel();// 最终积分为初始积分加上与等级相关的积分return initialHealthPoint + healthPointFromHealthLevel;}public String getTaskName() {return taskName;}public int getInitialHealthPoint() {return initialHealthPoint;}
}

循环依赖的产生

从代码中可以看出,HealthRecordHealthTask 之间存在循环依赖:

  • HealthRecord 需要知道 HealthTask 列表来确定健康等级。
  • HealthTask 需要引用 HealthRecord 来计算任务的健康积分。

这种循环依赖在系统扩展和维护时会带来很多问题,例如增加新的功能可能导致意想不到的耦合和复杂度。

(二)具体解决方案一:提取中介者

提取中介者的核心思想是把两个相互依赖的组件中的交互部分抽象出来形成一个新的组件,而新组件同时包含着原有两个组件的引用,这样就把循环依赖关系剥离出来并提取到一个专门的中介者组件中。

在医疗健康类系统中,我们面对 HealthRecordHealthTask 两个类之间的循环依赖问题:HealthRecord 类负责管理健康档案和健康任务列表,同时根据任务数量确定用户的健康等级。而 HealthTask 类则依赖于 HealthRecord 的健康等级信息来计算任务的健康积分,这导致了双向的依赖关系。

提取中介者的实现

为消除 HealthRecordHealthTask 的直接依赖,引入中介者类 HealthPointMediator。该中介者类负责协调 HealthRecordHealthTask 的交互,并提供了计算任务健康积分的方法。

public class HealthPointMediator {private HealthRecord record;public HealthPointMediator(HealthRecord record) {this.record = record;}public Integer calculateHealthPointForTask(HealthTask task) {Integer healthLevel = record.getHealthLevel();Integer initialHealthPoint = task.getInitialHealthPoint();Integer healthPoint = 12 / healthLevel + initialHealthPoint;return healthPoint;}
}

简化的 HealthTask

为了减少 HealthTaskHealthRecord 的依赖,可简化 HealthTask 类的实现。现在它专注于任务的描述和初始化积分,不再直接引用 HealthRecord

public class HealthTask {private String taskName;private Integer initialHealthPoint;public HealthTask(String taskName, Integer initialHealthPoint) {this.taskName = taskName;this.initialHealthPoint = initialHealthPoint;}public String getTaskName() {return taskName;}public Integer getInitialHealthPoint() {return initialHealthPoint;}
}

测试用例示例

编写了一个简单的测试用例来验证 HealthPointMediator 的功能,确保它能正确计算每个任务的健康积分。

public class HealthPointTest {public static void main(String[] args) {HealthRecord record = new HealthRecord();record.addTask("忌烟酒", 5);record.addTask("一周慢跑三次", 4);record.addTask("一天喝两升水", 2);record.addTask("坐1小时起来活动5分钟", 2);record.addTask("晚上10点按时睡觉", 3);record.addTask("晚上8点之后不再饮食", 1);HealthPointMediator mediator = new HealthPointMediator(record);List<HealthTask> tasks = record.getTasks();for (HealthTask task : tasks) {Integer healthPoint = mediator.calculateHealthPointForTask(task);System.out.println("任务:" + task.getTaskName() + ",积分:" + healthPoint);}}
}

通过提取中介者的方法,我们成功地消除了 HealthRecordHealthTask 之间的循环依赖关系。中介者模式使得系统更加灵活和可扩展,同时降低了类之间的耦合度,提高了代码的可维护性和可读性。这种设计方式不仅符合面向对象设计的原则,也使得系统更易于理解和维护。

(三)具体解决方案二:转移业务逻辑

这种方法的实现思路在于提取一个专门的业务组件来完成对等级的计算过程。这样,HealthTask原有的对HealthRecord的依赖就转移到了对这个业务组件的依赖,而这个业务组件本身不需要依赖任何对象。

转移业务逻辑的实现

提取一个专门的业务组件 HealthLevelHandler,负责计算健康等级而不依赖于任何其他对象。这样一来,HealthTask 类的原有对 HealthRecord 的依赖转移到了对 HealthLevelHandler 的依赖,从而消除了循环依赖。

public class HealthLevelHandler {private Integer taskCount;public HealthLevelHandler(Integer taskCount) {this.taskCount = taskCount;}public Integer getHealthLevel() {if (taskCount > 5) {return 1;} else if (taskCount < 2) {return 3;} else {return 2;}}
}

改造后的 HealthRecord

HealthRecord 类现在封装了对 HealthLevelHandler 的创建过程,并提供了获取健康任务列表的方法。

public class HealthRecord {private List<HealthTask> tasks = new ArrayList<>();public void addTask(String taskName, Integer initialHealthPoint) {HealthTask task = new HealthTask(taskName, initialHealthPoint);tasks.add(task);}public HealthLevelHandler getHealthPointHandler() {return new HealthLevelHandler(tasks.size());}public List<HealthTask> getTasks() {return tasks;}
}

改造后的 HealthTask

HealthTask 类改为接受 HealthLevelHandler 对象作为参数,并利用其计算任务的健康积分。

public class HealthTask {private String taskName;private Integer initialHealthPoint;public HealthTask(String taskName, Integer initialHealthPoint) {this.taskName = taskName;this.initialHealthPoint = initialHealthPoint;}public Integer calculateHealthPointForTask(HealthLevelHandler handler) {Integer healthPointFromHealthLevel = 12 / handler.getHealthLevel();return initialHealthPoint + healthPointFromHealthLevel;}public String getTaskName() {return taskName;}
}

测试用例示例

编写一个简单的测试用例来验证改造后的 HealthRecordHealthTask 的功能。现在,系统中不存在任何循环依赖,且代码更易于理解和维护。

public class HealthPointTest {public static void main(String[] args) {HealthRecord record = new HealthRecord();record.addTask("忌烟酒", 5);record.addTask("一周慢跑三次", 4);record.addTask("一天喝两升水", 2);record.addTask("坐1小时起来活动5分钟", 2);record.addTask("晚上10点按时睡觉", 3);record.addTask("晚上8点之后不再饮食", 1);HealthLevelHandler handler = record.getHealthPointHandler();List<HealthTask> tasks = record.getTasks();for (HealthTask task : tasks) {Integer healthPoint = task.calculateHealthPointForTask(handler);System.out.println("任务:" + task.getTaskName() + ",积分:" + healthPoint);}}
}

通过转移业务逻辑的方法,我们成功消除了 HealthRecordHealthTask 之间的循环依赖。通过引入 HealthLevelHandler 业务组件,我们将等级计算的责任集中在一个地方,简化了系统的设计并提高了其灵活性和可维护性。这种设计方式符合单一职责原则,使得各个类的功能更加清晰和独立。

(四)具体解决方案三:采用回调接口

所谓回调本质上就是一种双向调用模式,也就是说,被调用方在被调用的同时也会调用对方。在实现上,我们可以提取一个用于计算等级的业务接口,然后让HealthRecord去实现这个接口。这样,HealthTask在计算积分时只需要依赖这个业务接口,而不需要关心这个接口的具体实现类。

使用回调接口的实现

首先定义了一个名为 HealthLevelHandler 的接口,该接口包含了计算健康等级的方法声明,作为回调接口使用。接着,HealthRecord 类实现了这个接口,并提供了具体的等级计算逻辑。在创建 HealthTask 对象时,我们将 HealthRecord 对象作为参数传入 HealthTask 的构造函数,并在 HealthTask 中使用 HealthLevelHandler 接口来获取健康等级信息,从而消除了对 HealthRecord 的直接依赖。

HealthLevelHandler 接口的定义
public interface HealthLevelHandler {Integer getHealthLevel();
}
改造后的 HealthTask

HealthTask 类不再直接依赖 HealthRecord,而是依赖 HealthLevelHandler 接口,并通过该接口获取健康等级信息来计算任务的健康积分。

public class HealthTask {private String taskName;private Integer initialHealthPoint;private HealthLevelHandler handler;public HealthTask(String taskName, Integer initialHealthPoint, HealthLevelHandler handler) {this.taskName = taskName;this.initialHealthPoint = initialHealthPoint;this.handler = handler;}public Integer calculateHealthPointForTask() {Integer healthPointFromHealthLevel = 12 / handler.getHealthLevel();return initialHealthPoint + healthPointFromHealthLevel;}public String getTaskName() {return taskName;}
}
改造后的 HealthRecord

HealthRecord 类实现了 HealthLevelHandler 接口,并提供了具体的健康等级计算逻辑。在创建 HealthTask 对象时,将 this 作为 HealthLevelHandler 的实例传入 HealthTask 的构造函数。

public class HealthRecord implements HealthLevelHandler {private List<HealthTask> tasks = new ArrayList<>();@Overridepublic Integer getHealthLevel() {if (tasks.size() > 5) {return 1;} else if (tasks.size() < 2) {return 3;} else {return 2;}}public void addTask(String taskName, Integer initialHealthPoint) {HealthTask task = new HealthTask(taskName, initialHealthPoint, this);tasks.add(task);}public List<HealthTask> getTasks() {return tasks;}
}

测试用例示例

编写一个简单的测试用例来验证改造后的 HealthRecordHealthTask 的功能。现在,系统中不存在任何循环依赖,且代码更易于理解和维护。

public class HealthRecord implements HealthLevelHandler {private List<HealthTask> tasks = new ArrayList<>();@Overridepublic Integer getHealthLevel() {if (tasks.size() > 5) {return 1;} else if (tasks.size() < 2) {return 3;} else {return 2;}}public void addTask(String taskName, Integer initialHealthPoint) {HealthTask task = new HealthTask(taskName, initialHealthPoint, this);tasks.add(task);}public List<HealthTask> getTasks() {return tasks;}
}

通过引入 HealthLevelHandler 接口,HealthTask 类不再直接依赖于 HealthRecord,而是依赖于一个通用的接口,提高了系统的灵活性和可维护性。这种设计方式符合面向接口编程的思想,使得各个组件之间的耦合度降低,同时也使得代码更具扩展性和测试性。

参考书籍、文献和链接等

如何有效识别和解决代码中存在的循环依赖问题?-极客时间

JDepend 的官方网站

GitHub - clarkware/jdepend: A Java package dependency analyzer that generates design quality metrics.

JDepend Task

Managing Your Dependencies with JDepend – Craftsmanship

六、如何解决循环依赖_循环依赖解决方式-CSDN博客

https://jiapan.me/2020/circular-dependence/

https://blog.51cto.com/u_16038001/6159153

中介者模式解决Spring循环依赖_哔哩哔哩_bilibili

Spring Boot 系统学习第四天:Spring循环依赖案例分析_springboot 循环以来例子-CSDN博客

深入理解循环依赖:如何避免和解决

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

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

相关文章

用Python pillow 创建和保存GIF动画

使用pillow库来创建和保存gif GIFs:图形交换格式(gif)是一种位图图像格式&#xff0c;由美国计算机科学家Steve Wilhite于1987年6月15日领导的在线服务提供商CompuServe的一个团队开发。 一个GIF文件通常存储一个图像&#xff0c;但该格式允许在一个文件中存储多个图像。该格…

【Java05】Java中的多维数组

从数组底层运行机制上看&#xff0c;Java没有多维数组一说。所谓多维数组&#xff0c;是说一个引用变量指向的元素也是引用变量。 例如&#xff0c;type[] arrayName是个指向type类型元素的数组。倘若type也是数组引用变量&#xff0c;比如int[]&#xff0c;那么这个数组就可以…

中国银行信息科技运营中心、软件中心春招笔试测评面试体检全记录

本文介绍2024届春招中&#xff0c;中国银行下属各部门统一笔试&#xff0c;以及信息科技运营中心与软件中心各自的面试&#xff0c;以及编程能力测评、体检等相关环节的具体流程、相关信息等。 2024年04月投递了中国银行的信息科技类岗位&#xff0c;一共投递了4个岗位&#xf…

数字孪生定义及应用介绍

数字孪生定义及应用介绍 1 数字孪生&#xff08;Digital Twin, DT&#xff09;概述1.1 定义1.2 功能1.3 使用场景1.4 数字孪生三步走1.4.1 数字模型1.4.2 数字影子1.4.3 数字孪生 数字孪生地球平台Earth-2 参考 1 数字孪生&#xff08;Digital Twin, DT&#xff09;概述 数字孪…

基于自编码器的心电信号异常检测(Pytorch)

代码较为简单&#xff0c;很容易读懂。 # Importing necessary libraries for TensorFlow, pandas, numpy, and matplotlib import tensorflow as tf import pandas as pd import numpy as np import matplotlib.pyplot as plt import copy# Importing the PyTorch library im…

ml307A模块连接阿里云(详细版)

1、需要的信息 MQTT连接参数、订阅或发布的主题、服务器地址、端口1883 服务器地址&#xff1a; alFMz7jnArW.iot-as-mqtt.cn-shanghai.aliyuncs.com 注&#xff1a;重要的信息阿里云信息大家不要透露&#xff0c;写完笔记会及时删除产品及设备&#xff0c;大家用自己的信息…

linux精通 4.1

2.1.3 http服务器实现 目的 reactor应用——webserver webclient 每次上课前 看大纲down code 复习&#xff1a; 不行啊 编译给的代码报错啊 给的最新的不是0430那一版就不行啊 reactor.c:(.text0x254): relocation truncated to fit: R_X86_64_PC32 against symbol begin de…

《QT实用小工具·七十一》基于Qt+Qml开发的文件传输工具

1、概述 源码放在文章末尾 该项目基于QTQML实现了文件传输的功能&#xff0c;可以在局域网环境下使用(热点)&#xff0c;扫描使用UDP&#xff0c;传输使用TCP&#xff0c;每一个文件传输使用独立的线程进行处理&#xff0c;高效便捷。 开发环境 使用Qt/Qml开发 QT版本&#x…

Linux服务器上激活conda环境conda: error: argument COMMAND: invalid choice: ‘activate‘

正常我们使用如下来流程&#xff1a; 创建环境&#xff1a;conda create -n 环境名称 激活环境&#xff1a;conda activate 环境名称 但是&#xff0c;在Linux服务器上&#xff0c;使用conda activate 环境名称&#xff0c;出现如上图所示的报错。conda: error: argument CO…

Excel 常用技巧(六)

Microsoft Excel 是微软为 Windows、macOS、Android 和 iOS 开发的电子表格软件&#xff0c;可以用来制作电子表格、完成许多复杂的数据运算&#xff0c;进行数据的分析和预测&#xff0c;并且具有强大的制作图表的功能。由于 Excel 具有十分友好的人机界面和强大的计算功能&am…

CMSIS-RTOS2简介

本文介绍CMSIS-RTOS2。 1.引入 CMSIS-RTOS2在基于Arm Cortex处理器的设备上运行的实时操作系统内核上指定了通用RTOS接口。应用程序和中间件组件可以使用CMSIS-RTOS2 API在各种软件生态系统中实现更好的代码重用和更简单的集成。 CMSIS-RTOS2还指定了RTOS内核使用的标准OS T…

windows上安装redis,并且用pycharm联通调用测试

在 Windows 上启动 Redis&#xff0c;官网版本不支持windows直接安装&#xff0c;你可以按照以下步骤进行操作&#xff1a; 使用Github Redis 版本启动 Redis 如果你想使用 Redis 在 Windows 上启动 Redis&#xff0c;以下是基本的步骤&#xff1a; 下载 Redis&#xff1a; 访…

自定义starter并发布maven私服

一、搭建nexus私服 nexus就是maven的私有服务器&#xff0c;这个搭建教程可以在网络上找到很多&#xff0c;这里就不赘述了。搭建完成之后再进行下一步 二、本地maven的setting配置文件中配置nexus的用户名和密码 <servers><server><id>nexus-releases<…

索引在手,查询无忧:MySQL索引简介

在数据库的世界里&#xff0c;MySQL作为一款广泛使用的关系型数据库管理系统。在DB-Engines的2024年5月的数据库管理系统流行度排名中得分1084&#xff0c;仅次于老大哥Oracle&#xff0c;足以MySQL在全球数据库市场中占有重要地位&#xff0c;当然MySQL在2009年被Oracle公司收…

解决使用Jmeter进行测试时出现“302“,‘‘401“等用户未登录的问题

使用 JMeter 压力测试时解决登录问题的两种方法 在使用 JMeter 进行压力测试时&#xff0c;可能会遇程序存在安全验证&#xff0c;必须登录后才能对里面的具体方法进行测试&#xff1a; 如果遇到登录问题&#xff0c;通常是因为 JMeter 无法模拟用户的登录状态&#xff0c;导…

表单中的常用元素

10.图像形式上传文件 <input type“image”>定义图像形式的提交。 src 属性和alt属性必须与<input type“image””>结合使用。 input type"image"src"img/l.jpg"alt"submit"/> 11.下拉列表框 <select>标签定义下拉列表框…

数据库管理-第205期 换个角度看23ai(20240617)

数据库管理205期 2024-06-17 数据库管理-第205期 换个角度看23ai&#xff08;20240617&#xff09;1 规范应用开发2 融合总结 数据库管理-第205期 换个角度看23ai&#xff08;20240617&#xff09; 作者&#xff1a;胖头鱼的鱼缸&#xff08;尹海文&#xff09; Oracle ACE Pro…

大量用户中招,远控木马已经潜伏各类在线会议平台

从 2023 年 12 月开始&#xff0c;研究人员发现有攻击者创建虚假 Skype、Google Meet 和 Zoom 网站来进行恶意软件传播。攻击者为安卓用户投递 SpyNote 远控木马&#xff0c;为 Windows 用户投递 NjRAT 和 DCRAT 远控木马。 攻击行动概述 攻击者在单个 IP 地址上部署了所有的虚…

小白入手实现AI客服机器人demo

一、环境准备 1 安装python 2 安装vscode 3 安装相关python库 pip install flask flask_cors openai 4.在vscode里安装TONGYI Lingma(AI编程助手&#xff09; 二、后端搭建 创建一个后端文件夹chatbot&#xff0c;再新建一个app.py的python文件 from flask import Flask, requ…

electron下载失败(electron如何切换镜像源)

打开&#xff1a; 或者&#xff1a; C:\Users\用户名\.npmrc 添加&#xff1a; electron_mirrorhttps://npmmirror.com/mirrors/electron/ 到文件中&#xff0c;保存 方法二&#xff1a; npm config set ELECTRON_MIRROR https://npmmirror.com/mirrors/electron/ ELECTR…