主頁 > 後端開發 > 微服務之間最佳呼叫方式是什么?

微服務之間最佳呼叫方式是什么?

2020-10-02 04:40:51 後端開發

在微服務架構中,需要呼叫很多服務才能完成一項功能,服務之間如何互相呼叫就變成微服務架構中的一個關鍵問題,

服務呼叫有兩種方式,一種是RPC方式,另一種是事件驅動(Event-driven)方式,也就是發訊息方式,

訊息方式是松耦合方式,比緊耦合的RPC方式要優越,但RPC方式如果用在適合的場景也有它的一席之地,

我們總在談耦合,那么耦合到底意味著什么呢?

耦合的種類:

時間耦合: 客戶端和服務端必須同時上線才能作業,發訊息時,接受訊息佇列必須運行,但后臺處理程式暫時不作業也不影響,

容量耦合: 客戶端和服務端的處理容量必須匹配,發訊息時,如果后臺處理能力不足也不要緊,訊息佇列會起到緩沖的作用,

介面耦合: RPC呼叫有函式標簽,而訊息佇列只是一個訊息,例如買了商品之后要呼叫發貨服務,如果是發訊息,那么就只需發送一個商品被買訊息,

發送方式耦合: RPC是點對點方式,需要知道對方是誰,它的好處是能夠傳回回傳值,訊息既可以點對點,也可以用廣播的方式,這樣減少了耦合,但也使回傳值比較困難,

下面我們來逐一分析這些耦合的影響,第一,時間耦合,對于多數應用來講,你希望能馬上得到回答,因此即使使用訊息佇列,后臺也需要一直作業,

第二,容量耦合,如果你對回復有時間要求,那么訊息佇列的緩沖功能作用不大,因為你希望及時回應,

真正需要的是自動伸縮(Auto-scaling),它能自動調整服務端處理能力去匹配請求數量,第三和第四,介面耦合和發送方式耦合,這兩個確實是RPC方式的軟肋,

事件驅動(Event-Driven)方式

Martin Fowler把事件驅動分成四種方式(What do you mean by “Event-Driven”),簡化之后本質上只有兩種方式,一種就是我們熟悉的的事件通知(Event Notification),另一種是事件溯源(Event Sourcing),

事件通知就是微服務之間不直接呼叫,而是通過發訊息來進行合作,事件溯源有點像記賬,它把所有的事件都記錄下來,作為永久存盤層,再在它的基礎之上構建應用程式,

實際上從應用的角度來講,它們并不應該分屬一類,它們的用途完全不同,事件通知是微服務的呼叫(或集成)方式,應該和RPC分在一起,事件溯源是一種存盤資料的方式,應該和資料庫分在一起,

事件通知(Event Notification)方式

讓我們用具體的例子來看一下,在下面的例子中,有三個微服務,“Order Service”, “Customer Service” 和“Product Service”,

先說讀資料,假設要創建一個“Order”,在這個程序中需要讀取“Customer”的資料和“Product”資料,

如果用事件通知的方式就只能在“Order Service”本地也創建只讀“Customer”和“Product”表,并把資料用訊息的方式同步過來,

再說寫資料,如果在創建一個“Order”時需要創建一個新的“Customer”或要修改“Customer”的資訊,那么可以在界面上跳轉到用戶創建頁面,然后在“Customer Service”創建用戶之后再發”用戶已創建“的訊息,“Order Service”接到訊息,更新本地“Customer”表,

這并不是一個很好的使用事件驅動的例子,因為事件驅動的優點就是不同的程式之間可以獨立運行,沒有系結關系,但現在“Order Service”需要等待“Customer Service”創建完了之后才能繼續運行,來完成整個創建“Order”的作業,主要是因為“Order”和“Customer”本身從邏輯上來講就是緊耦合關系,沒有“Customer”你是不能創建“Order”的,

在這種緊耦合的情況下,也可以使用RPC,你可以建立一個更高層級的管理程式來管理這些微服務之間的呼叫,這樣“Order Service”就不必直接呼叫“Customer Service”了,

當然它從本質上來講并沒有解除耦合,只是把耦合轉移到了上一層,但至少現在“order Service”和“Customer Service”可以互不影響了,之所以不能根除這種緊耦合關系是因為它們在業務上是緊耦合的,

