京东金融Android瘦身探索与实践
作者:京东科技 冯建华
一、背景
随着业务不断迭代更新,App的大小也在快速增加,2019年~2022年期间一度超过了117M,期间我们也做了部分优化如图1红色部分所示,但在做优化的同时面临着新的增量代码,包体积一直持续上升**。**包体积直接或间接地影响着下载转化率、安装时间、磁盘空间等重要指标,所以投入精力发掘更深层次的安装包体积优化是十分必要的。根据谷歌商店的内部数据,APK体积每减少10M,平均可增加~1.5%的下载转化率,如图2所示:
图1 京东金融Android版本2019-2022体积变化过程 (红色部分是期间做的部分优化,但是很快就反弹回去了)
图2 谷歌商店应用转化率增加幅度 / 10M [1]
因此2022年9月开始我们针对金融APP进行了瘦身专项整治,在不考虑增量的情况,无删减业务代码的情况下实现从117M瘦身至74M,在本次安装包瘦身过程中我们遇到了不少坑,同时也积累了些经验,在此分享给大家。
二、APK分析
接下来我们会简单分析下 Apk内各组成部分,以及 Apk 作为 ZIP,其标准结构是什么样的,为包瘦身的目标设定及任务拆解提供数据支撑。
2.1 APK内容分析
图3 APK 结构
•classes.dex APK 中可能包含一个或多个 classes.dex 文件,应用程序内的 Java/Kotlin 源码最终会以字节码的方式存在于 classes.dex 文件中。
•resources.arscaapt工具在编译资源会将一些资源或者资源索引打包成resources.arsc。
•res/ 源码工程中 res 目录下除了 values 外的资源文件,这些文件路径同时会记录在 resources.arsc 中。
•lib/ nativeLibraries,即源码工程 jni 目录下的 so 文件,二级目录为 NDK支持的 ABI。
•assets/ 与 res/ 资源目录不同,assets/ 下的资源文件不会在 resources.arsc 中生成查询条目,且 assets/ 下的资源目录可完全自定义,在程序中通过 AssetManager 对象来获取。
•META-INF/该文件夹下主要包含 CERT.SF 和 CERT.RSA 签名文件, 以及 MANIFEST.MF 清单文件。
•AndroidManifest.xml 应用清单文件,用于描述应用基本信息,主要包括应用包名、应用id、应用组件、所需权限、设备兼容性等。
2.2 SDK大小分析
通过我们自研的能效提升平台Pandora[7],可以直观地看到SDK的大小,如图4所示:
图4 SDK大小排序(包含版本号)
图5 SDK中包含的SO库列表及大小
根据SDK分析后结合业务,来判断哪些业务适合做插件化,进而直观的降低包体积。
2.3 ZIP结构分析
可以用zipinfo命令输出压缩包中每个文件的详细信息日志,用法:zipinfo -l --t --h test.apk > test.txt
输出的日志文件打开如图6所示,每个文件的压缩信息一行,包括文件名、原始大小、压缩后大小等指标:
图6 APK内文件信息大小
对以上日志信息进行逐行解析,根据解混淆后的文件名路径、文件类型进行归类统计,即可得出Apk的总览信息,包括各类型文件的数量、总大小、单一文件大小等指标,并建立文件大小索引。
三、瘦身实践
整体实施路径如图7所示,主要分为:
1.常规技术方案,通过Gradle插件(代码无侵入、自动化)在编译时期完成APP瘦身;
2.进阶技术方案,将部分业务线差别性的通过插件化或者SO动态下载的方式就行改造,业务改造的越多,收益越高;
3.业务优化方案,针对业务线的数据埋点,生成访问UV进行排名,将UV较低的业务线反馈架构委员会,评估是否可以进行下线或者通过进阶技术方案(2)进行改造,进而减小包体积。
图7 整体实施路径
3-1 常规技术方案
3-1-1 图片处理
经过上述的APP的剖析,得出占用体积第一大的还是图片,因此将APP所有含SDK内所有图片在编译打包过程中通过瘦身任务自动完成图片优化处理,整体优化方案如图8所示:
图8 图片优化方案
1.多 DPI 优化:
Android 为了适配各种不同分辨率或者模式的设备,为开发者设计了同一资源多个配置的资源路径,app 通过 resource 获取图片资源时,自动根据设备配置加载适配的资源,但这些配置伴随着的问题就是高分辨率的设备包含低分辨率的无用图片或者低分辨率的设备包含高分辨率的无用图片。
一般情况下,针对国内应用市场,App 为了减少包大小,会选用市场占有率最高的一套 dpi(google 推荐 xxhdpi)兼容所有设备。而针对海外应用市场的 APP,大多会通过 AppBundle 打包上传至 Google Play,能够享受动态分发 dpi 这一功能,不同分辨率手机可以下载不同 dpi 的图片资源,因此我们需要提供多套 dpi 来满足所有设备。在项目中,我们的图片有的只有一套 dpi,有的有多套 dpi,针对上述两种场景,我们分别在打包时合并资源、复制资源,减少了包大小。
2.转换为webp格式:
_WebP_是谷歌提供的一种支持有损压缩和无损压缩的图片文件格式,而且可以提供比JPEG或PNG更好的压缩。在Android 4.0(API level 14)中支持有损的WebP图像,在Android 4.3(API level 18)和更高版本中支持无损和透明的WebP图像
因此:我们采用插件在编译时期仅保留针对图片通过Google提供的shell程序进行格式转换,转换成功删除旧的图片,进而达到APK瘦身的效果
3.png压缩
_Pngquant是一个_好用的png压缩工具一个,可以进行有损图片压缩的命令行工具,因此在1和2处理结束后,可以使用_Pngquant_进行二次压缩,达到更优的图片瘦身。
3-1-2 R文件内联优化
DEX里是Java/Kotlin 源码编译后的字节码文件,对DEX的优化其实就是怎么优化字节码文件,DEX中包含大量的资源索引R文件,这里主要讲下如何通过资源ID内联后进行R文件删除,达到APK瘦身的目的:
R文件瘦身的可行性分析
日常开发阶段,在主工程中通过R.xx.xx的方式引用资源,经过编译后R类引用对应的常量会被编译进class中。
setContentView(2131427356);
这种变化叫做内联,内联是java的一种机制(如果一个常量被标记为static final,在java编译的过程中会将常量内联到代码中,减少一次变量的内存寻址)。非主工程中,R类资源ID以引用的方式编译进class中,不会产生内联。
setContentView(R.layout.activity_main);
产生这种现象的原因是AGP打包工具导致的。具体细节,大家可以去查阅一下android gradle plugin在R文件上的处理过程。结论:R类id内联后程序可运行,但并非所有的工程都会自动产生内联现象,我们需要通过技术手段在合适的时机将R类id内联到程序中,内联完成后,由于不再依赖R类文件,则可以将R类文件删除,在应用正常运行的同时,达到包瘦身目的,如图9所示,在编译完成后会产生大量的R文件:
图9 项目R文件生成示意
整体方案如图10所示:
图10 R文件优化流程
注意事项:在替换阶段一定要加入二次检查,防止替换完,运行时出现ResourceNotFind异常,如下所示:
try {int value = RManager.checkInt(type, name);
}catch (Exception e){String errorMsg = "resource is not found(I),className="+className+",fieldName="+owner+"."+name;throw new ResourceNotFoundException(errorMsg);
}
try {int[] value = RManager.checkIntArray(type, name);
}catch (Exception e){String errorMsg = "resource is not found(I[]),className="+className+",fieldName="+owner+"."+name;throw new ResourceNotFoundException(errorMsg);
}
3-1-3 AndResGuard进行资源混淆
1.资源加载过程分析
开发过程中我们通过aapt生成的R.java中的常量来使用资源,而在编译之后使用常量的地方都会被替换为常量的值,如下所示:
final View layout = inflater.inflate(2131165182, container, false);
也就是说我们通过Resource使用一个int数值来查找使用资源。那么Resource是怎么通过int数值找到具体的资源呢?我们解压apk可以看到里面有个resources.arsc文件,这个文件也是由aapt生成,文件中保存着资源id和资源key的映射关系,Resource就是按照这个映射关系找到资源的。
2.resources.arsc:
图11是resources.arsc的里存储的映射关系,resources.arsc可以理解为一个资源映射数据库,根据ID映射其中具体的路径和名称。
图11 resources.arsc解析
通过解压APK后,将资源文件名进行短链处理比如res/layout/hello.xml转换为r/l/a.xml后,然后更改resources.arsc对应的value值,达到整体的瘦身效果。
AndResGuard[5]是微信推出资源优化工具,它的基本思想类似于 ProGuard 中的混淆,可以实现以上方案。
3-1-4 7zip压缩
7zip命令解释:
-t:指定压缩类型,支持7z, xz, split, zip, gzip, bzip2, tar, …
-m:指定压缩算法,默认是Deflate
具体流程如下:
3-1-5 配置CPU架构
根据不同的CPU架构,构建不同的类型的安装包,目前主流设备都是64位机器,因此安卓市场上主要投放的是依据arm64-v8a编译构建的安装包
ndk {abiFilters arm64-v8a
}
3-1-6 arsc 压缩
resources.arsc 的压缩体积收益很高,但对其进行压缩会影响启动速度和内存指标。原因是:系统在加载 arsc 文件时,若 arsc 文件未压缩,可使用 mmap 进行内存映射;若 arsc 文件被压缩了,则需要将其解压缩后读取到RAM 缓冲区,会增加内存使用,也会拖慢启动速度。
官方出于同样的考虑,从 targetSdkVersion>=30后不能用这种方式 开始强制要求resources.arsc ,否则会直接安装失败,因此本文不在展开阐述。
3-1-7 国际化语言处理
京东金融App目前仅在国内市场运营,但是接入的大量SDK中加入了几十种语言一样,导致整个体积变大,经过评估可以通过配置 resConfigs 去除无用的语言资源。
defaultConfig {resConfigs "zh","en"
}
3-1-8 shrinkResources
shrinkResources:编译过程中用来检测并删除无用资源文件,也就是没有引用的资源
minifyEnabled:用来开启删除无用代码,比如没有引用到的代码,所以如果需要知道资源是否被引用就要配合minifyEnabled使用,只有两者都为true时才会起到真正的删除无效代码和无引用资源的目的。
其作用是将未被引用的资源文件替换为一个体积很小的格式文件(仍存在占位体积,同时保留了该资源条目,所以 resources.arsc 体积并不会减少),可通过 res/raw/keep.xml 文件配置 shrinkMode 和白名单。
buildTypes {release {// 不显示LogbuildConfigField "boolean", "LOG_DEBUG", "false"//混淆minifyEnabled true// 移除无用的resource文件shrinkResources trueproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'signingConfig sign.release}
}
3-1-9 编码约束
•尽量少用枚举类型,因为枚举在编译成字节码后,会增加大量体积,如图12所示(22行代码编译后字节码是86行)
图12 枚举类型编译后的字节码对比
•删除不必要的LOG日志输出
3-2 进阶技术方案
SO库动态下载和插件化技术,本质上都属于动态下载的一个范畴,两个方案可以在业务中长期持续使用,在具体使用过程中如何选择,如图13所示:
图13 业务如何选择进阶方案
3-2-1 SO库动态加载
APP中有部分业务不适合做插件化改造,经过拆解发现其中的SO库占比很大,因此可以考虑采用动态下载的方式进行改造,进而实现减小体积。
SO库加载的两种方式
第一种方式我们直接把SO库下载并放到指定目录就可以
第二种方式是通过环境变量设置的目录中进行加载SO库,因此我们需要追加指定的目录到环境变量中,就可以正常加载SO库
System.load("{安全路径}/libxxx.so")
System.load("xxx")
1、如何设置APP中SO库的环境变量位置(借鉴Tinker):
final Field pathListField = ShareReflectUtil.findField(classLoader, "pathList");
final Object dexPathList = pathListField.get(classLoader);final Field nativeLibraryDirectories = ShareReflectUtil.findField(dexPathList, "nativeLibraryDirectories");List<File> origLibDirs = (List<File>) nativeLibraryDirectories.get(dexPathList);
if (origLibDirs == null) {origLibDirs = new ArrayList<>(2);
}
final Iterator<File> libDirIt = origLibDirs.iterator();
while (libDirIt.hasNext()) {final File libDir = libDirIt.next();if (folder.equals(libDir)) {libDirIt.remove();break;}
}
origLibDirs.add(0, folder);final Field systemNativeLibraryDirectories = ShareReflectUtil.findField(dexPathList, "systemNativeLibraryDirectories");
List<File> origSystemLibDirs = (List<File>) systemNativeLibraryDirectories.get(dexPathList);
if (origSystemLibDirs == null) {origSystemLibDirs = new ArrayList<>(2);
}final List<File> newLibDirs = new ArrayList<>(origLibDirs.size() + origSystemLibDirs.size() + 1);
newLibDirs.addAll(origLibDirs);
newLibDirs.addAll(origSystemLibDirs);final Method makeElements = ShareReflectUtil.findMethod(dexPathList, "makePathElements", List.class);final Object[] elements = (Object[]) makeElements.invoke(dexPathList, newLibDirs);final Field nativeLibraryPathElements = ShareReflectUtil.findField(dexPathList, "nativeLibraryPathElements");
nativeLibraryPathElements.set(dexPathList, elements);
2、如何删除指定SO库和整个加载流程,如图14所示:
图14 SO库删除和加载流程
3-2-2 插件化
什么是插件化:
插件化是将一个Apk根据业务功能拆分成不同的子Apk(也就是不同的插件),每个子Apk可以独立编译打包,最终发布上线的是集成后的Apk。在Apk使用时,每个插件是动态加载的,插件也可以进行热修复和热更新。
•宿主:主App可以用来加载插件也成为Host
•插件:插件App,被宿主加载的App,可以跟普通的App一样的Apk文件
什么形式的业务适合插件化改造:
•业务相对独立,与宿主App解耦彻底
•改造成本低,收益相对较高
•占用体积较大
经过一些列评估,视频营业符合以上几点,改造后的效果如图15所示:
图15 视频营业厅插件化改造后效果
3-3 业务优化方案
随着业务越来越多,一些陈旧的业务UV越来越低,因此制定了一套业务下线优化流程,如图16所示:
图16 业务优化方案流程
四、管控
瘦身方案的实施很重要,后续的管控不反弹更重要,我们一边做瘦身治理,另一边探索常态化的管控机制,最终沉淀了一套管控规范和管控机制。管控的目的不是限制业务迭代或者新增代码,而是怎么做到在有限的代码中实现其功能,提升工程师日常编码中的瘦身意识。
4.1 SDK接入规范
为防止SDK无序扩张,制定了SDK准入规范,在保证功能的前提下严控SDK体积大小,最大程度控制APP体积反弹。
4.2 管控流程
图17 管控流程
根据增加内容、删除内容、增大内容、减小内容、重复文件、代码治理等资源文件的变动情况结合治理管控规范等进行治理,打包构建完成会跟历史版本就行差量对比,获取变化的内容来评估是否具有优化空间,并给出优化目标,待优化后重新构建打包集成。
五、成果与后续规划
5.1 成果
通过以上措施,京东金融Android版本经过两个季度5个版本的迭代,从117M到现在的74M(图18),整体一直维持在可控的范围内。同时在接下来的版本迭代中,我们会将APK瘦身常态化,始终维持包体积在可控的范围内。
图18 金融APP瘦身成果
5.2 后续规划
持续技术手段优化:
业务的不断堆积迭代,总会产生一些无用的资源,所以安装包瘦身要定期清理这些无用文件和代码;
做好各个版本的监控,对比版本之间的差异,发现可以在不影响业务情况下,使用技术手段优化。
线上管控平台搭建:
前期采用线下的管控治理,实施起来有点耗时,后续我们会完善线上管控平台的搭建,与整个App发布构建平台进行融合,形成流水线的机制,做好管控。
小结:安装包瘦身的探索还有很长的路走,本文也只是列举了一些常用的瘦身方案,对于庞大的项目除了优化外,还有做好项目之间的治理,持续对APP进行体积优化,提升用户体验。
其实想要全面掌握好 Android 性能优化的话,这些知识点你必须要有所了解,如: 内存优化、网络优化、卡顿优化、存储优化……等,其实除了这些,像Framework 底层原理逻辑话,也需要有一定的了解,为了让大家一次都可以了解全,所以将其整合成名为《Android 性能优化核心知识点手册》和《Android Framework核心知识点手册》,大家可以参考下:
《Android 性能调优核心笔记汇总》:https://qr18.cn/FVlo89
《Android 性能监控框架》:https://qr18.cn/FVlo89
《Android Framework核心知识点手册》:https://qr18.cn/AQpN4J
- 开机Init 进程
- 开机启动 Zygote 进程
- 开机启动 SystemServer 进程
- Binder 驱动
- AMS 的启动过程
- PMS 的启动过程
- Launcher 的启动过程
- Android 四大组件
- Android 系统服务 - Input 事件的分发过程
- Android 底层渲染 - 屏幕刷新机制源码分析
- Android 源码分析实战
相关文章:

京东金融Android瘦身探索与实践
作者:京东科技 冯建华 一、背景 随着业务不断迭代更新,App的大小也在快速增加,2019年~2022年期间一度超过了117M,期间我们也做了部分优化如图1红色部分所示,但在做优化的同时面临着新的增量代码,包体积一直…...

open3d-ml 读取SemanticKITTI Dataset
目录 1. 下载dataset 2. 读取并做可视化 3. 源码阅读 3.1 读取点云数据-bin格式 3.2 读取标注数据-.label文件 3.3 读取配置 3.4 test 3.5 train 1. 下载dataset 以SemanticKITTI为例。下载链接:http://semantic-kitti.org/dataset.html#download 把上面三…...

6.其他函数
1.时间日期类 -- current_date() 返回当前日期 -- date_add(date, n) 返回从date开始n天之后的日期 -- date_sub(date, n) 返回从date开始n天之前的日期 -- datediff(date1, date2) 返回date1-date2的日期差 -- year(date) 返回…...

2023年宜昌市中等职业学校技能大赛 “网络搭建与应用”竞赛题-1
2023年宜昌市中等职业学校技能大赛 “网络搭建与应用”竞赛题 一、竞赛内容分布 “网络搭建及应用”竞赛共分二个部分,其中: 第一部分:企业网络搭建部署项目,占总分的比例为50%; 第二部分:企业网络服…...

Linux权限划分的原则
考察的不仅是一个具体的指令,还考察对技术层面的认知。 如果对 Linux 权限有较深的认知和理解,那么完全可以通过查资料去完成具体指令的执行。更重要的是,认知清晰的程序员可以把 Linux 权限管理的知识迁移到其他的系统设计中。 权限抽象 一…...

PhotoScan拼接无人机航拍RGB照片
目录 背景 拼接步骤 1.新建并保存项目 2.添加照片 3.对齐照片 4.添加标记(Markers) 5.添加地面控制点 6.建立批处理任务 7.使用批处理文件进行批处理 8.导出DEM 9.导出DOM 背景 本文介绍使用地面控制点(GCPs)拼接…...

【设计模式】责任链模式的介绍及其应用
责任链的介绍 责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求&a…...

一些思考关于行业,关于方向,关于人生路线
一些碎碎念 选择与视角工程与科研平台与信息敢问路在何方 选择与视角 两年前的秋招时几乎速通了出现在学校招聘会上的几乎出现的每一个offer,那也是我人生第一次收获到如此多的肯定与选择,为此我在b站上上传了一期就业解读,作为一个冷门到几…...

fbx sdk的使用介绍
我们平时需要围绕fbx写一些小工具,虽说使用ascii格式的fbx可以直接进行字符串解析,并且网上也有一些基于ascii解析的开源库,但在制作一些通用的工具时,使用fbx sdk进行编写肯定是最好的。 1.下载fbx sdk和cmake 要用cmake生成vi…...

mvvm模式
mvvm是Model-View-ViewModel的缩写,是前端的一种架构模式 M - Model,模型 对应data数据 V - View,视图 对应用户界面,DOM元素 VM - ViewModel,视图模型 对应vue实例对象,是连接model和view的桥梁 …...

Spring/SpringBoot常用注解总结
为什么要写这篇文章? 最近看到网上有一篇关于 SpringBoot 常用注解的文章被转载的比较多,我看了文章内容之后属实觉得质量有点低,并且有点会误导没有太多实际使用经验的人(这些人又占据了大多数)。所以,自…...

2023 年第八届数维杯大学生数学建模挑战赛 B 题 节能列车运行控制优化策略
在城市交通电气化进程快速推进的同时,与之相应的能耗增长和负面效应也 在迅速增加。城市轨道交通中的快速增长的能耗给城轨交通的可持续性发展带来 负担。2018 年,北京、上海、广州地铁负荷占全市总负荷的 1.5%-2.5%,成为了 城市电网的最大单体负荷[1]。…...

【Swift】 NSButton的用法和示例
NSButton是macOS开发中常用的控件,用于创建按钮。它有许多用法和需要注意的事项,下面介绍其中的一些。 1. 创建按钮:使用init(frame:)或init(title:action:)初始化按钮 let button NSButton(frame: NSRect(x: 0, y: 0, width: 100, height…...

2023什么蓝牙耳机好?经销商盘点新手必入蓝牙耳机品牌
蓝牙耳机是除手机外我们使用频率最高的数码产品,我做蓝牙耳机经销商五年来,对各个品牌都有深入了解。近期看到很多新手们咨询什么蓝牙耳机好,我给大家盘点一下新手必看的五大蓝牙耳机品牌。 1.JEET Air 2蓝牙耳机 推荐理由:专为舒…...

MySQL基础(二十)MySQL的数据目录
1. MySQL8的主要目录结构 find / -name mysql1.1 数据库文件的存放路径 show variables like datadir; # /var/lib/mysql/1.2 相关命令目录 相关命令目录:/usr/bin 和/usr/sbin。 1.3 配置文件目录 配置文件目录:/usr/share/mysql-8.0(命…...

低代码行业未来如何?大家都真的看好低代码开发吗?
低代码行业未来如何?大家都真的看好低代码开发吗? 是否一定需要开发人员?低代码和无代码平台会取代传统编程吗?低代码/无代码真的是未来吗? 无疑是需要且重要的。今天就来解答为什么低/零代码工具越来越受欢迎…...

mac m2芯片 安装 brew 和cocoapods
Homebrew的安装 /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 这里可能会失败,如 git clone 时候报错 error: RPC failed; curl 92 HTTP/2 stream 5 was not closed cleanly before end of the underlyi…...

SingleR --细胞注释
文章目录 briefExample使用内置的 references使用其他注释好的数据集作为 reference singleR还提供了注释诊断的方法 brief Example The celldex package provides access to several reference datasets (mostly derived from bulk RNA-seq or microarray data)。 The Human…...

【结构与算法】—— 游戏概率常用算法整理 | 游戏中的常见概率设计分析
📢博客主页:肩匣与橘📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!📢本文由肩匣与橘编写,首发于CSDN🙉📢生活依旧是美好而又温柔的,你也是✨ …...

WebRTC系列-适配GPUImage及其他视频处理改造
文章目录 1. GPUImage 的一些改动1.1 GPUImage数据输入源1.1 GPUImage数据输出源2.WebRTC摄像头采集类改造GPUImage使用OpenGL提供了很多的图像处理算法,包括最常用的美颜处理、水印等功能,这些基本的功能如何添加到WebRTC中,本文以美颜为例子,叙述主要的改造流程;同时也适…...

day43—选择题
文章目录 1.A,B两台机器都正常工作,B机器未监听任何端口.如果A机器向B机器80端口发送SYN包,会收到何种类型的回包(D)2.下列哪个IP地址可以分配给一台计算机(D)3.以下哪个ip不和10.11.12.91/28处于同一个子网(D…...

<<和>>操作符、取地址重载、const关键字
文章目录 自定义类型<<和>>重载const关键字取地址重载(类的默认构造函数) 自定义类型<<和>>重载 在内置类型中,<<和>>可以自动识别 在自定义类型冲,运算符重载,<<和>&…...

数学模型,如何计算概率?
既然是数学模型,那应该如何计算呢? 最简单的方法,当然就是用统计学的方法去计算了,简单说来,就是靠输入的上下文进行统计,计算出后续词语的概率,比如「你吃了晚饭了吗」,「你吃了」后面按照概率,名词如「饭」或「晚饭」等概率更高,而不太可能是动词,如「睡」「睡觉…...

【Ehcache技术专题】「入门到精通」带你一起从零基础进行分析和开发Ehcache框架的实战指南(Spring整合ehcache)
带你一起从零基础进行分析和开发Ehcache框架的实战指南(Spring整合ehcache) 回顾一下Ehcache主要的特性 Spring框架所支持的第三方缓存Spring Cache的实现方式Spring Cache基本准备工作定义Ehcache配置文件启用Spring-CacheXML风格的xml代码 JavaConfig注…...

合肥市2023年度高校毕业生“双千培养工程”培训项目学员招募公告
为贯彻落实人社部实施促进高校毕业生等青年就业创业推进计划要求,提升高校毕业生就业技能,拟开展高校毕业生“双千培养工程”培训项目。根据工作计划安排,现面向高校和社会招募学员参加培训,培训方向为大数据应用、PythonAI人工智…...

重写Properties类,实现对properties文件的有序读写,数据追加,解决中文乱码
前言 *.properties文件,是 Java 支持的一种配置文件类型,并且 Java 提供了 properties 类来读取 properties 文件中的信息。文件中以键值对 "键值"的形式,存储工程中会多次重复使用的配置信息,通过“Properties”类来读…...

态势感知与信质、信量
未来的新智能是人机环境系统智能,而人机融合的态势感知是其关键,简单地说,态势感知(situation awareness)就是智能体在“一定时间和空间环境中的元素的感知,对它们的含义的理解,并对他们稍后状态…...

20230508----重返学习-call()与bind()重写-JS中数据类型检测汇总-装箱与拆箱-类的多种继承方案
day-065-sixty-five-20230508-call()与bind()重写-JS中数据类型检测汇总-装箱与拆箱-类的多种继承方案 call()与bind()重写 call()重写 call()的作用例子 let obj {name: 珠峰培训 } const fn function fn(x, y, ev) {console.log(this, x, y, ev)return x y } let res f…...

Node.js对ES6 及更高版本的支持
目录 1、简介 2、默认情况下什么特性随着 Node.js 一起发布? 3、有哪些特性在开发中? 4、移除这个标记(--harmony)吗 5、Node.js 对应 V8 引擎 1、简介 Node.js 是针对 V8 引擎构建的。通过与此引擎的最新版本保持同步&…...

【华为OD机试2023】工作安排 100% C++ Java Python
【华为OD机试2023】工作安排 100% C++ Java Python 前言 如果您在准备华为的面试,期间有想了解的可以私信我,我会尽可能帮您解答,也可以给您一些建议! 本文解法非最优解(即非性能最优),不能保证通过率。 Tips1:机试为ACM 模式 你的代码需要处理输入输出,input/cin接收…...