主頁 > 後端開發 > Dubbo淺入淺出

Dubbo淺入淺出

2020-09-18 00:07:39 後端開發

點贊再看,養成習慣,微信搜一搜【三太子敖丙】關注這個喜歡寫情懷的程式員,

本文 GitHub https://github.com/JavaFamily 已收錄,有一線大廠面試完整考點、資料以及我的系列文章,

前言

接下來一段時間敖丙將帶大家開啟緊張刺激的 Dubbo 之旅!是的要開始寫 Dubbo 系列的文章了,之前我已經寫過一篇架構演進的文章,也說明了微服務的普及化以及重要性,服務化場景下隨之而來的就是服務之間的通信問題,那服務間的通信腦海中想到的就是 RPC,說到 RPC 就離不開咱們的 Dubbo,

這篇文章敖丙先帶著大家來總覽全域,一般而言熟悉一個框架你要先知道這玩意是做什么的,能解決什么痛點,核心的模塊是什么,大致運轉流程是怎樣的,

你要一來就扎入細節之中無法自拔,一波 DFS 直接被勸退的可能性高達99.99%,所以本暖男敖丙將帶大家先過一遍 Dubbo 的簡介、總體分層、核心組件以及大致呼叫流程

不僅如此我還會帶著大家過一遍如果要讓你設計一個 RPC 框架你看看都需要什么功能?這波操作之后你會發現嘿嘿 Dubbo 怎么設計的和我想的一樣呢?真是英雄所見略同啊!

而且我還會寫一個簡單版 RPC 框架實作,讓大家明白 RPC 到底是如何作業的,

如果看了這篇文章你要還是不知道 Dubbo 是啥,我可以要勸退了,

我們先來談一談什么叫 RPC ,我發現有很多同學不太了解這個概念,還有人把 RPC 和 HTTP 來進行對比,所以咱們先來說說什么是 RPC,

什么是 RPC

RPC,Remote Procedure Call 即遠程程序呼叫,遠程程序呼叫其實對標的是本地程序呼叫,本地程序呼叫你熟悉吧?

想想那青蔥歲月,你在大學趕著期末大作業,正在攻克圖書管理系統,你奮筆疾書瘋狂地敲擊鍵盤,實作了圖書借閱、圖書歸還等等模塊,你實作的一個個方法之間的呼叫就叫本地程序呼叫,

你要是和我說你實作圖書館里系統已經用了服務化,搞了遠程呼叫了,我只能和你說你有點東西,

簡單的說本機上內部的方法呼叫都可以稱為本地程序呼叫,而遠程程序呼叫實際上就指的是你本地呼叫了遠程機子上的某個方法,這就是遠程程序呼叫,

所以說 RPC 對標的是本地程序呼叫,至于 RPC 要如何呼叫遠程的方法可以走 HTTP、也可以是基于 TCP 自定義協議,

所以說你討論 RPC 和 HTTP 就不是一個層級的東西,

RPC 框架就是要實作像那小助手一樣的東西,目的就是讓我們使用遠程呼叫像本地呼叫一樣簡單方便,并且解決一些遠程呼叫會發生的一些問題,使用戶用的無感知、舒心、放心、順心,它好我也好,快樂沒煩惱,

如何設計一個 RPC 框架

在明確了什么是 RPC,以及 RPC 框架的目的之后,咱們想想如果讓你做一款 RPC 框架你該如何設計?

服務消費者

我們先從消費者方(也就是呼叫方)來看需要些什么,首先消費者面向介面編程,所以需要得知有哪些介面可以呼叫,可以通過公用 jar 包的方式來維護介面,

現在知道有哪些介面可以呼叫了,但是只有介面啊,具體的實作怎么來?這事必須框架給處理了!所以還需要來個代理類,讓消費者只管調,啥事都別管了,我代理幫你搞定

對了,還需要告訴代理,你呼叫的是哪個方法,并且引數的值是什么,

雖說代理幫你搞定但是代理也需要知道它到底要調哪個機子上的遠程方法,所以需要有個注冊中心,這樣呼叫方從注冊中心可以知曉可以呼叫哪些服務提供方,一般而言提供方不止一個,畢竟只有一個掛了那不就沒了,

所以提供方一般都是集群部署,那呼叫方需要通過負載均衡來選擇一個呼叫,可以通過某些策略例如同機房優先呼叫啊啥的,

當然還需要有容錯機制,畢竟這是遠程呼叫,網路是不可靠的,所以可能需要重試什么的,