再舉一個購物的例子,用戶選好商品之后進行“Checkout”,生成“Order”,然后需要“payment”,再從“Inventory”取貨,最后由“Shipment”發貨,它們每一個都是微服務,這個例子用RPC方式和事件通知方式都可以完成,

當用RPC方式時,由“Order”服務呼叫其他幾個服務來完成整個功能,用事件通知方式時,“Checkout”服務完成之后發送“Order Placed”訊息,“Payment”服務收到訊息,接收用戶付款,發送“Payment received”訊息,

“Inventory”服務收到訊息,從倉庫里取貨,并發送“Goods fetched”訊息,“Shipment”服務得到訊息,發送貨物,并發送“Goods shipped”訊息,

對這個例子來講,使用事件驅動是一個不錯的選擇,因為每個服務發訊息之后它不需要任何反饋,這個訊息由下一個模塊接收來完成下一步動作,時間上的要求也比上一個要寬松,用事件驅動的好處是降低了耦合度,壞處是你現在不能在程式里找到整個購物程序的步驟,

如果一個業務邏輯有它自己相對固定的流程和步驟,那么使用RPC或業務流程管理(BPM)能夠更方便地管理這些流程,在這種情況下選哪種方案呢?在我看來好處和壞處是大致相當的,從技術上來講要選事件驅動,從業務上來講要選RPC,不過現在越來越多的人采用事件通知作為微服務的集成方式,它似乎已經成了微服務之間的標椎呼叫方式,

事件溯源(Event Sourcing)

這是一種具有顛覆性質的的設計,它把系統中所有的資料都以事件(Event)的方式記錄下來,它的持久存盤叫Event Store, 一般是建立在資料庫或訊息佇列(例如Kafka)基礎之上,并提供了對事件進行操作的介面,例如事件的讀寫和查詢,事件溯源是由領域驅動設計(Domain-Driven Design)提出來的,

DDD中有一個很重要的概念,有界背景關系(Bounded Context),可以用有界背景關系來劃分微服務,每個有界背景關系都可以是一個微服務,下面是有界背景關系的示例,下圖中有兩個服務“Sales”和“Support”,

有界背景關系的一個關鍵是如何處理共享成員, 在圖中是“Customer”和“Product”,在不同的有界背景關系中,共享成員的含義、用法以及他們的物件屬性都會有些不同,DDD建議這些共享成員在各自的有界背景關系中都分別建自己的類(包括資料庫表),而不是共享,可以通過資料同步的手段來保持資料的一致性,下面還會詳細講解,

事件溯源是微服務的一種存盤方式,它是微服務的內部實作細節,因此你可以決定哪些微服務采用事件溯源方式,哪些不采用,而不必所有的服務都變成事件溯源的,通常整個應用程式只有一個Event Store, 不同的微服務都通過向Event Store發送和接受訊息而互相通信,

Event Store內部可以分成不同的stream(相當于訊息佇列中的Topic), 供不同的微服務中的領域物體(Domain Entity)使用,

事件溯源的一個短板是資料查詢,它有兩種方式來解決,第一種是直接對stream進行查詢,這只適合stream比較小并且查詢比較簡單的情況,

查詢復雜的話,就要采用第二種方式,那就是建立一個只讀資料庫,把需要的資料放在庫中進行查詢,資料庫中的資料通過監聽Event Store中相關的事件來更新,

資料庫存盤方式只能保存當前狀態,而事件溯源則存盤了所有的歷史狀態,因而能根據需要回放到歷史上任何一點的狀態,具有很大優勢,但它也不是一點問題都沒有,

第一,它的程式比較復雜,因為事件是一等公民,你必須把業務邏輯按照事件的方式整理出來,然后用事件來驅動程式,第二,如果你要想修改事件或事件的格式就比較麻煩,因為舊的事件已經存盤在Event Store里了(事件就像日志,是只讀的),沒有辦法再改,

由于事件溯源和事件通知表面上看起來很像,不少人都搞不清楚它們的區別,事件通知只是微服務的集成方式,程式內部是不使用事件溯源的,內部實作仍然是傳統的資料庫方式,

只有當要與其他微服務集成時才會發訊息,而在事件溯源中,事件是一等公民,可以不要資料庫,全部資料都是按照事件的方式存盤的,

