前端monorepo大倉共享復雜業務組件最佳實踐

一、背景

在 Monorepo 大倉模式中,我們把組件放在共享目錄下,就能通過源碼引入的方式實現組件共享。越來越多的應用愿意走進大倉,正是為了享受這種組件復用模式帶來的開發便利。這種方式可以滿足大部分代碼復用的訴求,但對于復雜業務組件而言,無論是功能的完整性,還是質量的穩定性都有著更高的要求。?源碼引入的組件提供方一旦發生變更,其所有使用方都需要重新拉取 master 代碼,然后構建發布才能使用新功能,這一特性對物料組件、工具組件以及那些對新功能敏感度較低的業務組件來說是可以接受的,但對于新功能敏感度高的復雜業務組件來說,功能更新的不及時會直接面臨著資損風險。?這類復雜組件也往往面臨著頻繁且快速的迭代發布,這樣一來對于組件使用方而言不光需要訂閱組件更新,而且需要做到及時發布升級才能規避風險,因此只用源碼引入的方式來共享復雜業務組件是耗費精力且不合適的。

圖片

Webpack5 的 MF(Module Federation,模塊聯邦)有著動態集成多個構建的特性能夠規避上述更新的問題。但同樣也是把雙刃劍,一旦遠程組件提供方發掛了,其所有使用方也就不能正常使用,問題所造成的影響面也會被進一步放大。從分布式風險轉化為集中式風險后,權限管控、依賴關系、業務埋點各方面都需要考慮清楚,對組件的能力要求更高。?而且 MF 遠程組件本地開發代理復雜,無插件情況下本地至少要啟兩個服務進行調試,對電腦配置有一定要求,總的來說有一定上手成本。

那么,有沒有一種共享方式能夠保留兩者的優點,又能對缺點進行規避。本文就基于這個目的從以下兩點展開討論:

  • 對于共享復雜業務組件,如何做好權限控制、數據埋點以及平穩降級。
  • 如何規避 MF 遠程組件的穩定性風險、解決組件源碼依賴發布更新等問題,保證穩定性的同時,降低本地開發門檻。

二、大倉下組件共享方式

Monorepo 大倉模式下跨應用共享組件的方式有很多,常用的是源碼引入、模塊聯邦兩種方式。本文不對這兩種方式的原理展開介紹和討論,先簡單介紹下這兩種方式在大倉下的使用方法。

源碼引入組件

這種方式能解決大倉下大部分組件復用的需求,代碼復用的便利性也是大家愿意走進大倉的原因之一。

組件提供

為了區分其他組件,可以在 /業務域/_share/remote-components 目錄下開發遠程組件。dx 是內部大倉的 CLI,cc 命令可以快速生成一個組件模板。

// 區分普通組件,新增一個remote-components組件目錄
cd remote-components && dx cc order-detail

同樣是 Monorepo,大倉組件的創建方式和 Lerna 新建物料組件類似。借助腳手架根據填寫的內容就能生成模版,可以編寫單測去自測組件變更,能一定程度的保證組件的健壯性,避免出現破壞性升級的問題。生成之后的模板目錄結構如下圖。

組件使用

依賴注入、源碼引用

  • package.json 引入依賴,配置?workspace:*,構建時動態去取_share/目錄下最新版本的組件資源。若從穩定性考慮,也可以固定版本號。
/** package.json */
"@demo/order-detail": "workspace:*"/** 業務組件 */
import OrderDetail from '@demo/order-detail'<OrderDetail {...props} />

總結

優點

  • 開發便捷,本地只需啟一個應用就能開發,調試方便。
  • 若組件迭代發掛了,只會影響當前發布的應用,不影響其他使用方,能正常使用該組件,對普通組件和一些對新功能不敏感的業務組件來說是合適的。

缺點

  • 對新功能敏感度較高的復雜業務組件而言,使用方如果要更新版本需要重新拉代碼構建部署,信息同步、發布投入成本較高。
  • 由于大倉特性,代碼變更權限很難做到管控,非組件提供方也能修改代碼,組件 Owner 需要嚴格 CR 變更。

