当前位置: 首页 > news >正文

十三、代理模式

文章目录

  • 1 基本介绍
  • 2 案例
    • 2.1 Sortable 接口
    • 2.2 BubbleSort 类
    • 2.3 SortTimer 类
    • 2.4 Client 类
    • 2.5 Client 类的运行结果
    • 2.6 总结
  • 3 各角色之间的关系
    • 3.1 角色
      • 3.1.1 Subject ( 主体 )
      • 3.1.2 RealObject ( 目标对象 )
      • 3.1.3 Proxy ( 代理 )
      • 3.1.4 Client ( 客户端 )
    • 3.2 类图
  • 4 动态代理的使用
    • 4.1 JDK 动态代理
      • 4.1.1 实现动态代理的步骤
      • 4.1.2 代码演示
    • 4.2 CGLIB 动态代理
      • 4.2.1 实现动态代理的步骤
      • 4.2.2 代码演示
  • 5 注意事项
  • 6 优缺点
  • 7 适用场景
  • 8 总结


1 基本介绍

代理模式(Proxy Pattern)是一种 结构型 设计模式,它在 不改变原有对象结构 的基础上,通过为其提供代理,来 增强对象的功能

代理模式分为 静态代理动态代理,本文着重讲解 静态代理,对于 动态代理,由于其实现非常复杂,所以本文只介绍如何使用 动态代理

2 案例

本案例使用 静态代理 实现了对冒泡排序进行计时的功能。

2.1 Sortable 接口

public interface Sortable { // 排序接口,实现它之后就能对 int 数组进行排序void sort(int[] nums); // 对 int 数组进行升序排序
}

2.2 BubbleSort 类

public class BubbleSort implements Sortable { // 冒泡排序@Overridepublic void sort(int[] nums) {for (int i = nums.length - 1; i > 0; i--) {for (int j = 0; j < i; j++) {if (nums[j] > nums[j + 1]) {int temp = nums[j];nums[j] = nums[j + 1];nums[j + 1] = temp;}}}}
}

2.3 SortTimer 类

public class SortTimer implements Sortable { // 排序计时器private Sortable sortable;public SortTimer(Sortable sortable) {this.sortable = sortable;}@Overridepublic void sort(int[] nums) {long start = System.currentTimeMillis(); // 记录排序的起始时间sortable.sort(nums);long end = System.currentTimeMillis(); // 记录排序的终止时间System.out.println("排序花费的时间为 " + (end - start) + " ms");}
}

2.4 Client 类

import java.util.Random;public class Client { // 客户端,测试了冒泡排序的计时功能public static void main(String[] args) {Sortable sortable = new SortTimer(new BubbleSort());sortable.sort(generateRandomArray(10000));}// 生成随机的 int 数组,长度为 length,用于测试排序private static int[] generateRandomArray(int length) {int[] arr = new int[length];Random random = new Random();for (int i = 0; i < length; i++) {arr[i] = random.nextInt(100);}return arr;}
}

2.5 Client 类的运行结果

运行结果大概为 47 毫秒,这与电脑的性能也有一定的关系。

排序花费的时间为 47 ms

2.6 总结

在没有修改 BubbleSort 类的 sort() 方法的代码的前提下,通过代理类 SortTimer,实现了对 sort() 的功能增强——增加计时功能。唯一不好的一点是需要自己实现代理类,比较麻烦。

3 各角色之间的关系

3.1 角色

3.1.1 Subject ( 主体 )

该角色负责 定义 RealObject 应该具有的 方法,Proxy 也实现 Subject 中定义的方法,从而 使 RealObject 和 Proxy 具有一致性。本案例中,Sortable 接口扮演该角色。

3.1.2 RealObject ( 目标对象 )

该角色负责 实现 Subject 定义的 方法,具备基础的功能。本案例中,BubbleSort 类扮演该角色。

3.1.3 Proxy ( 代理 )

该角色负责 使用内部聚合的 RealObject 对象实现 Subject 定义的 方法,并 对 RealObject 对的功能作一定的增强。本案例中,SortTimer 类扮演该角色。