雖然事件溯源的踐行者有不同的意見,但有不少人都認為事件溯源不是微服務的集成方式,而是微服務的一種內部實作方式,因此,在一個系統中,可以某些微服務用事件溯源,另外一些微服務用資料庫,

當你要集成這些微服務時,你可以用事件通知的方式,注意現在有兩種不同的事件需要區分開,一種是微服務的內部事件,是顆粒度比較細的,這種事件只發送到這個微服務的stream中,只被事件溯源使用,

另一種是其他微服務也關心的,是顆粒度比較粗的,這種事件會放到另外一個或幾個stream中,被多個微服務使用,是用來做服務之間集成的,這樣做的好處是限制了事件的作用范圍,減少了不相關事件對程式的干擾,詳見"Domain Events vs. Event Sourcing",

事件溯源出現已經很長時間了,雖然熱度一直在上升(尤其是這兩年),但總的來說非常緩慢,談論的人不少,但生產環境使用的不多,究其原因就是應為它對現在的體系結構顛覆太大,需要更改資料存盤結構和程式的作業方式,還是有一定風險的,

另外,微服務已經形成了一整套體系,從程式部署,服務發現與注冊,到監控,服務韌性(Service Resilience),它們基本上都是針對RPC的,雖然也支持訊息,但成熟度就差多了,因此有不少作業還是要自己來做,

有意思的是Kafka一直在推動它作為事件驅動的工具,也取得了很大的成功,但它卻沒有得到事件溯源圈內的認可,

多數事件溯源都使用一個叫evenstore的開源Event Store,或是基于某個資料庫的Event Store,只有比較少的人用Kafka做Event Store,

但如果用Kafka實作事件通知就一點問題都沒有,總的來說,對大多數公司來講事件溯源是有一定挑戰的,應用時需要找到合適的場景,如果你要嘗試的話,可以先拿一個微服務試水,

雖然現在事件驅動還有些生澀,但從長遠來講,還是很看好它的,像其他全新的技術一樣,事件溯源需要大規模的適用場景來推動,例如容器技術就是因為微服務的流行和推動,才走向主流,

事件溯源以前的適用場景只限于記賬和源代碼庫,局限性較大,區塊鏈可能會成為它的下一個機遇,因為它用的也是事件溯源技術,

另外AI今后會滲入到具體程式中,使程式具有學習功能,而RPC模式注定沒有自適應功能,事件驅動本身就具有對事件進行反應的能力,這是自我學習的基礎,因此,這項技術長遠來講定會大放異彩,但短期內(3-5年)大概不會成為主流,

RPC方式

RPC的方式就是遠程函式呼叫,像RESTFul,gRPC, DUBBO 都是這種方式,它一般是同步的,可以馬上得到結果,在實際中,大多數應用都要求立刻得到結果,這時同步方式更有優勢,代碼也更簡單,

服務網關(API Gateway)

熟悉微服務的人可能都知道服務網關(API Gateway),當UI需要呼叫很多微服務時,它需要了解每個服務的介面,這個作業量很大,

于是就用服務網關創建了一個Facade,把幾個微服務封裝起來,這樣UI就只呼叫服務網關就可以了,不需要去對付每一個微服務,下面是API Gateway示例圖:

服務網關(API Gateway)不是為了解決微服務之間呼叫的緊耦合問題,它主要是為了簡化客戶端的作業,其實它還可以用來降低函式之間的耦合度,

有了API Gateway之后,一旦服務介面修改,你可能只需要修改API Gateway, 而不必修改每個呼叫這個函式的客戶端,這樣就減少了程式的耦合性,

服務呼叫

可以借鑒API Gateway的思路來減少RPC呼叫的耦合度,例如把多個微服務組織起來形成一個完整功能的服務組合,并對外提供統一的服務介面,這種想法跟上面的API Gateway有些相似,都是把服務集中起來提供粗顆粒(Coarse Granular)服務,而不是細顆粒的服務(Fine Granular),

但這樣建立的服務組合可能只適合一個程式使用,沒有多少共享價值,因此如果有合適的場景就采用,否側也不必強求,雖然我們不能降低RPC服務之間的耦合度,卻可以減少這種緊耦合帶來的影響,

降低緊耦合的影響