MF遠程組件

umi 4.0.48 +?支持在 umi config 使用 MF 配置來使用 MF 的功能。umi4 可以直接從@umijs/max導出defineConfig,也可以使用@umijs/plugins/dist/mf插件去支持配置 MF 屬性,本質也是對 WebPack Plugin 的封裝,屬性是類似的。不一樣的點在于?Host 不再需要通過配置 Exposes 將組件一個個的暴露出去,而是約定暴露 Exposes 目錄下的組件,十分方便。

需要注意的是,該特性用到了 ES2021 的 Top-Level await,所以瀏覽器必須支持該特性。比如谷歌 Chrome 瀏覽器要在 89 版本以上。?

/** 方法一:使用umijs/max導出的defineConfig */
import { defineConfig } from '@umijs/max';export default defineConfig({// 已經內置 Module Federation 插件, 直接開啟配置即可mf: {remotes: [{name: `remote${MFCode}`,aliasName: 'APP_A',entry: 'xxx/remote.js',},],// 配置 MF 共享的模塊shared,},
});
/** 方法二:使用umijs/plugins/dist/mf的插件 */
import { defineConfig } from 'umi';export default defineConfig({plugins: ['@umijs/plugins/dist/mf'], // 引入插件mf: {remotes: [{name: `remote${MFCode}`,aliasName: 'APP_A',entry: 'xxx/remote.js',},],// 配置 MF 共享的模塊shared,},
});

組件提供

用了該插件后,可在正常目錄結構(/pages)下開發代碼,約定在 Exposes 目錄下新建對應組件引用,然后將其暴露出去。

之前

現在

組件使用

使用方也在 Config 配置?MF,可配置多個 Host,自己也能當 Host。然后使用umijs/maxsafeRemoteComponent?異步注冊組件。

 //config.tsconst APP_A_ENTRIES = {PROD: 'https://prod-a-env.com/xxxx/remote.js',DEV: 'https://dev-a-env.com/xxxx/remote.js',PRE: 'https://pre-a-env.com/xxxx/remote.js',TEST: 'https://test-a-env.com/xxxx/remote.js',
}const APP_B_ENTRIES = {PROD: 'https://prod-b-env.com/xxxx/remote.js',DEV: 'https://dev-b-env.com/xxxx/remote.js',PRE: 'https://pre-b-env.com/xxxx/remote.js',TEST: 'https://test-b-env.com/xxxx/remote.js',
}mf: {name: `remote${DemoCode}`,library: { type: 'window', name: `remote${DemoCode}` },remotes: [{/** app-A遠程組件 */name: `remote${aMFCode}`,aliasName: 'appA',keyResolver: getEnv(),entries: ORDER_ENTRIES,},/** app-B遠程組件 */{name: `remote${bMFCode}`,aliasName: 'appB',keyResolver: getEnv(),entries: IM_ENTRIES,},],shared},
  • 在 moduleSpecifier 配置使用的遠程組件,規則為 Guest Remotes 配置的?${aliasName}和 Host Exposes 目錄下的組件名。
  • 在 FallbackComponent 配置遠程組件加載失敗的兜底。
  • 在 LoadingElement 配置加載遠程組件的過度狀態。

總結

優點

  • 非源碼依賴,Host 組件更新,所有使用者都能馬上同步新版本使用到新功能,節省了訂閱發布的投入。
  • 權限隔離,有 Host 應用權限才能開發組件。

缺點

  • 雖然 umi 已經能夠集成代理了,需要注意資源跨域問題,但開發仍需要至少本地啟兩個項目。
  • 如果 Host 發掛了,所有使用者的對應功能都受影響了。

三、最佳實踐

簡單介紹完兩種大倉組件共享方式,進入本文的正題。

  • 權限管控:復雜業務組件有著完整的功能,內部往往會請求很多接口,接口就伴隨著權限分配的問題,如何不申請組件主系統權限就能將組件集成到自己的系統中。
  • 埋點上報:前端 APM 平臺能夠記錄用戶行為進行上報,用于數據分析。不做任何處理會上報到組件主系統的應用中,組件使用方無法在自己的應用監控中接受這部分埋點數據。
  • 平穩降級:質量問題是重中之重,作為復雜業務組件的使用方不關注組件具體業務邏輯的,但是需要考慮系統的整體穩定性不受引入的組件所影響。

