成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

轉轉質檢桌面應用程序的架構演進

開發 架構
本文對轉轉質檢的 EJC 架構做了一些分享,并給出一些實踐經驗,希望能為大家解決類似的問題提供一些幫助。目前 EJC 架構體系已經在質檢業務中上線了多個桌面應用并穩定運行,未來將會覆蓋更多的應用場景,助力業務得到實質發展。

質檢是轉轉履約體系中的重要一環,通過對手機、平板、筆記本、耳機、手表等品類商品的軟硬件功能、外觀成色等進行全方面檢測,為買家、賣家把好質量關,讓二手交易變得更透明、更靠譜,促進綠色消費。

在質檢環節中,通過標準化產線,結合自動化設備、質檢 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),具有不錯的優勢。

2 EJC 架構

簡單說,EJC 技術架構即:Electron(視圖層/用戶層),Java(應用層),C/C++(基礎能力層)。

圖片

2.1 Electron

Electron 是一個基于 Chromium 和 Node.js 的框架,一套多端生成 Windows、macOS 和 Linux 的跨平臺桌面應用程序。

  • 本質是前端技術棧,內置了 Chromium 內核使得應用程序具有最新的 web 標準,開發人員可以專注應用程序的邏輯和界面設計,不用再束手束足做瀏覽器兼容性操作。
  • 整包更新和熱更新,使程序保持最新的狀態,類似混合移動應用(Hybrid APP)的快感。
  • 安全的跨平臺運行環境,可以有效地降低程序崩潰和系統錯誤的機率,實現更加可靠和穩定的應用程序。
  • 豐富的 API 在 C/C++能力的加持下,讓軟硬件結合更加絲滑,擴展能力更進一步。

2.2 Java

Java 應用層,主要包括:

  • 通訊模塊:提供基于 HTTP、WebSocket 等協議的通信能力。
  • 底層交互模塊: 封裝了 Java 調用本地代碼(動態庫)的技術(JNI/JNA)。
  • 數據存儲:使用輕量級數據庫 SQLite 來持久化數據,為數據的高可用及容錯提供基礎能力。
  • 事件監聽:基于 Spring 的事件和監聽機制實現了基于事件驅動的編程模型,有松耦合、高擴展性和可測試性等優點。
  • 業務模塊:必要的業務邏輯處理。
  • 監控模塊:對客戶端的實時運行參數、硬件異常情況等數據進行記錄,定時上報云端。
  • 配置管理:定時從云端拉取最新的配置,覆蓋本地配置。
  • 調度策略:根據設備的歷史狀態,預判硬件(如貨架貨位上的 USB 通訊口、USB 集線器等設備)是否出現故障,當判定故障時,可以優先調度其它設備并將故障信息上報。

2.3 C/C++

基礎能力層,核心 SDK 的實現。提供與 Windows、IOS、安卓、相機、機械臂等底層通用能力。

基于上述說明,在轉轉質檢中,筆者呈現的 EJC 技術架構,如下:

圖片

EJC架構圖

下面重點對 Java 應用層的前端通訊模塊、底層通訊模塊進行介紹。

2.4 前端通訊模塊

在 Java 應用層兼容了 HTTP 協議、WebSocket 協議的通信方式。接下來介紹幾種與前端通訊的方案以及我們在 EJC 架構中的選型和考量:

2.4.1 HTTP 短輪詢

客戶端周期性的向服務器發送請求,以獲得最新的數據,這種方式會造成服務器和網絡資源的浪費。適用于實時性要求不高的場景:在 Java 客戶端從云端拉取配置時,采用的就是此機制。

圖片

2.4.2 HTTP 長輪詢

與 HTTP 短輪詢相比,HTTP 長輪詢能夠避免客戶端頻繁向服務器發送請求,節省了網絡和服務器資源的開銷,同時能實現更及時和可靠的數據推送。

圖片

2.4.3 SSE(Server-Sent Events)