什么是緊耦合的主要問題呢?就是客戶端和服務端的升級不同步,服務端總是先升級,客戶端可能有很多,如果要求它們同時升級是不現實的,它們有各自的部署時間表,一般都會選擇在下一次部署時順帶升級,

一般有兩個辦法可以解決這個問題:

同時支持多個版本:這個作業量比較大,因此大多數公司都不會采用這種方式,

服務端向后兼容:這是更通用的方式,例如你要加一個新功能或有些客戶要求給原來的函式增加一個新的引數,但別的客戶不需要這個引數,這時你只好新建一個函式,跟原來的功能差不多,只是多了一個引數,這樣新舊客戶的需求都能滿足,它的好處是向后兼容(當然這取決于你使用的協議),

它的壞處是當以后新的客戶來了,看到兩個差不多的函式就糊涂了,不知道該用那個,而且時間越長越嚴重,你的服務端可能功能增加的不多,但相似的函式卻越來越多,無法選擇,

它的解決辦法就是使用一個支持向后兼容的RPC協議,現在最好的就是Protobuf gRPC,尤其是在向后兼容上,另外,大家可以關注下微信公眾號:Java技術堆疊,在后臺回復:架構,可以獲取我整理的 N 篇 Java 架構及微服務教程,

它給每個服務定義了一個介面,這個介面是與編程語言無關的中性介面,然后你可以用工具生成各個語言的實作代碼,供不同語言使用,函式定義的變數都有編號,變數可以是可選型別的,這樣就比較好地解決了函式兼容的問題,

就用上面的例子,當你要增加一個可選引數時,你就定義一個新的可選變數,由于它是可選的,原來的客戶端不需要提供這個引數,因此不需要修改程式,

而新的客戶端可以提供這個引數,你只要在服務端能同時處理這兩種情況就行了,這樣服務端并沒有增加新的函式,但用戶的新需求滿足了,而且還是向后兼容的,

微服務的數量有沒有上限?

總的來說微服務的數量不要太多,不然會有比較重的運維負擔,有一點需要明確的是微服務的流行不是因為技術上的創新,而是為了滿足管理上的需要,單體程式大了之后,各個模塊的部署時間要求不同,對服務器的優化要求也不同,而且團隊人數眾多,很難協調管理,

把程式拆分成微服務之后,每個團隊負責幾個服務,就容易管理了,而且每個團隊也可以按照自己的節奏進行創新,但它給運維帶來了巨大的麻煩,所以在微服務剛出來時,我一直覺得它是一個退步,弊大于利,但由于管理上的問題沒有其他解決方案,只有硬著頭皮上了,

值得慶幸的是微服務帶來的麻煩都是可解的,直到后來,微服務建立了全套的自動化體系,從程式集成到部署,從全鏈路跟蹤到日志,以及服務檢測,服務發現和注冊,這樣才把微服務的作業量降了下來,

雖然微服務在技術上一無是處,但它的流行還是大大推動了容器技術,服務網格(Service Mesh)和全鏈路跟蹤等新技術的發展,不過它本身在技術上還是沒有發現任何優勢,

直到有一天,我意識到單體程式其實性能除錯是很困難的(很難分離出瓶頸點),而微服務配置了全鏈路跟蹤之后,能很快找到癥結所在,看來微服務從技術來講也不全是缺點,總算也有好的地方,但微服務的顆粒度不宜過細,否則作業量還是太大,

一般規模的公司十幾個或幾十個微服務都是可以承受的,但如果有幾百個甚至上千個,那么絕不是一般公司可以管理的,盡管現有的工具已經很齊全了,而且與微服務有關的整個流程也已經基本上全部自動化了,但它還是會增加很多作業,

Martin Fowler幾年以前建議先從單體程式開始(詳見 MonolithFirst),然后再逐步把功能拆分出去,變成一個個的微服務,但是后來有人反對這個建議,他也有些松口了,

如果單體程式不是太大,這是個好主意,可以用資料額庫表的數量來衡量程式的大小,我見過大的單體程式有幾百張表,這就太多了,很難管理,正常情況下,一個微服務可以有兩、三張表到五、六張表,一般不超過十張表,但如果要減少微服務數量的話,可以把這個標準放寬到不要超過二十張表,

用這個做為大致的指標來創建微程式,如果使用一段時間之后還是覺得太大了,那么再逐漸拆分,當然,按照這個標準建立的服務更像是服務組合,而不是單個的微服務,不過它會為你減少作業量,只要不影響業務部門的創新進度,這是一個不錯的方案,