還要和服務提供方約定一個協議,例如我們就用 HTTP 來通信就好啦,也就是大家要講一樣的話,不然可能聽不懂了,

當然序列化必不可少,畢竟我們本地的結構是“立體”的,需要序列化之后才能傳輸,因此還需要約定序列化格式

并且這程序中間可能還需要摻入一些 Filter,來作一波統一的處理,例如呼叫計數啊等等,

這些都是框架需要做的,讓消費者像在呼叫本地方法一樣,無感知,

服務提供者

服務提供者肯定要實作對應的介面這是毋庸置疑的,

然后需要把自己的介面暴露出去,向注冊中心注冊自己,暴露自己所能提供的服務,

然后有消費者請求過來需要處理,提供者需要用和消費者協商好的協議來處理這個請求,然后做反序列化

序列化完的請求應該扔到執行緒池里面做處理,某個執行緒接受到這個請求之后找到對應的實作呼叫,然后再將結果原路回傳

注冊中心

上面其實我們都提到了注冊中心,這東西就相當于一個平臺,大家在上面暴露自己的服務,也在上面得知自己能呼叫哪些服務,

當然還能做配置中心,將配置集中化處理,動態變更通知訂閱者,

監控運維

面對眾多的服務,精細化的監控和方便的運維必不可少,

這點很多開發者在開發的時候察覺不到,到你真正上線開始運行維護的時候,如果沒有良好的監控措施,快速的運維手段,到時候就是睜眼瞎!手足無措,等著挨批把!

那種痛苦不要問我為什么知道,我就是知道!

小結一下

讓我們小結一下,大致上一個 RPC 框架需要做的就是約定要通信協議,序列化的格式、一些容錯機制、負載均衡策略、監控運維和一個注冊中心!

簡單實作一個 RPC 框架

沒錯就是簡單的實作,上面我們在思考如何設計一個 RPC 框架的時候想了很多,那算是生產環境使用級別的功能需求了,我們這是 Demo,目的是突出 RPC框架重點功能 - 實作遠程呼叫

所以啥七七八八的都沒,并且我用偽代碼來展示,其實也就是洗掉了一些保護性和約束性的代碼,因為看起來太多了不太直觀,需要一堆 try-catch 啥的,因此我刪減了一些,直擊重點,

Let's Do It!

首先我們定義一個介面和一個簡單實作,

public interface AobingService {  
    String hello(String name);  


public class AobingServiceImpl implements AobingService {  
    public String hello(String name) {  
        return "Yo man Hello,I am" + name;  
    }  
}  

然后我們再來實作服務提供者暴露服務的功能,

public class AobingRpcFramework 
     public static void export(Object service, int port) throws Exception 
          ServerSocket server = new ServerSocket(port);
          while(true) {
              Socket socket = server.accept();
              new Thread(new Runnable() {
                  //反序列化
                  ObjectInputStream input = new ObjectInputStream(socket.getInputStream()); 
                  String methodName = input.read(); //讀取方法名
                  Class<?>[] parameterTypes = (Class<?>[]) input.readObject(); //引數型別
                  Object[] arguments = (Object[]) input.readObject(); //引數
                  Method method = service.getClass().getMethod(methodName, parameterTypes);  //找到方法
                  Object result = method.invoke(service, arguments); //呼叫方法
                  // 回傳結果
                  ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream());
                  output.writeObject(result);
              }).start();
          }
     }
    public static <T> refer (Class<T> interfaceClass, String host, int port) throws Exception {
       return  (T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[] {interfaceClass}, 
            new InvocationHandler() {  
                public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {  
                    Socket socket = new Socket(host, port);  //指定 provider 的 ip 和埠
                    ObjectOutputStream output = new ObjectOutputStream(socket.getOutputStream()); 
                    output.write(method.getName());  //傳方法名
                    output.writeObject(method.getParameterTypes());  //傳引數型別
                    output.writeObject(arguments);  //傳引數值
                    ObjectInputStream input = new ObjectInputStream(socket.getInputStream());  
                    Object result = input.readObject();  //讀取結果
                    return result;  
               }
        });  
    }  
}

好了,這個 RPC 框架就這樣好了,是不是很簡單?就是呼叫者傳遞了方法名、引數型別和引數值,提供者接收到這樣引數之后呼叫對于的方法回傳結果就好了!這就是遠程程序呼叫,