3.1.4 Client ( 客户端 )

该角色负责 调用 Subject 定义的方法完成业务。本案例中,Client 类扮演该角色。

3.2 类图

alt text
说明:虽然图中没有指出 Client 使用了 Proxy 和 RealObject,但实际上 Client 只在创建对象时使用了它们。

4 动态代理的使用

在 Java 中,动态代理主要有两种实现方式:

  • JDK 动态代理:通过 实现 目标对象实现的 接口 来生成代理类,当目标对象没有实现的接口时,这种方法无法使用。
  • CGLIB 动态代理:通过 继承 目标对象的类来生成代理类,不需要目标对象实现接口。

这两种方式都是通过 反射 的机制在 运行时 创建具体的代理类,不需要像静态代理那样硬编码,只不过会延缓应用程序的启动。

4.1 JDK 动态代理

JDK 动态代理是 Java 原生支持 的代理方式,要求目标类必须实现至少一个接口,其核心是 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口。

4.1.1 实现动态代理的步骤

  1. 定义一个(或多个)接口 和 其实现类(目标对象的类)。
  2. 创建一个实现了 InvocationHandler 接口的 处理器类,用于处理代理对象上的方法调用。
  3. 使用 Proxy.newProxyInstance() 方法 创建代理对象,该方法需要三个参数:类加载器实现的接口列表InvocationHandler 对象实例

4.1.2 代码演示

以上面为冒泡排序计时为例,Sortable 接口、BubbleSort 类不变,只需要修改 SortTimer 类、Client 类的代码,测试的结果没有明显变化。

SortTimer 类:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;// 排序计时器,实现了 InvocationHandler 接口的处理器类
public class SortTimer implements InvocationHandler {private Sortable sortable;public SortTimer(Sortable sortable) {this.sortable = sortable;}// 获取 Sortable 的代理对象public static Sortable getProxy(Sortable sortable) {return (Sortable) Proxy.newProxyInstance(sortable.getClass().getClassLoader(), // 获取 sortable 的类加载器sortable.getClass().getInterfaces(), // 获取 sortable 实现的接口// 创建一个新的 SortTimer 对象,要求这个对象的类实现 InvocationHandler 接口new SortTimer(sortable));}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long start = System.currentTimeMillis(); // 记录排序的起始时间Object res = method.invoke(sortable, args);long end = System.currentTimeMillis(); // 记录排序的终止时间System.out.println("排序花费的时间为 " + (end - start) + " ms");return res;}
}

Client 类:

import java.util.Random;public class Client { // 客户端,测试了冒泡排序的计时功能public static void main(String[] args) {Sortable sortable = SortTimer.getProxy(new BubbleSort());sortable.sort(generateRandomArray(10000));}// 生成随机的 int 数组,长度为 length,用于测试排序private static int[] generateRandomArray(int length) {int[] arr = new int[length];Random random = new Random();for (int i = 0; i < length; i++) {arr[i] = random.nextInt(100);}return arr;}
}

4.2 CGLIB 动态代理

CGLIB 动态代理是 Java 中另一种 强大 的代理技术,允许在不实现接口的情况下对类进行代理。CGLIB 通过 继承目标对象的类 来创建代理对象,也就是说,通过这种方式创建的代理对象的类 是 目标对象的类 的 子类。它适用于那些没有实现接口的类。

4.2.1 实现动态代理的步骤

  1. 添加 CGLIB 依赖
    <dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version>
    </dependency>
    
  2. 创建一个实现了 MethodInterceptor 接口的 拦截器类
  3. 使用 Enhancer 来生成代理对象,需要设置 要代理类拦截器对象实例

4.2.2 代码演示

以上面为冒泡排序计时为例,BubbleSort 类可以不实现 Sortable 接口,删除 Sortable 接口,修改 SortTimer 类、Client 类的代码,测试的结果没有明显变化。

注意:最好不要在 JDK 17 的环境下运行如下的代码,会报错,推荐使用 JDK 8。

BubbleSort 类:

public class BubbleSort { // 冒泡排序public void sort(int[] nums) {for (int i = nums.length - 1; i > 0; i--) {for (int j = 0; j < i; j++) {if (nums[j] > nums[j + 1]) {int temp = nums[j];nums[j] = nums[j + 1];nums[j + 1] = temp;}}}}
}

SortTimer 类:

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;// 排序计时器,实现了 MethodInterceptor 接口的拦截器类
public class SortTimer implements MethodInterceptor {private BubbleSort bubbleSort;public SortTimer(BubbleSort bubbleSort) {this.bubbleSort = bubbleSort;}// 获取 BubbleSort 的代理对象public static BubbleSort getProxy(BubbleSort bubbleSort) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(bubbleSort.getClass()); // 设置要代理的类enhancer.setCallback(new SortTimer(bubbleSort)); // 设置拦截器对象实例return (BubbleSort) enhancer.create(); // 创建代理对象}@Overridepublic Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {long start = System.currentTimeMillis(); // 记录排序的起始时间Object res = method.invoke(bubbleSort, args);long end = System.currentTimeMillis(); // 记录排序的终止时间System.out.println("排序花费的时间为 " + (end - start) + " ms");return res;}
}

Client 类:

public class Client { // 客户端,测试了冒泡排序的计时功能public static void main(String[] args) {BubbleSort bubbleSort = SortTimer.getProxy(new BubbleSort());bubbleSort.sort(generateRandomArray(10000));}// 生成随机的 int 数组,长度为 length,用于测试排序private static int[] generateRandomArray(int length) {int[] arr = new int[length];Random random = new Random();for (int i = 0; i < length; i++) {arr[i] = random.nextInt(100);}return arr;}
}

5 注意事项

  • 代理对象与目标对象的接口一致性:代理对象应该与目标对象 实现相同的接口(仅限 静态代理 和 Java 代理),以便在代理对象中可以透明地替换目标对象,客户端代码无需修改即可使用代理对象。
  • 代理行为的合理性:在创建代理对象之前,需要明确代理的目的,例如是为了 延迟加载安全控制日志记录,还是其他目的,代理对象中的代理逻辑应该 合理且高效,避免不必要的复杂性和性能开销。
  • 代理对象的管理:需要妥善管理代理对象的生命周期,确保代理对象在适当的时候被创建和销毁。
  • 静态代理与动态代理的选择
    • 静态代理:如果代理类 在编译时就已经确定,且 不需要频繁更换代理逻辑,可以选择静态代理。
    • 动态代理:如果代理类 在运行时才能确定,或者 需要频繁更换代理逻辑,可以选择动态代理。
  • 避免过度使用:虽然代理模式可以带来很多好处,但也需要避免过度使用。过度使用代理模式可能会增加系统的 复杂性 和维护成本。

6 优缺点

优点

  • 降低系统耦合度:代理模式可以在 客户端目标对象 之间起到一个 中介 的作用,客户端 不直接访问 目标对象,而是通过代理对象来 间接访问,这样可以降低系统的耦合度。
  • 增强系统扩展性:当需要在目标对象上添加新的功能时,可以通过 修改代理类 来实现,而不需要修改目标对象,这提高了系统的可扩展性。
  • 保护目标对象:代理对象可以 控制对目标对象的访问,比如 限制访问权限实现延迟加载(只在需要使用目标对象时创建,其他情况只使用代理对象自身的功能)等,从而保护目标对象不被过度使用或错误使用。
  • 实现远程代理:在 分布式系统 中,远程代理可以 隐藏远程对象的存在细节,使得客户端可以像调用本地对象一样调用远程对象,简化了分布式系统的复杂性。

缺点

  • 增加系统复杂度:引入代理模式后,系统中会增加代理类,这可能会增加系统的复杂度,特别是当系统中存在大量代理类时,会使得系统难以理解和维护。
  • 请求处理速度可能变慢:由于客户端的请求需要 先经过代理对象才能到达目标对象,因此代理模式可能会 降低请求的处理速度,特别是当代理对象需要执行额外的处理逻辑时。
  • 过度使用代理:如果过度使用代理模式,可能会使得系统变得复杂且难以理解。在设计时需要根据实际需求权衡是否使用代理模式。
  • 代理类的编写和维护:编写和维护代理类需要一定的时间和精力,特别是在目标对象接口频繁变化的情况下,代理类也需要进行相应的修改。