到底應不應該選擇微服務呢?如果單體程式已經沒法管理了,那么你別無選擇,如果沒有管理上的問題,那么微服務帶給你的只有問題和麻煩,其實,一般公司都沒有太多選擇,只能采用微服務,不過你可以選擇建立比較少的微服務,如果還是沒法決定,有一個折中的方案,“內部微服務設計”,

內部微服務設計

這種設計表面上看起來是一個單體程式,它只有一個源代碼存盤倉庫,一個資料庫,一個部署,但在程式內部可以按照微服務的思想來進行設計,它可以分成多個模塊,每個模塊是一個微服務,可以由不同的團隊管理,

用這張圖做例子,這個圖里的每個圓角方塊大致是一個微服務,但我們可以把它作為一個單體程式來設計,內部有五個微服務,

每個模塊都有自己的資料庫表,它們都在一個資料庫中,但模塊之間不能跨資料庫訪問(不要建立模塊之間資料庫表的外鍵),

“User”(在Conference Management模塊中)是一個共享的類,但在不同的模塊中的名字不同,含義和用法也不同,成員也不一樣(例如,在“Customer Service”里叫“Customer”),

DDD(Domain-Driven Design)建議不要共享這個類,而是在每一個有界背景關系(模塊)中都建一個新類,并擁有新的名字,

雖然它們的資料庫中的資料應該大致相同,但DDD建議每一個有界背景關系中都建一個新表,它們之間再進行資料同步,

這個所謂的“內部微服務設計”其實就是DDD,但當時還沒有微服務,因此外表看起來是單體程式,但內部已經是微服務的設計了,

它的書在2003就出版了,當時就很有名,但它更偏重于業務邏輯的設計,踐行起來也比較困難,因此大家談論得很多,真正用的較少,

直到十年之后,微服務出來之后,人們發現它其實內部就是微服務,而且微服務的設計需要用它的思想來指導,于是就又重新煥發了青春,而且這次更猛,已經到了每個談論微服務的人都不得不談論DDD的地步,不過一本軟體書籍,在十年之后還能指導新技術的設計,非常令人欽佩,

這樣設計的好處是它是一個單體程式,省去了多個微服務帶來的部署、運維的麻煩,但它內部是按微服務設計的,如果以后要拆分成微服務會比較容易,至于什么時候拆分不是一個技術問題,

如果負責這個單體程式的各個團隊之間不能在部署時間表,服務器優化等方面達成一致,那么就需要拆分了,

當然你也要應對隨之而來的各種運維麻煩,內部微服務設計是一個折中的方案,如果你想試水微服務,但又不愿意冒太大風險時,這是一個不錯的選擇,

結論

微服務之間的呼叫有兩種方式,RPC和事件驅動,事件驅動是更好的方式,因為它是松耦合的,但如果業務邏輯是緊耦合的,RPC方式也是可行的(它的好處是代碼更簡單),而且你還可以通過選取合適的協議(Protobuf gRPC)來降低這種緊耦合帶來的危害,

由于事件溯源和事件通知的相似性,很多人把兩者弄混了,但它們實際上是完全不同的東西,微服務的數量不宜太多,可以先創建比較大的微服務(更像是服務組合),

如果你還是不能確定是否采用微服務架構,可以先從“內部微服務設計”開始,再逐漸拆分,

著作權宣告:本文為博主原創文章,遵循 CC 4.0 BY-SA 著作權協議,轉載請附上原文出處鏈接和本宣告,本文鏈接:https://blog.csdn.net/weixin_38748858/article/details/101062272

關注公眾號Java技術堆疊回復"面試"獲取我整理的2020最全面試題及答案,

推薦去我的博客閱讀更多:

1.Java JVM、集合、多執行緒、新特性系列教程

2.Spring MVC、Spring Boot、Spring Cloud 系列教程

3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程

4.Java、后端、架構、阿里巴巴等大廠最新面試題

覺得不錯,別忘了點贊+轉發哦!

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/147248.html

標籤:Java

上一篇:不會用Java Future,我懷疑你泡茶沒我快, 又是超長圖文!!

下一篇:本地快取解決方案-Caffeine Cache

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more