我們來看看如何使用

        //服務提供者只需要暴露出介面
       AobingService service = new AobingServiceImpl ();  
       AobingRpcFramework.export(service, 2333);  

       //服務呼叫者只需要設定依賴
       AobingService service = AobingRpcFramework.refer(AobingService.class, "127.0.0.1"2333);  
       service.hello(); 

看起來好像好不錯喲,不過這很是簡陋,用作 demo 有助理解還是極好的!

接下來就來看看 Dubbo 吧!上正菜!

Dubbo 簡介

Dubbo 是阿里巴巴 2011年開源的一個基于 Java 的 RPC 框架,中間沉寂了一段時間,不過其他一些企業還在用 Dubbo 并自己做了擴展,比如當當網的 Dubbox,還有網易考拉的 Dubbok,

但是在 2017 年阿里巴巴又重啟了對 Dubbo 維護,在 2017 年榮獲了開源中國 2017 最受歡迎的中國開源軟體 Top 3,

在 2018 年和 Dubbox 進行了合并,并且進入 Apache 范訓器,在 2019 年畢業正式成為 Apache 頂級專案,

目前 Dubbo 社區主力維護的是 2.6.x 和 2.7.x 兩大版本,2.6.x 版本主要是 bug 修復和少量功能增強為準,是穩定版本,

而 2.7.x 是主要開發版本,更新和新增新的 feature 和優化,并且 2.7.5 版本的發布被 Dubbo 認為是里程碑式的版本發布,之后我們再做分析,

它實作了面向介面的代理 RPC 呼叫,并且可以配合 ZooKeeper 等組件實作服務注冊和發現功能,并且擁有負載均衡、容錯機制等,

Dubbo 總體架構

我們先來看下官網的一張圖,

本丙再暖心的給上圖內每個節點的角色說明一下,

節點 角色說明
Consumer 需要呼叫遠程服務的服務消費方
Registry 注冊中心
Provider 服務提供方
Container 服務運行的容器
Monitor 監控中心

我再來大致說一下整體的流程,首先服務提供者 Provider 啟動然后向注冊中心注冊自己所能提供的服務,

服務消費者 Consumer 啟動向注冊中心訂閱自己所需的服務,然后注冊中心將提供者元資訊通知給 Consumer, 之后 Consumer 因為已經從注冊中心獲取提供者的地址,因此可以通過負載均衡選擇一個 Provider 直接呼叫

之后服務提供方元資料變更的話注冊中心會把變更推送給服務消費者

服務提供者和消費者都會在記憶體中記錄著呼叫的次數和時間,然后定時的發送統計資料到監控中心

一些注意點

首先注冊中心和監控中心是可選的,你可以不要監控,也不要注冊中心,直接在組態檔里面寫然后提供方和消費方直連,

然后注冊中心、提供方和消費方之間都是長連接,和監控方不是長連接,并且消費方是直接呼叫提供方,不經過注冊中心

就算注冊中心和監控中心宕機了也不會影響到已經正常運行的提供者和消費者,因為消費者有本地快取提供者的資訊,

Dubbo 分層架構

總的而言 Dubbo 分為三層,如果每一層再細分下去,一共有十層,別怕也就十層,本丙帶大家過一遍,大家先有個大致的印象,之后的文章丙會帶著大家再深入,

大的三層分別為 Business(業務層)、RPC 層、Remoting,并且還分為 API 層和 SPI 層,

分為大三層其實就是和我們知道的網路分層一樣的意思,只有層次分明,職責邊界清晰才能更好的擴展

而分 API 層和 SPI 層這是 Dubbo 成功的一點,采用微內核設計+SPI擴展,使得有特殊需求的接入方可以自定義擴展,做定制的二次開發,

接下來咱們再來看看每一層都是干嘛的,

  • Service,業務層,就是咱們開發的業務邏輯層,

  • Config,配置層,主要圍繞 ServiceConfig 和 ReferenceConfig,初始化配置資訊,

  • Proxy,代理層,服務提供者還是消費者都會生成一個代理類,使得服務介面透明化,代理層做遠程呼叫和回傳結果,

  • Register,注冊層,封裝了服務注冊和發現,

  • Cluster,路由和集群容錯層,負責選取具體呼叫的節點,處理特殊的呼叫要求和負責遠程呼叫失敗的容錯措施,

  • Monitor,監控層,負責監控統計呼叫時間和次數,

  • Portocol,遠程呼叫層,主要是封裝 RPC 呼叫,主要負責管理 Invoker,Invoker代表一個抽象封裝了的執行體,之后再做詳解,

  • Exchange,資訊交換層,用來封裝請求回應模型,同步轉異步,

  • Transport,網路傳輸層,抽象了網路傳輸的統一介面,這樣用戶想用 Netty 就用 Netty,想用 Mina 就用 Mina,

  • Serialize,序列化層,將資料序列化成二進制流,當然也做反序列化,