7 适用场景

  • 远程代理:当 对象位于远程服务器上 时,可以使用代理模式来进行 远程访问。代理对象可以隐藏实际对象的细节,客户端通过代理对象来访问远程对象,而无需了解远程对象的实现细节。
  • 虚拟代理:当 创建一个对象 需要很长时间 或 消耗大量资源 时,可以使用代理模式来 延迟对象的创建。代理对象会尽量满足各种方法调用,当需要时才真正创建真正的对象。
  • 安全代理:当 需要控制对对象的访问权限 时,可以使用代理模式。代理对象可以控制客户端对真实对象的访问权限。
  • 缓存代理:当 需要缓存对象 时,可以使用代理模式。代理对象可以在获取真实对象之前首先检查缓存中是否存在对象,如果存在则直接返回缓存对象,降低数据库的访问压力,提高系统的响应速度。
  • 日志记录代理:当 需要对对象的方法调用进行日志记录 时,可以使用代理模式。代理对象可以在调用真实对象的方法之前或之后记录日志。

8 总结

代理模式 是一种 结构型 设计模式,在 不改变原有对象结构 的基础上,通过为其 提供代理,来 增强对象的功能,如虚拟代理、安全代理、日志记录代理等功能。使用代理模式可以 降低系统耦合度增强系统扩展性。但是在使用 代理模式 时需要注意不要过度使用,如果过度使用,则会降低系统的响应速度。

代理模式 共有两种:

  • 静态代理:提前在源文件中写代理类(硬编码),实现起来比较简单。
  • 动态代理:不需要提前写代理类,而是在运行程序时通过 反射 动态生成代理类,实现起来比较复杂,但可以使用现有的技术:
    • JDK 动态代理:使用位于 java.lang.reflect 包中的 Proxy 类 和 InvocationHandler 接口。
    • CGLIB 动态代理:添加 CGLIB 的依赖,使用其内部的 MethodInterceptor 接口 和 Enhancer 类。

相关文章:

十三、代理模式

文章目录 1 基本介绍2 案例2.1 Sortable 接口2.2 BubbleSort 类2.3 SortTimer 类2.4 Client 类2.5 Client 类的运行结果2.6 总结 3 各角色之间的关系3.1 角色3.1.1 Subject ( 主体 )3.1.2 RealObject ( 目标对象 )3.1.3 Proxy ( 代理 )3.1.4 Client ( 客户端 ) 3.2 类图 4 动态…...

Unity物理模块 之 2D效应器

本文仅作笔记学习和分享&#xff0c;不用做任何商业用途 本文包括但不限于unity官方手册&#xff0c;unity唐老狮等教程知识&#xff0c;如有不足还请斧正​ 1.什么是效应器 2D 效应器 - Unity 手册 2D 效应器是与 2D 碰撞器一起使用的组件&#xff0c;相当于预先编写好的插…...

一款手机壳凭什么卖800元?Casetify品牌策略全解析 | 品牌出海

Casetify官网 巴黎奥运会&#xff0c;张怡宁的手机壳火了。 张怡宁在现场观战并使用手机的照片在网上流传&#xff0c;不是因为这位奥运前冠军&#xff0c;而是她的手机壳。这款满是「花花绿绿」图案的手机壳&#xff0c;迅速被网友发掘出是Casetify品牌的名为「炫彩花卉」的…...

【Rust光年纪】并发编程利器:探索 Rust 异步库与并行处理工具

构建高效异步应用&#xff1a;Rust 异步库详细解读 前言 在当今软件开发领域&#xff0c;Rust语言作为一种快速、安全和并发性能出色的编程语言&#xff0c;备受开发者青睐。随着Rust生态系统的不断扩大&#xff0c;越来越多的异步库和并行处理工具被引入到Rust开发中。本文将…...

