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

广州建设网站平台/上海网站推广广告

广州建设网站平台,上海网站推广广告,做网站都需要哪些软硬件,哪里有好看的网站本篇文章主要讲解了 ARouter 框架的源码分析,包括其初始化过程、核心方法等。 初始化 在使用ARouter的时候我们都会先进行初始化: ARouter.init(this);我们看下 init() 源码: public static void init(Application application) {// 检查…

本篇文章主要讲解了 ARouter 框架的源码分析,包括其初始化过程、核心方法等。

初始化

在使用ARouter的时候我们都会先进行初始化:

ARouter.init(this);

我们看下 init() 源码:

public static void init(Application application) {// 检查 ARouter 是否已经初始化,避免重复初始化if (!hasInit) {// 获取 logger,并记录初始化开始的日志logger = _ARouter.logger;_ARouter.logger.info(Consts.TAG, "ARouter init start.");// 执行 ARouter 的初始化方法,并将初始化结果赋值给 hasInithasInit = _ARouter.init(application);// 如果初始化成功,执行后续的初始化步骤if (hasInit) {_ARouter.afterInit();}// 记录初始化完成的日志_ARouter.logger.info(Consts.TAG, "ARouter init over.");}
}

真正调用的还是里面的 _ARouter.init()

protected static synchronized boolean init(Application application) {// 将传入的 Application 实例赋值给 mContextmContext = application;// 初始化 LogisticsCenter,通常是用来管理路由路径和目标组件的调度LogisticsCenter.init(mContext, executor);// 记录初始化成功的日志logger.info(Consts.TAG, "ARouter init success!");// 设置初始化标志,标记 ARouter 已初始化hasInit = true;// 创建一个 Handler 用于在主线程中处理消息mHandler = new Handler(Looper.getMainLooper());// 返回初始化成功return true;
}

最终调用了LogisticsCenter的 init() 方法:

public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {// 保存上下文和线程池实例mContext = context;executor = tpe;try {// 记录初始化开始时间long startInit = System.currentTimeMillis();// 加载路由映射loadRouterMap();// 判断是否使用插件进行自动注册if (registerByPlugin) {logger.info(TAG, "Load router map by arouter-auto-register plugin.");} else {Set<String> routerMap;// 如果是调试模式或者是新版本安装,则重新构建路由映射if (ARouter.debuggable() || PackageUtils.isNewVersion(context)) {logger.info(TAG, "Run with debug mode or new install, rebuild router map.");// 获取路由类文件名(这些类是由 arouter-compiler 插件生成的)routerMap = ClassUtils.getFileNameByPackageName(mContext, ROUTE_ROOT_PAKCAGE);// 如果有新的路由映射,保存到 SharedPreferences 中if (!routerMap.isEmpty()) {context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).edit().putStringSet(AROUTER_SP_KEY_MAP, routerMap).apply();}// 更新应用版本信息PackageUtils.updateVersion(context);} else {// 非调试模式且不是新版本时,从缓存中加载路由映射logger.info(TAG, "Load router map from cache.");routerMap = new HashSet<>(context.getSharedPreferences(AROUTER_SP_CACHE_KEY, Context.MODE_PRIVATE).getStringSet(AROUTER_SP_KEY_MAP, new HashSet<String>()));}// 打印路由映射加载完成的日志logger.info(TAG, "Find router map finished, map size = " + routerMap.size() + ", cost " + (System.currentTimeMillis() - startInit) + " ms.");startInit = System.currentTimeMillis();// 遍历所有路由映射,判断并加载对应的组件for (String className : routerMap) {// 判断是否是根元素类,若是则加载到 groupsIndexif (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);}// 判断是否是拦截器类,若是则加载到 interceptorsIndexelse if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);}// 判断是否是提供者类,若是则加载到 providersIndexelse if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);}}}// 打印组件加载完成的日志logger.info(TAG, "Load root element finished, cost " + (System.currentTimeMillis() - startInit) + " ms.");// 检查是否加载到路由映射,如果没有,打印错误日志if (Warehouse.groupsIndex.size() == 0) {logger.error(TAG, "No mapping files were found, check your configuration please!");}// 如果是调试模式,打印路由、拦截器和提供者的数量if (ARouter.debuggable()) {logger.debug(TAG, String.format(Locale.getDefault(), "LogisticsCenter has already been loaded, GroupIndex[%d], InterceptorIndex[%d], ProviderIndex[%d]", Warehouse.groupsIndex.size(), Warehouse.interceptorsIndex.size(), Warehouse.providersIndex.size()));}} catch (Exception e) {// 捕获异常并抛出自定义的 HandlerExceptionthrow new HandlerException(TAG + "ARouter init logistics center exception! [" + e.getMessage() + "]");}
}

上面方法主要实现了:

  • 通过loadRouterMap方法判断是不是通过arouter-register自动加载路由表,如果是通过自动加载的则registerByPlugin=true,这里我们先不管通过arouter-register自动加载的方式
  • 紧接着通过ClassUtils.getFileNameByPackageName(此处用到了线程池、CountDownLatch面试高频考点)获取到apk中前缀为com.alibaba.android.arouter.routes的类,这里面主要是通过判断是不是支持MultiDex,如果不支持MultiDex,扫描所有的dex文件,然后压缩成zip文件,然后通过DexFile.loadDex转化成DexFile对象,如果支持MultiDex,直接new DexFile,然后循环DexFile拿里面的class文件,然后过滤出com.alibaba.android.arouter.routes前缀的class并返回。
  • 拿到了需要的class类后,放到sp里面,方便下次不去扫描apk拿class,更新版本号
  • 将com.alibaba.android.arouter.routes.ARouter$$Root前缀的class类放到Warehouse.groupsIndex中
  • 将com.alibaba.android.arouter.routes.ARouter$$Interceptors前缀的class类放到Warehouse.interceptorsIndex中
  • 将com.alibaba.android.arouter.routes.ARouter$$Providers前缀的class类放到Warehouse.providersIndex中

_ARouter.afterInit

static void afterInit() {// Trigger interceptor init, use byName.interceptorService = (InterceptorService) ARouter.getInstance().build("/arouter/service/interceptor").navigation();}

ARouter.build

下面我们来看ARouter的build方法:

public Postcard build(String path) {return _ARouter.getInstance().build(path);}

返回的是Postcard类型的对象,我们看一下里面的 _ARouter.build()

protected Postcard build(String path, String group, Boolean afterReplace) {// 检查路径(path)和分组(group)是否为空,如果为空则抛出异常if (TextUtils.isEmpty(path) || TextUtils.isEmpty(group)) {throw new HandlerException(Consts.TAG + "Parameter is invalid!");} else {// 如果 afterReplace 为 false,则进行路径替换if (!afterReplace) {// 获取 PathReplaceService 服务实例,该服务用于路径的替换操作PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);// 如果 PathReplaceService 服务实例不为空,则执行路径替换操作if (null != pService) {path = pService.forString(path);  // 调用替换方法替换路径}}// 构建并返回一个 Postcard 对象,使用处理后的 path 和 groupreturn new Postcard(path, group);}
}
  • build 方法:根据传入的路径 path 和分组 group 创建一个 Postcard 对象。
  • 路径替换:如果 afterReplacefalse,则调用 PathReplaceService 服务对路径进行替换。
  • 异常处理:如果 pathgroup 为空,抛出自定义的 HandlerException 异常。
  1. afterReplacefalse:如果 afterReplace 参数为 false,则会进行路径替换。这意味着在构建 Postcard 对象之前,会通过 PathReplaceService 服务来替换路径。这个服务允许开发者自定义路径替换逻辑,例如,根据配置或环境变量动态调整路径。这样做的好处是可以灵活地适应不同的部署环境或业务需求,而无需硬编码路径。
  2. afterReplacetrue:如果 afterReplace 参数为 true,则不会进行路径替换。这意味着直接使用原始的路径来构建 Postcard 对象。这通常用于那些不需要动态路径替换的场景,或者路径已经在其他地方被处理过,不需要再次替换。

示例代码

假设你实现了一个 PathReplaceService,它的作用是根据不同的环境替换路径中的某些部分:

public class PathReplaceServiceImpl implements PathReplaceService {@Overridepublic String forString(String path) {// 假设在生产环境中替换 "/test/" 为 "/prod/"if (BuildConfig.DEBUG) {return path;  // 开发环境不做替换} else {return path.replace("/test/", "/prod/");  // 生产环境进行路径替换}}
}

然后在调用 ARouter 时使用这个服务:

PathReplaceService pService = ARouter.getInstance().navigation(PathReplaceService.class);
if (null != pService) {path = pService.forString(path);  // 使用服务进行路径替换
}

Postcard类

Postcard 类是 ARouter 框架中的一个核心组件,它表示一个路由的实体,包含了路由的所有信息,比如目标路径、分组、传递的数据、动画效果、标志位等。

public final class Postcard extends RouteMeta {// Baseprivate Uri uri;private Object tag;             // A tag prepare for some thing wrong. inner params, DO NOT USE!private Bundle mBundle;         // Data to transformprivate int flags = 0;         // Flags of routeprivate int timeout = 300;      // Navigation timeout, TimeUnit.Secondprivate IProvider provider;     // It will be set value, if this postcard was provider.private boolean greenChannel;private SerializationService serializationService;private Context context;        // May application or activity, check instance type before use it.private String action;

Postcard 类继承自 RouteMeta,是路由的实际载体,包含导航需要的额外信息。

RouteMeta:

public class RouteMeta {// 路由类型,指示目标是 Activity、Fragment 还是 Provider 等private RouteType type;  // 原始类型元素,表示目标路由的原始类型(如 Activity 或 Fragment)private Element rawType;  // 目标页面的 Class 类型,表示路由请求的具体目标类private Class<?> destination;  // 路由路径,唯一标识一个路由,如 "/app/MainActivity"private String path;  // 路由分组,常用于模块化开发,避免路径冲突private String group;  // 路由的优先级,用于在多个路由匹配时,确定优先使用哪个路由private int priority;  // 额外的信息,通常用于存放一些配置信息private int extra;  // 路由参数类型的映射,存储参数名与其类型的对应关系private Map<String, Integer> paramsType;  // 路由的名称,通常用于调试或日志中,便于标识路由private String name;  // 注入的配置,存储需要自动注入的字段信息private Map<String, Autowired> injectConfig;  
}

PostCard.navigation

navigation有很多重载的方法,最终都会走_Arouter.navigation

/*** 导航到 postcard 中路径指定的路由。** @param context 上下文,通常是 Activity 等。*/
public Object navigation(Context context) {return navigation(context, null);
}/*** 导航到 postcard 中路径指定的路由。** @param context 上下文,通常是 Activity 等。* @param callback 导航回调接口。*/
public Object navigation(Context context, NavigationCallback callback) {return ARouter.getInstance().navigation(context, this, -1, callback);
}/*** 导航到 postcard 中路径指定的路由。** @param mContext 上下文,通常是 Activity 等。* @param requestCode `startActivityForResult` 的请求码。*/
public void navigation(Activity mContext, int requestCode) {navigation(mContext, requestCode, null);
}/*** 导航到 postcard 中路径指定的路由。** @param mContext 上下文,通常是 Activity 等。* @param requestCode `startActivityForResult` 的请求码。* @param callback 导航回调接口。*/
public void navigation(Activity mContext, int requestCode, NavigationCallback callback) {ARouter.getInstance().navigation(mContext, this, requestCode, callback);
}

这几个方法会调用ARouter.navigation:

 public Object navigation(Context mContext, Postcard postcard, int requestCode, NavigationCallback callback) {return _ARouter.getInstance().navigation(mContext, postcard, requestCode, callback);}

接着调用_Arouter.navigation:

protected Object navigation(final Context context, final Postcard postcard, final int requestCode, final NavigationCallback callback) {// 获取预处理服务实例PretreatmentService pretreatmentService = ARouter.getInstance().navigation(PretreatmentService.class);// 如果预处理服务存在并且返回的结果为 false,则导航失败,取消导航if (null != pretreatmentService && !pretreatmentService.onPretreatment(context, postcard)) {// 预处理失败,导航被取消return null;}// 设置 postcard 的上下文,如果传入的 context 为 null,则使用 mContextpostcard.setContext(null == context ? mContext : context);try {// 完成路由的物流处理LogisticsCenter.completion(postcard);} catch (NoRouteFoundException ex) {logger.warning(Consts.TAG, ex.getMessage());// 如果启用了调试模式,则显示友好的提示信息给用户if (debuggable()) {runInMainThread(new Runnable() {@Overridepublic void run() {// 弹出提示框,告知没有找到匹配的路由Toast.makeText(mContext, "没有找到匹配的路由!\n" +" 路径 = [" + postcard.getPath() + "]\n" +" 分组 = [" + postcard.getGroup() + "]", Toast.LENGTH_LONG).show();}});}// 如果有回调函数,调用 onLost 方法if (null != callback) {callback.onLost(postcard);} else {// 如果没有回调,则使用全局的降级服务DegradeService degradeService = ARouter.getInstance().navigation(DegradeService.class);if (null != degradeService) {degradeService.onLost(context, postcard);}}return null;}// 如果有回调函数,调用 onFound 方法if (null != callback) {callback.onFound(postcard);}// 如果不是绿色通道,则执行拦截器,可能会导致 ANR 问题if (!postcard.isGreenChannel()) {// 执行拦截器interceptorService.doInterceptions(postcard, new InterceptorCallback() {/*** 继续处理** @param postcard 路由元数据*/@Overridepublic void onContinue(Postcard postcard) {// 调用实际的导航方法_navigation(postcard, requestCode, callback);}/*** 中断处理,管道将在此方法被调用时销毁。** @param exception 中断原因*/@Overridepublic void onInterrupt(Throwable exception) {// 如果有回调,调用 onInterrupt 方法if (null != callback) {callback.onInterrupt(postcard);}// 记录导航失败信息logger.info(Consts.TAG, "导航失败,因拦截器中止 : " + exception.getMessage());}});} else {// 如果是绿色通道,直接执行导航return _navigation(postcard, requestCode, callback);}return null;
}

最后会执行_navigation:

private Object _navigation(final Postcard postcard, final int requestCode, final NavigationCallback callback) {// 获取当前的上下文final Context currentContext = postcard.getContext();// 根据 Postcard 的类型执行不同的导航操作switch (postcard.getType()) {case ACTIVITY:// 如果是 Activity 类型,构建 Intent 对象final Intent intent = new Intent(currentContext, postcard.getDestination());intent.putExtras(postcard.getExtras());  // 设置 extras 数据// 设置 flagsint flags = postcard.getFlags();if (0 != flags) {intent.setFlags(flags);  // 如果有 flags,设置到 intent 中}// 如果当前上下文不是 Activity,需要设置 FLAG_ACTIVITY_NEW_TASKif (!(currentContext instanceof Activity)) {intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);}// 设置 ActionString action = postcard.getAction();if (!TextUtils.isEmpty(action)) {intent.setAction(action);  // 如果有 action,设置到 intent 中}// 在主线程中启动 ActivityrunInMainThread(new Runnable() {@Overridepublic void run() {startActivity(requestCode, currentContext, intent, postcard, callback);}});break;case PROVIDER:// 如果是 Provider 类型,直接返回对应的 Providerreturn postcard.getProvider();case BOARDCAST:case CONTENT_PROVIDER:case FRAGMENT:// 如果是 Broadcast、ContentProvider 或 Fragment 类型Class<?> fragmentMeta = postcard.getDestination();try {// 通过反射创建 Fragment 实例Object instance = fragmentMeta.getConstructor().newInstance();if (instance instanceof Fragment) {((Fragment) instance).setArguments(postcard.getExtras());  // 设置 extras 数据} else if (instance instanceof android.support.v4.app.Fragment) {((android.support.v4.app.Fragment) instance).setArguments(postcard.getExtras());}// 返回创建的 Fragment 实例return instance;} catch (Exception ex) {logger.error(Consts.TAG, "获取 Fragment 实例出错, " + TextUtils.formatStackTrace(ex.getStackTrace()));}case METHOD:case SERVICE:default:// 如果是 METHOD 或 SERVICE 类型,或者未知类型,返回 nullreturn null;}return null;
}

参考:阿里ARouter全面全面全面解析(使用介绍+源码分析+设计思路)_arouter init-CSDN博客

已经到底啦!!

相关文章:

【Android】ARouter源码解析

本篇文章主要讲解了 ARouter 框架的源码分析&#xff0c;包括其初始化过程、核心方法等。 初始化 在使用ARouter的时候我们都会先进行初始化&#xff1a; ARouter.init(this);我们看下 init() 源码&#xff1a; public static void init(Application application) {// 检查…...

计算直线的交点数

主要实现思路 整体流程思路&#xff1a; 程序旨在解决给定平面上不同数量的直线&#xff08;无三线共点&#xff09;&#xff0c;求出每种直线数量下所有可能的交点数量&#xff0c;并按要求格式输出的问题。整体通过初始化一个二维数组来存储不同直线数量与交点数量对应的存在…...

STM32基于HAL库的串口接收中断触发机制和适用场景

1. HAL_UART_Receive_DMA函数 基本功能 作用&#xff1a;启动一个固定长度的 DMA 数据接收。特点&#xff1a; 需要预先指定接收数据的长度&#xff08;Size 参数&#xff09;。DMA 会一直工作直到接收到指定数量的数据&#xff0c;接收完成后触发 HAL_UART_RxCpltCallback 回…...

java面试宝典

本文只摘抄部分宝典内容&#xff0c;完整宝典可以在打开下方链接&#xff0c;在网盘获取 ^ _ ^ 链接:java面试宝典 提取码: wxy1 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 链接: java前端面试宝典 提取码: wxy1 复制这段内容后打开百度网盘手机App&#xff…...

Scala—Slice(提取子序列)方法详解

Scala—Slice&#xff08;提取子序列&#xff09;方法详解 在 Scala 中&#xff0c;slice 方法用于从集合中提取一个连续的子序列&#xff08;切片&#xff09;。可以应用于多种集合类型&#xff0c;如 List、Array、Seq 等。 一、slice 方法的定义 slice 根据提供的起始索引…...

【电子通识】案例:USB Type-C USB 3.0线缆做直通连接器TX/RX反向

【电子通识】案例:连接器接线顺序评估为什么新人总是评估不到位?-CSDN博客这个文章的后续。最近在做一个工装项目,需要用到USB Type-C线缆做连接。 此前已经做好了线序规划,结果新人做成实物后发现有的USB Type-C线缆可用,有的不行。其中发现USB3.0的TX-RX信号与自己的板卡…...

【SKFramework框架核心模块】3-5、函数扩展模块

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享QQ群&#xff1a;398291828小红书小破站 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 【Unity3D框架】SKFramework框架完全教程《全…...

使用 EasyExcel 提升 Excel 处理效率

目录 前言1. EasyExcel 的优点2. EasyExcel 的功能3. 在项目中使用 EasyExcel3.1 引入依赖3.2 实体类的定义与注解3.3 工具类方法的实现3.4 在 Controller 中使用 4. 总结5. 参考地址 前言 在日常开发中&#xff0c;Excel 文件的处理是不可避免的一项任务&#xff0c;特别是在…...

【提高篇】3.7 GPIO(七,GPIO开发模型 一)

目录 一,开发模型 二,初始化函数 2.1 时钟使能 一,开发模型 通常我们在进行GPIO相关外设的开发时,往往遵循下面4个步骤,如下: 初始化函数 用于进行时钟设置、参数设置、IO设置、中断设置等。读处理函数 用于从外设读取数据。写处理函数 用于从向外设写数据。中断处理…...

Webpack Tree Shaking 技术原理及应用实战,优化代码,精简产物

前言 在前端开发中&#xff0c;优化代码体积和提升应用性能是至关重要的课题。Webpack 提供了多种优化手段来帮助开发者实现这一目标&#xff0c;Tree Shaking 就是其中一种非常重要的优化技术&#xff0c;它通过在编译阶段移除未被使用的代码模块&#xff0c;从而显著减小最终…...

angular19-官方教程学习

周日了解到angular已经更新到19了&#xff0c;想按官方教程学习一遍&#xff0c;工欲善其事必先利其器&#xff0c;先更新工具&#xff1a; 安装新版版本 卸载老的nodejs 20.10.0&#xff0c;安装最新的LTS版本 https://nodejs.org 最新LTS版本已经是22.12.0 C:\Program File…...

RocketMQ集群部署完整指南

前言 本文将详细介绍RocketMQ集群的部署流程,包括环境准备、安装配置、启动运维等各个方面。 一、环境准备 1.1 系统要求 64位操作系统,建议LinuxJDK 1.8及以上版本源码安装需要Maven 3.2.x1.2 下载RocketMQ 可从以下地址获取RocketMQ安装包: Apache官方开源地址: http://r…...

解决mysql 内存持续上涨问题

问题背景&#xff1a; 业务量不大&#xff0c;Mysql 内存持续上涨&#xff0c;虽然不是很明显&#xff0c;但随着时间慢慢增长&#xff0c;1~2个月左右内存达到80%一旦有一些执行缓慢的sql 内存会快速上去增加/修改大表的字段内存会快速上去 常规操作&#xff1a; Mysql 设置…...

Qt 小项目 学生管理信息系统

主要是对数据库的增删查改的操作 登录/注册界面&#xff1a; 主页面&#xff1a; 添加信息&#xff1a; 删除信息&#xff1a; 删除第一行&#xff08;支持多行删除&#xff09; 需求分析&#xff1a; 用QT实现一个学生管理信息系统&#xff0c;数据库为MySQL 要求&#xf…...

16-01、JVM系列之:内存与垃圾回收篇(一)

JVM系列之&#xff1a;内存与垃圾回收篇&#xff08;一&#xff09; ##本篇内容概述&#xff1a; 1、JVM结构 2、类加载子系统 3、运行时数据区之&#xff1a;PC寄存器、Java栈、本地方法栈一、JVM与JAVA体系结构 JAVA虚拟机与JAVA语言并没有必然的联系&#xff0c;它只是与特…...

聊聊系统的弹力设计-服务器性能指标篇(一)

一、什么是弹性机制 弹性&#xff0c;大家可以轻易的联想到橡胶&#xff0c;可伸缩性是弹性机制的一个很重要的特点&#xff0c;但是实际上弹性不等同于可伸缩性 弹性&#xff08;Elasticity&#xff09; 通常指的是系统能够自动适应负载的变化&#xff0c;即自动扩展和收缩资…...

MQ:kafka-消费者的三种语义

文章目录 前言(一) 创建topic(二) 生产者&#xff08;三&#xff09;消费者1. At-most-once Kafka Consumer2. At-least-once kafka consumer3. 使用subscribe实现Exactly-once4. 使用assign实现Exactly-once 前言 本文主要是以kafka 09的client为例子&#xff0c;详解kafka c…...

中国1km分辨率SSP119情景(SSP119、SSP245 SSP585),模式逐月降水量数据集(2021-2100)

目录 简介 摘要 代码 引用 网址推荐 知识星球 机器学习 干旱监测平台 中国1km分辨率SSP119情景EC-Earth3模式逐月降水量数据集(2021-2100) 简介 该数据集为中国多情景多模式逐月降水量数据&#xff0c;空间分辨率为0.0083333&#xff08;约1km),时间为2021年1月-2100年…...

21天掌握javaweb-->第8天:前后端分离架构与Axios请求

前后端分离架构概念 前后端分离架构是一种现代Web应用开发模式,其中前端和后端分别独立开发和部署,通过API进行数据交互。这种架构使得前端专注于用户界面和用户体验,而后端则专注于业务逻辑和数据处理。 优势 开发效率高:前后端可以并行开发,减少了开发时间。技术栈灵活…...

基于阻塞队列的生产者消费者模型动画演示

一个基于阻塞队列的生产者消费者模型的动画演示&#xff1a; 这是打包好的程序。程序是用 QT 写的。 通过网盘分享的文件&#xff1a;CP模型.7z 链接: https://pan.baidu.com/s/1YjC7YiSqHGqdr6bbffaDWg?pwde6g5 提取码: e6g5 CP模型...

DHCP和BOOTP选项及DHCP协议操作详解

DHCP和BOOTP选项及DHCP协议操作详解 DHCP与BOOTP简介 1. BOOTP&#xff08;Bootstrap Protocol&#xff09; 功能&#xff1a;提供静态配置的IP分配。用途&#xff1a;在早期用于无盘工作站启动时获取IP地址和基本配置。缺点&#xff1a;只能提供静态IP配置&#xff0c;无法动…...

数据结构--链表和单链表详解及实现

一.前言 数据结构思维导图如下&#xff0c;灰色标记的是之前讲过的&#xff0c;本文将带你走近单链表(红色标记部分)&#xff0c;希望大家有所收获&#x1f339;&#x1f339; 二.链表的定义和概念 在讲单链表之前&#xff0c;我们先学习一下链表 2.1 链表的定义 链表是一种…...

vue3基础知识

书接上文&#xff0c;这篇继续来学习vue3的核心语法&#xff0c;可以先看上一篇再来看这篇效果更好。 1. computed computed 用于创建 计算属性&#xff0c;即基于其他响应式数据的值动态计算并缓存的属性。它的主要作用是优化性能和提高代码的可维护性&#xff0c;避免不必要…...

【Linux系统】Ubuntu 缓冲区机制

在Ubuntu中&#xff0c;和其他操作系统有个不一样的机制&#xff1a;缓冲区。这篇文章是对与缓冲区的详细介绍。 在 Ubuntu 中&#xff08;以及其他基于 Linux 的操作系统&#xff09;&#xff0c;缓冲区&#xff08;Buffer&#xff09;是内核用于优化 I/O 操作的重要机制。它…...

ChatGPT 最新推出的 Pro 订阅计划,具备哪些能力 ?

OpenAI 最近推出了 ChatGPT Pro&#xff0c;这是一个每月收费 200 美元的高级订阅计划&#xff0c;旨在为用户提供对 OpenAI 最先进模型和功能的高级访问。 以下是 ChatGPT Pro 的主要功能和能力&#xff1a; 高级模型访问&#xff1a; o1 模型&#xff1a;包括 o1 和 o1 Pro…...

数据结构理论

内容来源青岛大学数据结构与算法课程&#xff0c;链接&#xff1a;数据结构与算法基础&#xff08;青岛大学-王卓&#xff09;_哔哩哔哩_bilibili 绪论 数据结构概述 数据结构和算法的定义&#xff1a;我们如何把现实中大量而复杂的问题以特定的数据类型和特定的存储结构保存…...

es 3期 第14节-全文文本分词查询

#### 1.Elasticsearch是数据库&#xff0c;不是普通的Java应用程序&#xff0c;传统数据库需要的硬件资源同样需要&#xff0c;提升性能最有效的就是升级硬件。 #### 2.Elasticsearch是文档型数据库&#xff0c;不是关系型数据库&#xff0c;不具备严格的ACID事务特性&#xff…...

六安市第二届网络安全大赛复现

misc 听说你也喜欢俄罗斯方块&#xff1f; ppt拼接之后 缺三个角补上 flag{qfnh_wergh_wqef} 流量分析 流量包分离出来一个压缩包 出来一张图片 黑色代表0白色代表1 101010 1000 rab 反的压缩包 转一下 密码&#xff1a;拾叁拾陆叁拾贰陆拾肆 密文&#xff1a;4p4n5758…...

Sarcomere仿人灵巧手ARTUS,20个自由度拓宽机器人作业边界

Sarcomere Dynamics 是一家深度技术先驱&#xff0c;通过开发和商业化仿人机械来改变机器人行业。专注于为科研人员&#xff0c;系统集成商和制造商提供更实惠、更轻便且更灵活的末端执行器替代品。凭借创新的致动器技术&#xff0c;创造了一款紧凑、轻便且非常坚固的机械手Art…...

Django drf 基于serializers 快速使用

1. 安装: pip install djangorestframework 2. 添加rest_framework到您的INSTALLED_APPS设置。 settings.pyINSTALLED_APPS [...rest_framework, ] 3. 定义模型 models.pyfrom django.db import modelsclass BookModel(models.Model):name models.CharField(max_length64)…...