業務權限控制

首先要確認系統權限的結構,大部分系統只用了系統權限校驗,不過一些系統還有服務端的權限校驗。

系統權限原理(401)

通過系統唯一編碼去匹配接口 Header 頭中的系統碼字段的方式去綁定權限組。如下圖所示,左圖是用來配置系統菜單和分配角色的平臺,右圖是沒有匹配權限的接口就會報 401 狀態碼。

同樣的,也是根據系統碼去請求菜單,渲染菜單,這些邏輯大部分都是 umi 樣板間(plugin-proRoute/service/menu)里實現了,可以在 src/.umi 下看到具體實現邏輯,注入 Backstagecode 的邏輯還是需要自己在 Request 配置里實現。

業務權限原理(432)

一些系統除了系統權限外還保留業務權限校驗,此校驗通過 Redis 匹配用戶登陸態進行鑒權。沒有匹配權限就會報 432 狀態碼。

其原理圖如下,可通過 getTicketAuth 接口將登陸態寫入 Redis,第一張圖為 B 平臺,依賴 A 系統登陸。第二張圖為改造后,不再依賴 A 系統登陸,原理還是比較好理解的,就不展開了。?

?

Request方案

根據權限原理可以知道,權限管控問題的核心就是去考慮清楚什么時候該用什么系統碼,而我們塞系統碼的任務都是由 Request 來做的。所以接下來我們先了解下常用的 Request 方案,如果組件雙方的 Request 方式不一致怎么解決。

  • proRequest,通過內部 @xx/umi-request引入。

已經停止維護了,但是一些早期遷移的應用都還在使用 proRequest。App 入口或者 umi config 中配置 proRequest 屬性。

  //config.tsexport default defineConfig({// 其他配置proRequest: {},})//app.tsx
export const proRequest = {prefix: proxyFix,envConfig: {},headers: {backstageCode,},successCodes: [200, '200'],
};
  • Request?、基于 Request 的 crud 庫,通過 @umijs/Max 引入。

目前比較常用的 Request,有 crud 的方法,新遷移的應用都使用這個 Request,后續新應用也優先使用這個方法。

通過 Curd API 為 umi 的 Request 提供能力。

//utilsimport { AxiosRequestConfig, request } from '@umijs/max';
import initCrudApiClass from '@/utils/api';const CrudService = initCrudApiClass<AxiosRequestConfig>(({ url, ...config }) =>request(url as string, config).then((res) => res.data),
);CrudService.registerApiOptions('default', {mapping: {paramsType: {read: 'data',remove: 'data',queryList: 'data',queryPage: 'data',},},
});

通過請求配置攔截器去配置 Headers。

// app.tsxexport const request: RequestRuntimeConfig = {baseURL: proxyFix,// 請求攔截器requestInterceptors: [(c: RequestConfig) => {/** 一些配置 */Object.assign(c.headers, {/** 其他配置 */backstageCode,});return c;},],//響應攔截器responseInterceptors: [(res) => {/** 一些配置 */return res;},],// 錯誤配置errorConfig: {errorHandler: (error) => {return errorhandlerCallback(error as ResponseError);},},
};
  • Axios?、基于 Axios 的?crud 庫,源碼依賴。

原生支持,可以自適應 Request 配置。

功能集成在 utils 包中,需要單獨源碼引入。