机器学习第一课

1.背景 有监督学习&#xff1a;有标签&#xff08;连续变量&#xff08;回归问题&#xff1a;时间序列等&#xff09;、分类变量&#xff08;分类&#xff09;&#xff09; 无监督学习&#xff1a;没有标签&#xff08;聚类、关联&#xff08;相关性分析&#xff1a;哪些相关…...

C语言典型例题32

《C程序设计教程&#xff08;第四版&#xff09;——谭浩强》 习题2.9 编程序用getchar函数读入两个字符给c1&#xff0c;c2&#xff0c;然后分别用putchar函数和printf函数输出这两个字符。 &#xff08;1&#xff09;变量c1&#xff0c;c2应该定义为字符型或者整型吗&#x…...

第二十五天学习笔记2024.8.9

1、通过frp内网穿透共享数据库信息 [root1 ~]# mysql -p密码 mysql> create user li% identified by 1; mysql> create database test; mysql> grant all on test.* to li; [root1 ~]# tar -xf frp_0.33.0_linux_amd64.tar.gz [root1 ~]# cd frp_0.33.0_linux_a…...

sqlserver将一张表导出成txt

bcp zjwb_sb_20111122.dbo.ep_pb_groupvisitplace out c:/1.txt -n -U sa -P sa...

YOLOv8+DeepSort实现

目录 1&#xff0c;YOLOv8算法简介 2&#xff0c;DeepSort算法介绍 1. SORT目标追踪 3&#xff0c;实现流程 1.检测 2. 生成detections 3. 卡尔曼滤波预测 4.使用匈牙利算法将预测后的tracks和当前帧中的detections进行匹配 5. 卡尔曼滤波更新 4&#xff0c;代码实现 …...

「链表」链表原地算法合集:原地翻转|原地删除|原地取中|原地查重 / LeetCode 206|237|2095|287(C++)

概述 对于一张单向链表&#xff0c;我们总是使用双指针实现一些算法逻辑&#xff0c;这旨在用常量级别空间复杂度和线性时间复杂度来解决一些问题。 所谓原地算法&#xff0c;是指不使用额外空间的算法。 现在&#xff0c;我们利用双指针实现以下四种行为。 //Definition fo…...

【STM32】SPI通信和RTC实时时钟

个人主页~ SPI通信和RTC实时时钟 SPI通信一、简介二、硬件电路三、基本原理四、SPI时序1、时序基本单元2、时序 五、FLASH操作注意事项1、写入操作2、读取操作 六、SPI外设1、简介2、结构 七、传输方式1、主模式全双工连续传输2、非连续传输 RTC实时时钟一、Unix时间戳二、BKP1…...

DAMA学习笔记(十三)-大数据和数据科学

1.引言 大数据不仅指数据的量大&#xff0c;也指数据的种类多&#xff08;结构化的和非结构化的&#xff0c;文档、文件、音频、视频、流数据等&#xff09;&#xff0c;以及数据产生的速度快。数据科学家是指从从数据中探究、研发预测模型、机器学习模型、规范性模型和分析方法…...

【Java】Java 中的 toLowerCase() 方法详解

我最爱的那首歌最爱的angel 我到什么时候才能遇见我的angel 我最爱的那首歌最爱的angel 我不是王子也会拥有我的angel &#x1f3b5; 张杰《云中的angel》 在 Java 编程中&#xff0c;字符串处理是一个非常常见的任务。为了便于开发者操作和格式化字符串&…...

Linux: 进程概念详解

1. 冯诺依曼体系结构 截至目前&#xff0c;我们所认识的计算机&#xff0c;都是有一个个的硬件组件组成 。 【注意】&#xff1a; a. 这里的存储器指的是内存 b. 不考虑缓存情况&#xff0c;这里的CPU能且只能对内存进行读写&#xff0c;不能访问外设(输入或输出设备) c.外…...

【C++】模板详细讲解(含反向迭代器)