本質上是一個 HTTP 長連接,服務端發送給客戶端不是一個數據包,而是一個 stream 流,格式為 text/stream,所以客戶端不會關閉連接,會一直等著服務器發過來新的數據流。適合一些只需要服務端單向推送事件給客戶端的場景。

圖片

在實際的應用場景中,服務端只需要推送一次信息給前端(如:前端調用 Java 服務端獲取系統硬件配置信息),我們選擇 SSE 作為前后端的通信方式,有以下優勢:

  • 比 http 短輪詢性能更好。
  • 比 http 長輪詢更可靠。
  • 比 WebSocket 更輕量。
  • 可以在現有的基礎設施和技術上使用,而不需要進行任何額外的配置或部署。

2.4.4 WebSocket

WebSocket 是基于 TCP 的雙向通信協議,可以實現實時通信。適合實時性要求很高而且需要雙工通信的系統。在實際的應用中,如隱私清除工具,從插入手機到隱私清除完成只需要 3~5 秒,質檢人員需要實時的看到手機狀態的變更,這時候我們選用 Websocket 實時的將數據狀態推送到前端進行展示。

圖片

2.5 底層通訊模塊

Java 調用 C/C++ 有 JNI (Java Native Interface) 與 JNA (Java Native Access) 兩種方式,都是 Java 中用于調用本地底層 SDK 的技術。

下面通過簡單的代碼示例(獲取 IOS 設備名稱)來說明 Java 是如何調用底層 SDK 的。為了節約篇幅,僅展示了部分關鍵代碼。

2.5.1 JNI 介紹和使用

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 <jni.h>
/* Header for class JniDemo */

#ifndef _Included_JniDemo
#define _Included_JniDemo
#ifdef __cplusplus
extern "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
#endif
  • C/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 使用
public class JniDemo {
/**
* 獲取IOS設備的名稱
* @param udid 設備UDID
* @return 設備名稱
*/
public native String getDeviceNameByUDID(String udid);

public static void main(String[] args) {
System.loadLibrary("jniDemo");
JniDemo obj = new JniDemo();
String result = obj.getDeviceNameByUDID("00008110-001518392EE3801E");
System.out.println("Result is " + result);
// Result is iphone 13 pro
}
}

2.5.2 JNA 介紹和使用

JNA 是在 JNI 基礎上實現的編程框架,實現了 Java 類型到 C 類型的自動轉換。Java 開發人員只要在一個 Java 接口中描述目標 native library 的函數與結構,不再需要編寫任何 Native/JNI 代碼,極大的降低了 Java 調用動態庫的開發難度。

  • 編寫 C/C++代碼,聲明頭文件(需要使用 extern “C”關鍵字才能被 JNA 調用)。
#pragma once
#include "pch.h"

#ifndef JNADemoAPI
#define JNADemoAPI __declspec(dllexport)
#endif // !_Included_JnaDemo

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

JNADemoAPI const char* getDeviceNameByUDID(const char *udid);


#ifdef __cplusplus
}
#endif // __cplusplus
  • 實現頭文件,并將其編譯為動態庫。
#include "pch.h"
#include "JnaDemo.h"
#include "IOSDevice/ios_device_pimpl.h"

string IOS_Device_Interface::getDeviceNameByUDID(string udid) {
return ios_device->get_deviceName_by_udid(udid);
}
  • Java 中使用。

首先在項目中引入 JNA 庫:

<dependency>
<groupId>com.sun.jna</groupId>
<artifactId>jna</artifactId>
<version>5.12.1</version>
</dependency>

聲明與動態庫對應的 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 選型和考量

通過上述的示例代碼我們對比了兩種方案的優缺點,并進行了性能測試。


JNI

JNA

優點

本地方法編譯后可以選擇 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 機器上運行得到如下結果:

計算數量(百次)

JNI

JNA

1

1197ms

26957ms

2

2196ms

52800ms

3

2759ms