SPI

我再稍微提一下 SPI(Service Provider Interface),是 JDK 內置的一個服務發現機制,它使得介面和具體實作完全解耦,我們只宣告介面,具體的實作類在配置中選擇,

具體的就是你定義了一個介面,然后在META-INF/services目錄下放置一個與介面同名的文本檔案,檔案的內容為介面的實作類,多個實作類用換行符分隔,

這樣就通過配置來決定具體用哪個實作!

而 Dubbo SPI 還做了一些改進,篇幅有限留在之后再談,

Dubbo 呼叫程序

上面我已經介紹了每個層到底是干嘛的,我們現在再來串起來走一遍呼叫的程序,加深你對 Dubbo 的理解,讓知識點串起來,由點及面來一波連連看,

我們先從服務提供者開始,看看它是如何作業的,

服務暴露程序

首先 Provider 啟動,通過 Proxy 組件根據具體的協議 Protocol 將需要暴露出去的介面封裝成 Invoker,Invoker 是 Dubbo 一個很核心的組件,代表一個可執行體,

然后再通過 Exporter 包裝一下,這是為了在注冊中心暴露自己套的一層,然后將 Exporter 通過 Registry 注冊到注冊中心, 這就是整體服務暴露程序,

消費程序

接著我們來看消費者呼叫流程(把服務者暴露的程序也在圖里展示出來了,這個圖其實算一個挺完整的流程圖了),

首先消費者啟動會向注冊中心拉取服務提供者的元資訊,然后呼叫流程也是從 Proxy 開始,畢竟都需要代理才能無感知,

Proxy 持有一個 Invoker 物件,呼叫 invoke 之后需要通過 Cluster 先從 Directory 獲取所有可呼叫的遠程服務的 Invoker 串列,如果配置了某些路由規則,比如某個介面只能呼叫某個節點的那就再過濾一遍 Invoker 串列,

剩下的 Invoker 再通過 LoadBalance 做負載均衡選取一個,然后再經過 Filter 做一些統計什么的,再通過 Client 做資料傳輸,比如用 Netty 來傳輸,

傳輸需要經過 Codec 介面做協議構造,再序列化,最終發往對應的服務提供者,

服務提供者接收到之后也會進行 Codec 協議處理,然后反序列化后將請求扔到執行緒池處理,某個執行緒會根據請求找到對應的 Exporter ,而找到 Exporter 其實就是找到了 Invoker,但是還會有一層層 Filter,經過一層層過濾鏈之后最終呼叫實作類然后原路回傳結果,

完成整個呼叫程序!

總結

這次敖丙帶著大家先了解了下什么是 RPC,然后規劃了一波 RPC 框架需要哪些組件,然后再用代碼實作了一個簡單的 RPC 框架,

然后帶著大家了解了下 Dubbo 的發展歷史、總體架構、分層設計架構以及每個組件是干嘛的,再帶著大伙走了一遍整體呼叫程序,

我真的是太暖了啊!

dubbo近期我會安排幾個章節繼續展開,最后會出一個面試版本的dubbo,我們拭目以待吧,

絮叨

另外,敖丙把自己的面試文章整理成了一本電子書,共 1630頁!目錄如下,還有我復習時總結的面試題以及簡歷模板

現在免費送給大家,點贊后在我的公眾號三太子敖丙回復 【資料】 即可獲取,

我是敖丙,你知道的越多,你不知道的越多,我們下期見!

人才們的 【三連】 就是敖丙創作的最大動力,如果本篇博客有任何錯誤和建議,歡迎人才們留言!


文章持續更新,可以微信搜一搜「 三太子敖丙 」第一時間閱讀,回復【資料】有我準備的一線大廠面試資料和簡歷模板,本文 GitHub https://github.com/JavaFamily 已經收錄,有大廠面試完整考點,歡迎Star,

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

標籤:Java

上一篇:idea中部署Tomcat為什么是這樣的專案哪里出了問題

下一篇:thymeleaf session取不出一部分user的屬性值

標籤雲
其他(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