找回密码
 会员注册
查看: 184|回复: 0

转转质检桌面应用程序的架构演进

[复制链接]

3

主题

0

回帖

10

积分

新手上路

积分
10
发表于 2024-9-20 08:05:50 | 显示全部楼层 |阅读模式
1背景2EJC架构2.1Electron2.2Java2.3C/C++2.4前端通讯模块2.5底层通讯模块3EJC架构的落地3.1项目背景3.2架构实现3.3项目呈现4总结5参考链接质检是转转履约体系中的重要一环,通过对手机、平板、笔记本、耳机、手表等品类商品的软硬件功能、外观成色等进行全方面检测,为买家、卖家把好质量关,让二手交易变得更透明、更靠谱,促进绿色消费。在质检环节中,通过标准化产线,结合自动化设备、质检APP、桌面应用程序等,最终输出全面可信的“质检报告”呈现给用户。其中,桌面应用程序发挥着举足轻重的作用,本文将重点介绍桌面应用程序架构的演进及其落地。1背景转转质检的桌面应用程序,前期主要由Qt构建,C/C++提供底层支持。这些桌面应用的视图层、应用层、以及底层能力支持,均由C/C++开发人员承担全部开发迭代工作。其次随着业务的不断发展,部分桌面应用程序逐渐暴露出拓展性差、迭代难的问题。在转转质检技术团队,除了C/C++开发同学外,还有配套成熟的前端和Java后端,综合来说:对于视图层,前端的技术生态、以及开发人员的技术经验,在视图层开发方面具有很大的优势;在应用层方面,Java技术生态的优势不言而喻,同时Java后端同学对整体业务和系统都有着相对全面深入的了解,简而言之,Java同学在应用层架构设计和落地方面,是非常合适的。综上,基于团队实际,笔者团队对桌面应用程序,提出了新的技术架构——EJC(Electron、Java、C/C++)。该架构的主要优势在于:让C/C++开发同学更偏向于底层能力的研究,发挥更大的价值。Electron本质是前端技术栈,Java同学更理解整体业务,在应用层设计经验方面更擅长;且前端和Java资源更容易灵活调配。Electron和Java本身是跨端的,对于后续质检桌面应用各端的整合(Windows&Mac),具有不错的优势。2EJC架构简单说,EJC技术架构即:Electron(视图层/用户层),Java(应用层),C/C++(基础能力层)。2.1ElectronElectron是一个基于Chromium和Node.js的框架,一套多端生成Windows、macOS和Linux的跨平台桌面应用程序。本质是前端技术栈,内置了Chromium内核使得应用程序具有最新的web标准,开发人员可以专注应用程序的逻辑和界面设计,不用再束手束足做浏览器兼容性操作。整包更新和热更新,使程序保持最新的状态,类似混合移动应用(HybridAPP)的快感。安全的跨平台运行环境,可以有效地降低程序崩溃和系统错误的机率,实现更加可靠和稳定的应用程序。丰富的API在C/C++能力的加持下,让软硬件结合更加丝滑,扩展能力更进一步。2.2JavaJava应用层,主要包括:通讯模块:提供基于HTTP、WebSocket等协议的通信能力。底层交互模块:封装了Java调用本地代码(动态库)的技术(JNI/JNA)。数据存储:使用轻量级数据库SQLite来持久化数据,为数据的高可用及容错提供基础能力。事件监听:基于Spring的事件和监听机制实现了基于事件驱动的编程模型,有松耦合、高扩展性和可测试性等优点。业务模块:必要的业务逻辑处理。监控模块:对客户端的实时运行参数、硬件异常情况等数据进行记录,定时上报云端。配置管理:定时从云端拉取最新的配置,覆盖本地配置。调度策略:根据设备的历史状态,预判硬件(如货架货位上的USB通讯口、USB集线器等设备)是否出现故障,当判定故障时,可以优先调度其它设备并将故障信息上报。2.3C/C++基础能力层,核心SDK的实现。提供与Windows、IOS、安卓、相机、机械臂等底层通用能力。基于上述说明,在转转质检中,笔者呈现的EJC技术架构,如下:EJC架构图下面重点对Java应用层的前端通讯模块、底层通讯模块进行介绍。2.4前端通讯模块在Java应用层兼容了HTTP协议、WebSocket协议的通信方式。接下来介绍几种与前端通讯的方案以及我们在EJC架构中的选型和考量:2.4.1HTTP短轮询客户端周期性的向服务器发送请求,以获得最新的数据,这种方式会造成服务器和网络资源的浪费。适用于实时性要求不高的场景:在Java客户端从云端拉取配置时,采用的就是此机制。2.4.2HTTP长轮询与HTTP短轮询相比,HTTP长轮询能够避免客户端频繁向服务器发送请求,节省了网络和服务器资源的开销,同时能实现更及时和可靠的数据推送。2.4.3SSE(Server-SentEvents)本质上是一个HTTP长连接,服务端发送给客户端不是一个数据包,而是一个stream流,格式为text/stream,所以客户端不会关闭连接,会一直等着服务器发过来新的数据流。适合一些只需要服务端单向推送事件给客户端的场景。在实际的应用场景中,服务端只需要推送一次信息给前端(如:前端调用Java服务端获取系统硬件配置信息),我们选择SSE作为前后端的通信方式,有以下优势:比http短轮询性能更好。比http长轮询更可靠。比WebSocket更轻量。可以在现有的基础设施和技术上使用,而不需要进行任何额外的配置或部署。2.4.4WebSocketWebSocket是基于TCP的双向通信协议,可以实现实时通信。适合实时性要求很高而且需要双工通信的系统。在实际的应用中,如隐私清除工具,从插入手机到隐私清除完成只需要3~5秒,质检人员需要实时的看到手机状态的变更,这时候我们选用Websocket实时的将数据状态推送到前端进行展示。2.5底层通讯模块Java调用C/C++有JNI(JavaNativeInterface)与JNA(JavaNativeAccess)两种方式,都是Java中用于调用本地底层SDK的技术。下面通过简单的代码示例(获取IOS设备名称)来说明Java是如何调用底层SDK的。为了节约篇幅,仅展示了部分关键代码。2.5.1JNI介绍和使用Java语言提供的标准接口,它提供了一组函数和数据类型,允许Java应用程序调用和被C/C++语言调用。JNI通过编写本地方法实现与C/C++语言的交互。使用native关键字声明本地方法。public class JniDemo {    /**     * 获取IOS设备的名称     * @param udid 设备UDID     * @return 设备名称     */    public native String getDeviceNameByUDID(String udid);}通过javah命令,将代码中的native方法生成对应的C语言的头文件。> javah JniDemo// JDK10+已经移除了javah命令工具,使用以下命令> javac JniDemo.java -h outputDir执行上述命令后,将生成一个名为JniDemo.h的C/C++头文件。#include /* Header for class JniDemo */#ifndef _Included_JniDemo#define _Included_JniDemo#ifdef __cplusplusextern "C" {#endif/* * 包含了 getDeviceNameByUDID 方法的声明 * Class:     JniDemo * Method:    getDeviceNameByUDID * Signature: (Ljava/lang/String;)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_JniDemo_getDeviceNameByUDID  (JNIEnv *, jobject, jstring);#ifdef __cplusplus}#endif#endifC/C++实现头文件来实现Java_JniDemo_getDeviceNameByUDID方法,并将其编译为动态库。#include "jnidemo.h"JNIEXPORT jstring JNICALL Java_JniDemo_getDeviceNameByUDID(JNIEnv *env, jobject, jstring udid){    string udid_cpp = jstringTostring(env, udid);    LHW_INFO("udid_cpp = " << udid_cpp);    IOS_Device_Interface idi;    string device_name = idi.get_device_name_by_udid(udid_cpp);    LHW_INFO("device_name = " << device_name);    return stringtojstring(env, device_name.c_str());}java>get_deviceName_by_udid(udid);}Java中使用。首先在项目中引入JNA库:  com.sun.jna    5.12.1声明与动态库对应的Java接口类:/** *  定义动态库接口 */public interface JnaDemo extends Library {    /**     * 与 C/C++ 中的函数名对应     * @param 设备UDID     * @return 设备名称     */    String getDeviceNameByUDID(String udid);}加载动态库并调用方法:/** * 通过 JNA 调用 C/C++ 函数 * */public class JnaDemoTest {    public static void main(String[] args) {        // 加载名为 jnaDemo 动态库        JnaDemo jnaDemo = Native.load("JnaDemo", JnaDemo.class);        // 调用方法并获取结果        String result = jnaDemo.getDeviceNameByUDID("00008110-001518392EE3801E");        System.out.println("Result is " + result);        // Result is iphone 13 pro    }}2.5.3选型和考量通过上述的示例代码我们对比了两种方案的优缺点,并进行了性能测试。JNIJNA优点本地方法编译后可以选择C或C++来实现。调用本地方法时效率相对JNA高。封装了系统常用的动态库,可以直接使用。开发效率相对JNI高,无需Java编写本地方法。缺点开发效率相对较低,需要Java编写本地方法并编译生成C/C++头文件,C/C++需要按照生成的头文件进行编码实现。不支持C++编译生成的动态库,需要在C++接口的上层用C语言进行一次封装。从开发者的角度来说:JNA对Java开发者比较友好,JNI则对C/C++开发者比较友好。同时我们分别用JNI和JNA进行100次到500次读取IOS设备名称的性能测试,得到耗时对比。在8核16G机器上运行得到如下结果:计算数量(百次)JNIJNA11197ms26957ms22196ms52800ms32759ms79260ms44573ms106377ms56299ms132482ms通过上面的对比和性能测试,我们制定了如下选型标准:自研的SDK:高优使用JNI作为底层通信方式。优势在于:JNI的性能更好,底层数据交互的接口由Java定义,C/C++开发者可以选择C或C++进行实现,有更多的选择性及灵活性。外部厂商提供的SDK:优先调用厂商自带的SDK。优势在于:无需C/C++再次封装一层动态库,减少开发资源的投入。3EJC架构的落地EJC架构在转转质检已成功落地了多个应用,下面主要介绍EJC在Windows笔记本质检工具中的落地。3.1项目背景随着质检业务的发展,笔记本质检量再创新高。早期由C/C++开发、使用Qt构建的笔记本验机工具已不能满足业务的需求,主要体现有以下几点:维护成本高:代码的复杂性较高,维护需要开发者投入更多的时间和精力。覆盖率低:功能不够完善,易用性较差,使用覆盖率低。移植性差:无法移植到Mac平台。基于上述的项目背景,我们使用了EJC架构来重构笔记本验机工具。3.2架构实现3.2.1名词解释WMI:WindowsManagementInstrumentation;是Windows系统标准的信息服务。WinAPI:Windows系统提供的底层接口。DLL(C):即EJC中的C,由我们C/C++的同学研发的底层SDK。3.2.2流程描述录入获取数据流程:Electron启动后->后台异步启动Java服务端->开启异步全局扫描笔记本基本数据项注解->获得需读取的电脑属性->调度器分类执行属性获取命令->执行获取命令执行链(可横向扩展获取方式)->数据加工->数据纠错->经SSE通道推送页面渲染。质检流程辅助流程:进入质检流程->请求质检项辅助(某个功能,例如指纹是否正常)->Java调用底层(Dll、Wmi等其他方式)->返回辅助质检结果->页面回传渲染质检项支持结果。3.2.3流程释义执行链:考虑到电脑某项属性需要多种方式获取并互相就纠正,因此可以针对性的配置其特有的执行链,以达到更好的读取准确率,也更加方便扩展。数据纠错:某些属性比如电池健康值;默认采取WMI读取;但是部分厂商没有按照WMI的标准写值,导致获取为空;因此需要调取DLL(C)的其他获取方式作为补充。3.3项目呈现3.3.1录入模块通过Java、C/C++读取笔记本关键信息,获取笔记本基本情况。通过录入功能,辅助一线人员选择系统标品项,同时与质检码进行关联入库。在此基础上产生原始信息与标品ID的映射关系,减少下次相同机型的一个操作步骤,方便一线操作人员在质检相同机型的一个操作便携性。笔记本录入模块3.3.2质检模块通过品牌机型获取系统对应的质检模版,提供自动&辅助质检能力,协助一线质检人员对笔记本的质检能力更快捷、精准。4总结本文对转转质检的EJC架构做了一些分享,并给出一些实践经验,希望能为大家解决类似的问题提供一些帮助。目前EJC架构体系已经在质检业务中上线了多个桌面应用并稳定运行,未来将会覆盖更多的应用场景,助力业务得到实质发展。5参考链接https://www.electronjs.orghttp://java-native-access.github.io/jna/5.13.0/javadoc/overview-summary.html#overview_descriptionhttps://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/types.html#wp914https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events关于作者主要撰稿人:温筠庭,转转履约技术部RD。本文的参与者还有履约质检EJC小组的其他伙伴,一个充满热情、创新的小Team。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-26 01:10 , Processed in 0.855329 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表