79260ms

4

4573ms

106377ms

5

6299ms

132482ms

通過上面的對比和性能測試,我們制定了如下選型標準:

  • 自研的 SDK:高優使用 JNI 作為底層通信方式。優勢在于:JNI 的性能更好,底層數據交互的接口由 Java 定義,C/C++開發者可以選擇 C 或 C++進行實現,有更多的選擇性及靈活性。
  • 外部廠商提供的 SDK:優先調用廠商自帶的 SDK。優勢在于:無需 C/C++再次封裝一層動態庫,減少開發資源的投入。

3 EJC 架構的落地

EJC 架構在轉轉質檢已成功落地了多個應用,下面主要介紹 EJC 在 Windows 筆記本質檢工具中的落地。

3.1 項目背景

隨著質檢業務的發展,筆記本質檢量再創新高。早期由 C/C++開發、使用 Qt 構建的筆記本驗機工具已不能滿足業務的需求,主要體現有以下幾點:

  • 維護成本高:代碼的復雜性較高,維護需要開發者投入更多的時間和精力。
  • 覆蓋率低:功能不夠完善,易用性較差,使用覆蓋率低。
  • 移植性差:無法移植到 Mac 平臺。

基于上述的項目背景,我們使用了 EJC 架構來重構筆記本驗機工具。

3.2 架構實現

3.2.1 名詞解釋

  • WMI:Windows Management Instrumentation;是 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 參考鏈接

責任編輯:武曉燕 來源: 轉轉技術
相關推薦

2009-07-17 16:09:29

Swing桌面應用程序

2024-06-13 07:51:08

2010-07-15 11:34:13

應用虛擬化桌面虛擬化基礎架構

2020-10-10 10:30:31

JavaScript開發技術

2023-02-01 10:11:06

轉轉容器日志

2011-03-16 11:04:15

數據結構設計重點信息架構

2024-08-29 14:44:01

質檢埋點

2017-01-10 08:30:01

2020-05-12 10:06:52

JavaScript開發框架

2010-01-04 10:41:14

Silverlight

2011-08-10 11:25:59

ipad信息架構數據結構

2011-07-22 14:08:19

iPad 架構 數據

2023-01-09 17:04:24

2015-02-02 15:46:59

Web應用架構大數據

2019-02-18 15:20:57

微軟瀏覽器Windows

2021-08-23 09:00:00

架構開發技術

2023-07-12 08:33:34

引擎LiteFlow編排

2011-12-23 10:01:29

2020-09-23 14:33:01

Golang桌面開發GUI

2024-02-29 08:32:03

HTTP協議Web服務消息隊列
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 人人叉 | 国产精品久久久久久久午夜片 | 草比av| 97人澡人人添人人爽欧美 | 国产精品一区二区在线播放 | 在线免费看黄 | 中文字幕在线观看视频网站 | 一本一道久久a久久精品蜜桃 | 国产乱码精品一区二区三区中文 | 欧美精品一区二区三区在线播放 | 99国产精品久久久 | 成人a网 | 久久看看 | 日韩一区二区在线看 | 久国产视频 | 久久久成人免费一区二区 | 国产成人精品视频在线观看 | 中文字幕av网 | 久久伊人精品 | 国产一区二区三区在线 | 免费一级黄色录像 | 欧美日韩在线一区二区 | 一级黄色片在线免费观看 | 久久夜视频 | 99热精品在线 | 欧美三级视频 | 国内精品久久久久久 | 日韩精品在线播放 | 日韩视频高清 | 国产精品久久久久久影视 | 99视频在线免费观看 | 日本一区二区三区免费观看 | 国产精品海角社区在线观看 | 久久久国产一区二区三区四区小说 | www国产亚洲精品 | 亚洲综合无码一区二区 | 99热精品在线 | 国产在线精品一区二区 | 在线免费观看成人 | 成人一区二区三区在线 | 最近免费日本视频在线 |