欢迎来到我的Blog&#xff0c;点击关注哦&#x1f495; 前言&#xff1a; C的模板在是泛型编程的重要组成部分&#xff0c;编写在不同类型上工作的代码&#xff0c;而无需为每个类型编写重复的代码&#xff0c;这有助于减少代码冗余并提高代码的可维护性。 模板 模板的介绍 …...

haproxy七层代理详解之-完整安装部署流程及负载均衡实现-及热更新方法

一.负载均衡 1.1负载均衡时什么 负载均衡:Load Balance&#xff0c;简称LB&#xff0c;是一种服务或基于硬件设备等实现的高可用反向代理技术&#xff0c;负载均网络流量等)分担给指定的一个或多个后端特定的服务器或设备&#xff0c;从而提高了衡将特定的业务(web服务、公司…...

C++11 bind

bind bind 用来将可调用对象和参数一起进行绑定。可调用对象包括普通函数、全局函 数、静态函数、类静态函数甚至是类成员函数&#xff0c;参数包括普通参数和类成员。绑定后的 结果&#xff0c;可以使用 std::function 进行保存&#xff0c;并延迟调用到我们需要的时候。 绑…...

LeetCode199 二叉树的右视图

前言 题目&#xff1a; 199. 二叉树的右视图 文档&#xff1a; 代码随想录——二叉树的右视图 编程语言&#xff1a; C 解题状态&#xff1a; 成功解决&#xff01; 思路 二叉树层序遍历问题的变种&#xff0c;右视图即意味着二叉树每层的最后一个节点。 代码 /*** Definiti…...

数据赋能(172)——开发:数据挖掘——影响因素、直接作用、主要特征

影响因素 主要影响因素如下&#xff1a; 数据类型与属性&#xff1a; 数据类型和对象的不同属性会使用不同的数据类型来描述&#xff0c;如年龄可能是整数类型&#xff0c;而生日则是日期类型。数据挖掘时需要对不同的数据类型进行不同的处理&#xff0c;这直接影响到挖掘算法…...

Vue:Vue3-TypeScript-Pinia-Vite-pnpm / 基础项目 / 20240807

一、项目技术栈 / 依赖 序号技术栈版本解释1node20.14.02vue 3.4.31 3vite 5.3.4 4TypeScript 5.2.2 5 types/node 22.0.2 解决TypeScript项目中缺少对应模块的类型定义文件的问题6 element-plus 2.7.8 ui组建7 types/js-cookie js-cookie 3.0.6 3.0.5 8 sass 1.77.8 9 hu…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解

JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用&#xff0c;结合SQLite数据库实现联系人管理功能&#xff0c;并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能&#xff0c;同时可以最小化到系统…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

FFmpeg avformat_open_input函数分析

函数内部的总体流程如下&#xff1a; avformat_open_input 精简后的代码如下&#xff1a; int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...

AD学习(3)

1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分&#xff1a; &#xff08;1&#xff09;PCB焊盘&#xff1a;表层的铜 &#xff0c;top层的铜 &#xff08;2&#xff09;管脚序号&#xff1a;用来关联原理图中的管脚的序号&#xff0c;原理图的序号需要和PCB封装一一…...

Appium下载安装配置保姆教程(图文详解)

目录 一、Appium软件介绍 1.特点 2.工作原理 3.应用场景 二、环境准备 安装 Node.js 安装 Appium 安装 JDK 安装 Android SDK 安装Python及依赖包 三、安装教程 1.Node.js安装 1.1.下载Node 1.2.安装程序 1.3.配置npm仓储和缓存 1.4. 配置环境 1.5.测试Node.j…...

五、jmeter脚本参数化

目录 1、脚本参数化 1.1 用户定义的变量 1.1.1 添加及引用方式 1.1.2 测试得出用户定义变量的特点 1.2 用户参数 1.2.1 概念 1.2.2 位置不同效果不同 1.2.3、用户参数的勾选框 - 每次迭代更新一次 总结用户定义的变量、用户参数 1.3 csv数据文件参数化 1、脚本参数化 …...