"@xxx/utils": "workspace:*"
通過請求配置攔截器去新增headers,會自動獲取backstageCode,支持傳遞去修改
// src/app.tsximport { RuntimeConfig } from '@umijs/max';/*** @param instance - axios 實例,采用原生方式進行配置即可* @param setOptions - 配置函數*/
export const configRequest: RuntimeConfig['configRequest'] = (instance, setOptions) => {instance.interceptors.request.use((c) => {// 默認攜帶了兩個請求頭:accessToken、backstageCodeObject.assign(c.headers as object, {backstageCode,});return c;});setOptions({errorResponseHandler(error) {return undefined;},});
};

組件雙方的 Request 不一致怎么解決

系統 A 的 Reuqest 用的是 umijs/max 的,系統 B 的 Request 用的是 ProRequest。

上面 2 個原理搞清楚了,這個問題也就迎刃而解。

  • 首先,在業務組件中動態初始化 Request 配置,不能用 app.tsx 的配置,接收組件使用方傳過來的系統碼動態注冊 Request 實例。
// 可以通過動態注冊的方式初始化request,使用UmiRequest.requestInit方法。//被用作遠程組件時,從遠端拿到系統碼,通過api改寫headers配置enum BackstageCode {APP_A: 'CODE_A',APP_B: 'CODE_B',APP_C: 'CODE_C'}UmiRequest.requestInit({prefix: proxyFix,headers: {backstageCode: BackstageCode[props.code],},});
  • 然后在提供遠程組件時把依賴提供出去,使用方也不需要去安裝其他版本的 Request。
 // config.tsmf: {name: `remote${mfName}`,library: { type: "window", name: `remote${mfName}` },shared: {/** 其他依賴 */'@du/umi-request': {singleton: true,eager: true,}}}

權限管控最佳實踐

下面的方案都是在跑的方案,都能正常使用,各有優劣,按需使用。

  • 方案一:權限管控在組件提供方。

組件使用方不需要關心頁面權限,但訪問頁面的人需要申請 Host 系統的權限。

對組件提供者很友好,對頁面使用者很不友好,需要申請多個系統權限。

  • 方案二:權限管控在組件使用方,將接口配置在自己的天網子系統下,改寫系統碼,需要注意資源跨域問題。

訪問頁面的人對權限無感知,但對開發者無論是組件使用方還是提供方都要做更多的處理。使用者需要關心頁面權限,并及時配置,組件提供方要感知是哪個系統在用組件,并把 Request 配置及時修改,不然就走到組件主系統的權限里去了。?總結一句就是所有工作量都來到了組件維護者這邊,不過不用擔心,掌握上面說到的幾點原理就能游刃有余地處理權限問題。

埋點上報

數據上報 SDK 也都支持系統碼作為上報應用,同理可在 monitor.monitorInit 注冊實例時傳遞系統碼作為參數。

  • 支持使用方通過傳遞 Source 或者上報配置給組件。
    • Host 根據 Source 幫助 Guest 維護上報配置,配置維護在 Host。
    • Host 根據 Guest 的傳遞的自定義配置,直接集成配置進行上報。
  • 也可通過接口調用維度去分析數據。

降級方式

  • 對于發掛的應用做到自動降級。
    • FallbackComponent

前面說到 umi 支持配置遠程組件降級方案,將源碼依賴的組件傳給 SafeRemoteComponent 的 FallbackComponent 屬性,當遠程組件掛載失敗可以直接加載本地組件用作降級。

import { safeRemoteComponent } from '@umijs/max';
import { Spin } from 'poizon-design';
import { SharedOrderDetail } from '@xxx/order-detail'
import React from 'react';const MFOrderDetail = safeRemoteComponent<React.FC<Props>>({moduleSpecifier: 'Demo/OrderDetail',/** 將源碼依賴的組件 */fallbackComponent: <SharedOrderDetail {...props} />,loadingElement: <Spin></Spin>,
});const OrderDetailModule: React.FC<Props> = (props) => <MFOrderDetail key={props.name} {...props} />export default OrderDetailModule;
  • 開關

對于遠程組件掛載成功,但是功能不能正常使用的可用下面的方法。

對于新功能未達到業務要求需要支持手動回退版本的降級。

使用前端配置平臺開關,開關開啟走 MF 組件,開關關閉走源碼引入組件,后續可用主干研發模式替代,也可通過監控告警閾值去做到自動降級。?

四、源碼依賴結合MF模式

先源碼引入后MF

在 _share/remote-components 目錄下進行業務組件開發, 之后在子應用 Expose 目錄下通過源碼引入的方式使用組件,再暴露出去。用源碼依賴的方式注入 MF 暴露的組件中,可以適配自動降級方案,代碼片段如下。

先MF后源碼引入

在子應用編寫組件,通過 Expose 方式提供遠程組件,使用 Webpack Plugin 復制文件或者 Pre-Commit Hooks 的方式將組件代碼同步至 Share 目錄下,這樣能夠利用源碼依賴不會自動更新版本的特性用作降級,優先使用實時更新的 MF 遠程組件,降級使用源碼引入的大倉組件,而且這個方法也能夠管控開發權限。

五、未來&總結

未來

結合主干研發模式

新邏輯使用 MF,老邏輯使用源碼依賴。

import FWIns from '@/config/fw-config';const fw = FWIns.init({branchName: 'feature-base-main-xxx-xxx',
});await fw.feature(async () => {/** 新邏輯,使用MF*/<MFComponent />},async () => {/** 老邏輯,使用源碼依賴*/<SharedComponent />},
);

需要開發一些插件

  • 為了提升開發效率,需要一個將子應用的業務代碼同步至是 Share 目錄下的 WebPack 插件或者 Git Hooks。
  • 目前接入 MF 不管是 Host 還是 Guest 都需要在 umi config 配置一些東西,這些配置大部分是重復的,可以通過插件方式注入,降低接入成本。
  • 源碼依賴大文件對構建速度有影響,需進一步比對構建產物進行優化。

總結

本文首先介紹了兩種大倉下常用的共享組件方式,進行優劣勢的分析,并對其大倉內外的用法進行比對。

  • 源碼引入:開發便捷,調試方便,組件穩定性較高;但對于復雜業務組件代碼成本較高,開發權限管控較難。
  • Module Federation:動態集成,節省訂閱發布成本,權限隔離;過于依賴組件 Host 穩定性,調試較復雜。

然后對于共享復雜業務組件的一些注意事項提出解決方案。

  • 權限管控:組件權限可以管控在使用方也可以管控在提供方。如果管控在使用方,可以通過系統碼去動態初始化 Request 實例,對于組件雙方 Request 方式不一致,可通過 MF Shared 依賴的方式解決。
  • 埋點上報:同樣的,通過接收系統碼去實例化監控 SDK,不做任何處理就上報到組件得主系統的應用中。
  • 平穩降級:可以使用 FallbackComponent 對加載遠程組件失敗的情況做到自動降級,對于遠程組件加載成功,功能發掛了或者新功能未達到業務要求的支持手動回退版本的降級。可利用源碼依賴不會自動更新版本的特性用作開關,也可使用主干研發模式的能力去做降級。

最后聊了如何在大倉下基于源碼依賴結合模塊聯邦的方式實現共享組件。

  • 先源碼引入后 MF:在 Share 目錄下開發業務代碼,在子應用 Expose 目錄下通過源碼引入使用組件,再暴露出去供使用者使用。
  • 先 MF 后源碼引入:在子應用正常目錄下開發組件,通過 Expose 方式提供遠程組件,編譯時將業務代碼同步至 Share 目錄下。組件使用者可編寫開關優先使用 MF 組件,再利用源碼依賴不會自動更新版本的特性將源碼依賴版本用作降級。

*文/昌禾

本文屬得物技術原創,更多精彩文章請看:得物技術官網

未經得物技術許可嚴禁轉載,否則依法追究法律責任!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/714935.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/714935.shtml
英文地址,請注明出處:http://en.pswp.cn/news/714935.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JAVA *數據庫連接池 * 接JDBC

一.介紹: 數據庫連接池實際上就是一個 " 容器 " 當有多個擁護需要訪問數據庫的時候, 一個用戶會打開一個數據庫連接, 但是!當用戶離開的時候,就會斷開數據庫連接,那么數據庫連接就作廢了,之后如果還有用戶需要進行訪問,需要再建立一個數據庫連接......循環往復, …

【Mybatis】快速入門 基本使用 第一期

文章目錄 Mybatis是什么&#xff1f;一、快速入門&#xff08;基于Mybatis3方式&#xff09;二、MyBatis基本使用2.1 向SQL語句傳參2.1.1 mybatis日志輸出配置2.1.2 #{}形式2.1.3 ${}形式 2.2 數據輸入2.2.1 Mybatis總體機制概括2.2.2 概念說明2.2.3 單個簡單類型參數2.2.4 實體…

Web組態可視化編輯器 快速繪制組態

隨著工業智能制造的發展&#xff0c;工業企業對設備可視化、遠程運維的需求日趨強烈&#xff0c;傳統的單機版組態軟件已經不能滿足越來越復雜的控制需求&#xff0c;那么實現Web組態可視化界面成為了主要的技術路徑。 行業痛點 對于軟件服務商來說&#xff0c;將單機版軟件轉變…

計算機視覺基礎知識(十六)--圖像識別

圖像識別 信息時代的一門重要技術;目的是讓計算機代替人類處理大量的物理信息;隨著計算機技術的發展,人類對圖像識別技術的認識越來越深刻;圖像識別技術利用計算機對圖像進行處理\分析\理解,識別不同模式的目標和對象;過程分為信息的獲取\預處理\特征抽取和選擇\分類器設計\分…

重拾C++之菜鳥刷算法第6篇---棧與隊列

棧與隊列 一、用棧實現隊列 題目 請你僅使用兩個棧實現先入先出隊列。隊列應當支持一般隊列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 實現 MyQueue 類&#xff1a; void push(int x) 將元素 x 推到隊列的末尾int pop() 從隊列的開頭移除…

【Hadoop】使用Metorikku框架讀取hive數據統計分析寫入mysql

一、定義作業文件 作業文件 該文件將包括輸入源、輸出目標和要執行的配置文件的位置&#xff0c;具體內容如下 metrics:- /user/xrx/qdb.yaml # 此位置為hdfs文件系統目錄 inputs: output:jdbc:connectionUrl: "jdbc:mysql://233.233.233.233:3306/sjjc"user: &quo…

虛擬帆船:利用技術出海的探險家

在數字化的浪潮中&#xff0c;一個新時代的探險家誕生了。他們不是在尋找未知大陸的勇士&#xff0c;而是在尋求跨界電商和全球游戲市場的先鋒。這些現代探險家的帆船是由SOCKS5代理和代理IP構成的&#xff0c;他們的海圖則是由數據和市場分析繪制的。 出海的第一步&#xff1a…

WebServer -- 注冊登錄

目錄 &#x1f349;整體內容 &#x1f33c;流程圖 &#x1f382;載入數據庫表 提取用戶名和密碼 &#x1f6a9;同步線程登錄注冊 補充解釋 代碼 &#x1f618;頁面跳轉 補充解釋 代碼 &#x1f349;整體內容 概述 TinyWebServer 中&#xff0c;使用數據庫連接池實現…

Linux 內核irq_stack遍歷

環境Centos 4.18.0-80.el8.x86_64 一、x86架構堆棧類型說明 https://www.kernel.org/doc/Documentation/x86/kernel-stacks int get_stack_info(unsigned long *stack, struct task_struct *task,struct stack_info *info, unsigned long *visit_mask) {if (!stack)goto unk…

【深度學習筆記】計算機視覺——圖像增廣

圖像增廣 sec_alexnet提到過大型數據集是成功應用深度神經網絡的先決條件。 圖像增廣在對訓練圖像進行一系列的隨機變化之后&#xff0c;生成相似但不同的訓練樣本&#xff0c;從而擴大了訓練集的規模。 此外&#xff0c;應用圖像增廣的原因是&#xff0c;隨機改變訓練樣本可以…

Python + Selenium —— 下拉菜單處理!

傳統的下拉菜單 Select 元素&#xff0c;由一個 Select 一系列的 option 元素構成。 <select id"source" name"source"><option value"">--請選擇--</option><option value"1001">網絡營銷</option>&…

3.3 序列式容器-deque、stack、queue、heap、priority_queue

deque 3.1定義 std::deque&#xff08;雙端隊列&#xff09;是C標準模板庫&#xff08;STL&#xff09;中的一種容器&#xff0c;表示雙端隊列數據結構。它提供了在兩端高效地進行插入和刪除操作的能力。與vector的連續線性空間類似&#xff0c;但有所不同&#xff0c;deque動…

基于ssm旅社客房收費管理系統+vue

目 錄 目 錄 I 摘 要 III ABSTRACT IV 1 緒論 1 1.1 課題背景 1 1.2 研究現狀 1 1.3 研究內容 2 2 系統開發環境 3 2.1 vue技術 3 2.2 JAVA技術 3 2.3 MYSQL數據庫 3 2.4 B/S結構 4 2.5 SSM框架技術 4 3 系統分析 5 3.1 可行性分析 5 3.1.1 技術可行性 5 3.1.2 操作可行性 5 3…

STM32使用FlyMcu串口下載程序與STLink Utility下載程序

文章目錄 前言軟件鏈接一、FlyMcu串口下載程序原理優化手動修改跳線帽選項字節其他功能 二、STLink Utility下載程序下載程序選項字節固件更新 前言 本文主要講解使用FlyMcu配合USART串口為STM32下載程序、使用STLink Utility配合STLink為STM32下載程序&#xff0c;以及這兩個…

代碼隨想錄算法訓練營第62/63天| 503.下一個更大元素II、42. 接雨水、84.柱狀圖中最大的矩形

文章目錄 503.下一個更大元素II思路代碼 42. 接雨水思路代碼 84.柱狀圖中最大的矩形思路代碼 503.下一個更大元素II 題目鏈接&#xff1a;503.下一個更大元素II 文章講解&#xff1a;代碼隨想錄|503.下一個更大元素II 思路 和739. 每日溫度 (opens new window)也幾乎如出一轍&…

C++/數據結構:AVL樹

目錄 一、AVL樹的概念 二、AVL樹的實現 2.1節點定義 2.2節點插入 三、AVL樹的旋轉 3.1新節點插入較高左子樹的左側&#xff1a;右單旋 3.2新節點插入較高右子樹的右側&#xff1a;左單旋 3.3新節點插入較高左子樹的右側---左右&#xff1a;先左單旋再右單旋 3.4新節點插…

Rocky Linux 運維工具 Systemd

一、Systemd 的簡介 Systemd是一個用于管理Linux系統啟動進程和服務的系統和服務管理器&#xff0c;取代了傳統的init系統。它提供了并行啟動、依賴關系管理、動態加載服務文件等功能&#xff0c;成為現代Linux發行版中主流的初始化系統。 二、Systemd 的參數說明 [Unit] Des…

SLAM基礎知識-卡爾曼濾波

前言&#xff1a; 在SLAM系統中&#xff0c;后端優化部分有兩大流派。一派是基于馬爾科夫性假設的濾波器方法&#xff0c;認為當前時刻的狀態只與上一時刻的狀態有關。另一派是非線性優化方法&#xff0c;認為當前時刻狀態應該結合之前所有時刻的狀態一起考慮。 卡爾曼濾波是…

SD NAND:為車載顯示器注入智能與安全的心臟

SD NAND 在車載顯示器的應用 在車載顯示器上&#xff0c;SD NAND&#xff08;Secure Digital NAND&#xff09;可以有多種應用&#xff0c;其中一些可能包括&#xff1a; 導航數據存儲&#xff1a; SD NAND 可以用于存儲地圖數據、導航軟件以及車載系統的相關信息。這有助于提…

微服務day03-Nacos配置管理與Nacos集群搭建

一.Nacos配置管理 Nacos不僅可以作為注冊中心&#xff0c;可以進行配置管理 1.1 統一配置管理 統一配置管理可以實現配置的熱更新&#xff08;即不用重啟當服務發生變更時也可以直接更新&#xff09; dataId格式&#xff1a;服務名-環境名.yaml&#xff0c;分組一般使用默認…