環境資訊中心綜合外電;姜唯 編譯;林大利 審校
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
北部有線電視-提供穩定的寬頻光纖上網、高畫質HD數位頻道、第四台電視、數位電視,現在申辦免費體驗3個月"HD99高畫質套餐"
環境資訊中心綜合外電;姜唯 編譯;林大利 審校
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
環境資訊中心綜合外電;姜唯 編譯;林大利 審校
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
目錄
寫這篇博客主要是為了進一步了解如何將CNN當作Encoder結構來使用,同時這篇論文也是必看的論文之一。該論文證明了使用CNN作為特徵抽取結構實現Seq2Seq,可以達到與 RNN 相接近甚至更好的效果,並且CNN的高并行能力能夠大大減少我們的模型訓練時間(本文對原文中不清晰的部分做了梳理,建議與原文搭配服用)
原文鏈接:
模型結構如下圖所示:
下面對模型的每個部分進行分塊介紹:
卷積網絡和Transformer一樣,不是類似於RNN的時序模型,因此需要加入位置編碼來體現詞與詞之間的位置關係
GLU和GTU是在同一篇論文中提出的,其中,GLU也是CNN Seq2Seq的主要結構。可以直接將其當作激活函數來看待,其將某以卷積核的輸出輸入到兩個結構相同的卷積網絡,令其中一個的輸出為\(A\),另一個為\(B\)。
GLU與GRU的區別就在於A輸出的激活函數不同:
\[GLU:H_0=A \otimes \sigma (B)\]
\[GTU:H_0=tanh(A) \otimes \sigma (B)\]
而CNN Seq2Seq就採用了GLU作為模型的激活函數
原文鏈接:
編碼器與解碼器都是由多個卷積層構成的(原文中稱為block,實際上就是layer),每一層包含一個1維卷積核以及一個門控線性單元(Gated linear units, GLU)。假設單詞數即輸入長度為\(m\),kernel大小為\(k\),pad為\(p\),那麼計算輸出sequence長度的公式為\((m+2p-k)/stride+1\),只要適當的設置卷積核的kernel大小、pad以及步長參數,即可使得輸出序列與輸入序列的維度保持一致。在文中,輸入為25,kernel為5,則輸出序列長度為\((25+2*2-5)/1+1=25\)。
另外,為了充分讓輸出節點跟整個sequence單詞有聯繫,必須使用多個卷積層,這樣才能使得最後一個卷積核有足夠大得感受野以感受整個句子的特徵,同時也能捕捉局部句子的特徵。
來看一下整個編碼器的前向傳播方式:
這樣的卷積策略保證了每一層的輸入與輸出序列的一一對應,並且能夠將其看作簡單的編碼器單元,多層堆疊以實現更深層次的編碼。
對於Attention的計算,關鍵就是找到 Query、Key 和 Value。下圖為計算Attention且解碼的示意圖
Attention的計算過程如下:
Query由decoder的最後一個卷積層的輸出\(h_i^l\)以及上一時刻decoder最終的生成的目標\(g_i\)共同決定,\(W^l_d\)與\(b_d^l\)為線性映射的參數。
\[d_i^l = W^l_dh^l_i+b_d^l+g_i\]
Key 則採用 Encoder 的輸出\(z_j^u\),典型的二維匹配模型,將 Query 與 Key 一一對齊,計算 dot attention分數:
\[a_{ij}^l = \frac{exp(d^l_i \cdot z^u_j)}{\sum_{t=1}^mexp(z_j^u+e_j)}\]
Value 的值則取編碼器的輸出\(z_j^u\)以及詞向量表徵\(e_j\)之和,目的是為編碼器的輸出加上位置表徵信息。得到對應的 Value 值 \(c_i^l\) 之後,直接與當前時刻的 Decoder 輸出 \(h_i^l\) 相加,再輸入分類器進行分類。
\[c_i^l = \sum_{j=1}^ma_{ij}^l(z_j^u + e_j)\]
模型還通過歸一化策略來保證通過每一層模型的方差變化不會太大,這裏先簡單的記錄一下,具體的操作細節需要回去仔細琢磨代碼。歸一化的主要策略如下:
初始化的目的與歸一化是一致的,即都是為了保證前向與後項傳播的數據方差能夠保持在一個較穩定的水準,模型初始化的策略如下:
最後的實驗部分就不記錄了,有興趣的同學可以去原文里看看。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
苦勞網2020年2月3日報導;陳韋綸編譯
為了阻止更多移民自土耳其前來,,此舉引發人道組織的抨擊,認為將增加庇護尋求者與難民途中遭遇的危險,反對派也稱計畫「愚蠢」,更不可能阻止移民。
希臘政府預計在愛琴海北部的勒斯博島(Lesbos)設置長達2.7公里的網狀屏障,屏障將高於海平面50公分,費用約為50萬歐元(約新台幣1,680萬元)。勒斯博島上的摩利亞(Moria)難民營,是希臘主要的難民接待中心,原本僅能容納3千人的難民營,如今卻擠滿1萬9千人,環境惡劣,。
「遊戲規則已經改變!」掌管移民與難民事務的部長米塔拉希斯(Notis Mitarakis)嚴詞宣告:希臘不是想來就來的地方,「我們將採取一切措施保護邊境」,甚至揚言將加速驅逐出境的流程。
去年共計7萬2千人抵達希臘,米塔拉希斯表示,今年1月起,只要不符合難民資格的人,幾個月內便會被遣返土耳其。對於一百多萬民因戰爭逃離敘利亞的難民而言,希臘是進入歐盟的閘門,與希臘僅有愛琴海之隔的土耳其,已收容4百多萬名敘利亞難民,人數是世界之最。
國際特赦組織(AI)批評,此計畫不但增加庇護尋求者與難民上岸的難度,也嚴重影響救援者的協助工作,要求政府採取必要的安全措施,確保這套系統不會造成更多人犧牲。,而且難以實現。「即便是孩子都知道,海上建牆是不可能的。」
※轉載自()
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※想知道網站建置、網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計及後台網頁設計
※不管是台北網頁設計公司、台中網頁設計公司,全省皆有專員為您服務
※Google地圖已可更新顯示潭子電動車充電站設置地點!!
環境資訊中心綜合外電;鄒敏惠編譯、許芷榕審校
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
文章基本是官網內容的翻譯,英文不錯的同學可點擊上面的鏈接直接看英文文檔。
JWT全稱是JSON Web Token(JWT)是一個開放標準(RFC 7519),它定義了一種緊湊且自包含的方式,用於在各方之間作為JSON對象安全地傳輸信息。由於此信息是經過数字簽名的,因此可以被驗證和信任。
可以使用密鑰(HMAC算法)或使用RSA或ECDSA的公用/專用密鑰對對JWT進行簽名。
(Authorization)JWT的最常見情況。一旦用戶登錄,每個後續請求將包括JWT,從而允許用戶訪問該令牌允許的路由,服務和資源。單一登錄是當今廣泛使用JWT的一項功能,因為它的開銷很小並且可以在不同的域中輕鬆使用。(Information Exchange)JWT是在各方之間安全地傳輸信息的好方法。因為可以對JWT進行簽名(例如,使用公鑰/私鑰對),所以您可以確保發件人是他們所說的人。另外,由於簽名是使用Header和payload計算的,因此您還可以驗證內容是否未被篡改。由三部分組成,這些部分由點.分隔,分別是:
HeaderPayloadSignature因此,JWT通常如下所示。
xxxxx.yyyyy.zzzzz
通常由兩部分組成:
JWT)例如:
{
"alg": "HS256",
"typ": "JWT"
}
然後,將此JSON通過Base64Url編碼以形成JWT的第一部分。
令牌的第二部分是有效負載,其中包含聲明。聲明是有關實體(通常是用戶)和其他數據的聲明。共有三種類型的索賠: registered、public、private claims
Registered claimsiss(發出者),exp(到期時間),sub(主題),aud(受眾) 等。JWT是緊湊的。Public claimsJWT的人員隨意定義。但是為避免衝突,應在IANA JSON Web令牌註冊表中定義它們,或將其定義為包含抗衝突名稱空間的URI。Private claims有效負載示例:
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
同樣需要Base64Url編碼,以形成JWT的第二部分。
簽名(Signature)用於驗證消息在整個過程中沒有更改,並且對於使用私鑰進行簽名的令牌,它還可以驗證JWT的發送者是它所說的真實身份。
例如,如果要使用HMAC SHA256算法,則將通過以下方式創建簽名:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
輸出是三個由.分隔的Base64-URL字符串,可以在HTML和HTTP環境中輕鬆傳遞這些字符串,與基於XML的標準(例如SAML)相比,它更緊湊。
下圖显示了一個JWT,它已對先前的Header和Payload進行了編碼,並用一個Signature。
可以在這個網頁 驗證和生成JWT
在身份驗證中,當用戶使用其憑據成功登錄時,將返回令牌。由於令牌是憑據,因此必須格外小心以防止安全問題。通常,令牌的有效時間不宜設置過長。
Tip: 由於缺乏安全性,您也不應該將敏感的會話數據存儲在瀏覽器存儲中。
每當用戶想要訪問受保護的路由或資源時,用戶代理通常應在Bearer模式中使用授權頭髮送JWT。Header的內容應如下所示:
Authorization: Bearer <token>
在某些情況下,接口訪問並不需要身份授權。服務器的受保護路由將在Authorization Header中檢查JWT令牌是否有效,如果存在且有效,則將允許用戶訪問受保護的資源。
如果JWT包含必要的數據,則可以減少查詢數據庫中某些操作的需求。
如果令牌是在Authorization Header中發送的,則跨域資源共享 不會成為問題,因為它不使用cookie。
下圖显示了如何獲取JWT並將其用於訪問API或資源:
JWT令牌。JWT令牌是否有效,返回對應結果給客戶端下圖詳細的流程:
ps:請注意,使用簽名令牌,令牌或令牌中包含的所有信息都會暴露給用戶或其他方,即使他們無法更改它。這意味着您不應將機密信息放入令牌中。
對比 Simple Web Tokens (SWT) 和Security Assertion Markup Language Tokens (SAML),看看使用JSON Web Tokens (JWT) 有什麼好處。
JSON不如XML冗長,因此在編碼時JSON的大小也較小,從而使JWT比SAML更緊湊。這使得JWT是在HTML和HTTP環境中傳遞的不錯的選擇。SWT只能使用HMAC算法進行對稱簽名。但是JWT和SAML令牌可以使用X.509證書形式的公用/專用密鑰對進行簽名。與簽名JSON的簡單性相比,使用XML Digital Signature簽名XML而不引入模糊的安全漏洞是非常困難的。JSON解析器在大多數編程語言中都很常見,因為它們直接映射到對象。相反,XML沒有自然的文檔到對象映射。與SAML斷言相比,這使使用JWT更加容易。JWT是在Internet規模上使用的。這強調了在多個平台(尤其是移動平台)上對JSON Web令牌進行客戶端處理的簡便性。如果您想了解有關JSON Web令牌的更多信息,甚至開始使用它們在自己的應用程序中執行身份驗證,請瀏覽到 頁面。
諮詢請加微信:輕撩即可。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
環境資訊中心綜合外電;黃鈺婷 翻譯;彭瑞祥 審校;稿源:Mongabay
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
中國財政部長樓繼偉日前在中國電動汽車百人會論壇上表示,汽車企業對消費補貼過度依賴,2020年針對新能源汽車的補貼將退出。
樓繼偉稱2020年針對新能源汽車的補貼將退出;2017-2018年的補貼標準比2016年水準下調20%。
樓繼偉稱對優勢企業的補貼將提高。十三五期間中國新能源汽車市場進一步開放,將加快建立新能源汽車積分交易機制。
本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
三星集團的電池大廠三星SDI(Samsung SDI)公布2015年第4季財報,虧損擴大。不過三星SDI的化學部門即將分拆出售給樂天集團(Lotte),或許有助未來獲利。 韓聯社報導,三星SDI 25日盤後公布,去年Q4營收年減2.53%至1.86兆韓圜,營損為808億韓圜。淨損為2,313億韓圜(1.94億美元),虧損高於2014年同期的淨損1,288億美元,也不及Q3出現淨利5,024億韓圜。 此外,三星SDI股東25日同意,將分拆化學部門成立獨立公司,暫名為「SDI Chemical」,其中90%股權將在今年上半之前,出售給Lotte Chemical。去年十月樂天集團以3兆韓圜(25億美元)入股三星SDI化學部門,並購買Samsung Fine Chemicals的31.5%股權。 嘉實XQ全球贏家系統報價顯示,三星SDI 25日上漲0.49%收在102,500韓圜。和去年12月16日波段收盤高點(129,000韓圜),重挫21%之多。 三星集團積極卡位汽車市場,旗下電池大廠三星SDI (Samsung SDI)展示最新的車用電池,充電一次可跑600公里,預定2020年量產。 韓聯社11日報導,三星SDI在底特律車展秀出新的車用電池原型,充電一次可跑600公里,高於先前的500公里,預定2020年量產。該公司估計,2020年全球電動車銷量將增至116萬輛,遠高於2015年的27.8萬輛。 三星SDI已成為純粹的車用電池廠,該公司目前在南韓與中國擁有五座生產線、總產能多達4.5GWh。到了2020年,該公司還打算把產能擴充到35GWh。barron`s.com 去年11月4日報導,Bernstein Research分析師Mark Newman發表研究報告指出,三星SDI在2020年的車用電池產能,正好與特斯拉預定的Gigafactory產能完全一致。 (本文內容由授權使用)
本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開
文章來源:
一天下午正在摸魚的時候,測試小姐姐走了過來求助,說是需要改動測試環境 mock 應用。但是這個應用一時半會又找不到源代碼存在何處。但是測試小姐姐的活還是一定要幫,突然想起了 Arthas 可以熱更新應用代碼,按照網上的步驟,反編譯應用代碼,加上需要改動的邏輯,最後熱更新成功。對此,測試小姐姐很滿意,並表示下次會少提 Bug。
嘿嘿,以前一直對熱更新背後原理很好奇,藉著這個機會,研究一下熱更新的原理。
我們先來看下 Arthas 是如何熱更新的。
詳情參考:
假設我們現在有一個 HelloService 類,邏輯如下,現在我們使用 Arthas 熱更新代碼,讓其輸出 hello arthas。
public class HelloService {
public static void main(String[] args) throws InterruptedException {
while (true){
TimeUnit.SECONDS.sleep(1);
hello();
}
}
public static void hello(){
System.out.println("hello world");
}
}
首先運行 jad 命令反編譯 class 文件獲取源代碼,運行命令如下:。
jad --source-only com.andyxh.HelloService > /tmp/HelloService.java
拿到源代碼之後,使用 VIM 等文本編輯工具編輯源代碼,加入需要改動的邏輯。
ClassLoader然後使用 sc 命令查找加載修改類的 ClassLoader,運行命令如下:
$ sc -d com.andyxh.HelloService | grep classLoaderHash
classLoaderHash 4f8e5cde
這裏運行之後將會得到 ClassLoader 哈希值。
mc 內存編譯源代碼使用 mc 命令編譯上一步修改保存的源代碼,生成最終 class 文件。
$ mc -c 4f8e5cde /tmp/HelloService.java -d /tmp
Memory compiler output:
/tmp/com/andyxh/HelloService.class
Affect(row-cnt:1) cost in 463 ms.
運行 redefine 命令:
$ redefine /tmp/com/andyxh/HelloService.class
redefine success, size: 1
熱更新成功之後,程序輸出結果如下:
一般情況下,我們本地將會有源代碼,上面的步驟我們可以進一步省略,我們可以先在自己 IDE 上改動代碼,編譯生成 class 文件。這樣我們只需要運行 redefine 命令即可。也就是說實際上起到作用只是 redefine 。
Arthas 熱更新功能看起來很神奇,實際上離不開 JDK 一些 API,分別為 instrument API 與 attach API。
Java Instrumentation 是 JDK5 之後提供接口。使用這組接口,我們可以獲取到正在運行 JVM 相關信息,使用這些信息我們構建相關監控程序檢測 JVM。另外, 最重要我們可以替換和修改類的,這樣就實現了熱更新。
Instrumentation 存在兩種使用方式,一種為 pre-main 方式,這種方式需要在虛擬機參數指定 Instrumentation 程序,然後程序啟動之前將會完成修改或替換類。使用方式如下:
java -javaagent:jar Instrumentation_jar -jar xxx.jar
有沒有覺得這種啟動方式很熟悉,仔細觀察一下 IDEA 運行輸出窗口。
另外很多應用監控工具,如:zipkin、pinpoint、skywalking。
這種方式只能在應用啟動之前生效,存在一定的局限性。
JDK6 針對這種情況作出了改進,增加 agent-main 方式。我們可以在應用啟動之後,再運行 Instrumentation 程序。啟動之後,只有連接上相應的應用,我們才能做出相應改動,這裏我們就需要使用 Java 提供 attach API。
Attach API 位於 tools.jar 包,可以用來連接目標 JVM。Attach API 非常簡單,內部只有兩個主要的類,VirtualMachine 與 VirtualMachineDescriptor。
VirtualMachine 代表一個 JVM 實例, 使用它提供 attach 方法,我們就可以連接上目標 JVM。
VirtualMachine vm = VirtualMachine.attach(pid);
VirtualMachineDescriptor 則是一個描述虛擬機的容器類,通過該實例我們可以獲取到 JVM PID(進程 ID),該實例主要通過 VirtualMachine#list 方法獲取。
for (VirtualMachineDescriptor descriptor : VirtualMachine.list()){
System.out.println(descriptor.id());
}
介紹完熱更新涉及的相關原理,接下去使用上面 API 實現熱更新功能。
這裏我們使用 Instrumentation agent-main 方式。
首先需要編寫一個類,包含以下兩個方法:
public static void agentmain (String agentArgs, Instrumentation inst); [1]
public static void agentmain (String agentArgs); [2]
上面的方法只需要實現一個即可。若兩個都實現, [1] 優先級大於 [2],將會被優先執行。
接着讀取外部傳入 class 文件,調用 Instrumentation#redefineClasses,這個方法將會使用新 class 替換當前正在運行的 class,這樣我們就完成了類的修改。
public class AgentMain {
/**
*
* @param agentArgs 外部傳入的參數,類似於 main 函數 args
* @param inst
*/
public static void agentmain(String agentArgs, Instrumentation inst) {
// 從 agentArgs 獲取外部參數
System.out.println("開始熱更新代碼");
// 這裏將會傳入 class 文件路徑
String path = agentArgs;
try {
// 讀取 class 文件字節碼
RandomAccessFile f = new RandomAccessFile(path, "r");
final byte[] bytes = new byte[(int) f.length()];
f.readFully(bytes);
// 使用 asm 框架獲取類名
final String clazzName = readClassName(bytes);
// inst.getAllLoadedClasses 方法將會獲取所有已加載的 class
for (Class clazz : inst.getAllLoadedClasses()) {
// 匹配需要替換 class
if (clazz.getName().equals(clazzName)) {
ClassDefinition definition = new ClassDefinition(clazz, bytes);
// 使用指定的 class 替換當前系統正在使用 class
inst.redefineClasses(definition);
}
}
} catch (UnmodifiableClassException | IOException | ClassNotFoundException e) {
System.out.println("熱更新數據失敗");
}
}
/**
* 使用 asm 讀取類名
*
* @param bytes
* @return
*/
private static String readClassName(final byte[] bytes) {
return new ClassReader(bytes).getClassName().replace("/", ".");
}
}
完成代碼之後,我們還需要往 jar 包 manifest 寫入以下屬性。
## 指定 agent-main 全名
Agent-Class: com.andyxh.AgentMain
## 設置權限,默認為 false,沒有權限替換 class
Can-Redefine-Classes: true
我們使用 maven-assembly-plugin,將上面的屬性寫入文件中。
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<!--指定最後產生 jar 名字-->
<finalName>hotswap-jdk</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptorRefs>
<!--將工程依賴 jar 一塊打包-->
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifestEntries>
<!--指定 class 名字-->
<Agent-Class>
com.andyxh.AgentMain
</Agent-Class>
<Can-Redefine-Classes>
true
</Can-Redefine-Classes>
</manifestEntries>
<manifest>
<!--指定 mian 類名字,下面將會使用到-->
<mainClass>com.andyxh.JvmAttachMain</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
到這裏我們就完成熱更新主要代碼,接着使用 Attach API,連接目標虛擬機,觸發熱更新的代碼。
public class JvmAttachMain {
public static void main(String[] args) throws IOException, AttachNotSupportedException, AgentLoadException, AgentInitializationException {
// 輸入參數,第一個參數為需要 Attach jvm pid 第二參數為 class 路徑
if(args==null||args.length<2){
System.out.println("請輸入必要參數,第一個參數為 pid,第二參數為 class 絕對路徑");
return;
}
String pid=args[0];
String classPath=args[1];
System.out.println("當前需要熱更新 jvm pid 為 "+pid);
System.out.println("更換 class 絕對路徑為 "+classPath);
// 獲取當前 jar 路徑
URL jarUrl=JvmAttachMain.class.getProtectionDomain().getCodeSource().getLocation();
String jarPath=jarUrl.getPath();
System.out.println("當前熱更新工具 jar 路徑為 "+jarPath);
VirtualMachine vm = VirtualMachine.attach(pid);//7997是待綁定的jvm進程的pid號
// 運行最終 AgentMain 中方法
vm.loadAgent(jarPath, classPath);
}
}
在這個啟動類,我們最終調用 VirtualMachine#loadAgent,JVM 將會使用上面 AgentMain 方法使用傳入 class 文件替換正在運行 class。
這裏我們繼續開頭使用的例子,不過這裏加入一個方法獲取 JVM 運行進程 ID。
public class HelloService {
public static void main(String[] args) throws InterruptedException {
System.out.println(getPid());
while (true){
TimeUnit.SECONDS.sleep(1);
hello();
}
}
public static void hello(){
System.out.println("hello world");
}
/**
* 獲取當前運行 JVM PID
* @return
*/
private static String getPid() {
// get name representing the running Java virtual machine.
String name = ManagementFactory.getRuntimeMXBean().getName();
System.out.println(name);
// get pid
return name.split("@")[0];
}
}
首先運行 HelloService,獲取當前 PID,接着複製 HelloService 代碼到另一個工程,修改 hello 方法輸出 hello agent,重新編譯生成新的 class 文件。
最後在命令行運行生成的 jar 包。
HelloService 輸出效果如下所示:
普通的應用我們可以在 IDE 直接使用 Debug 模式調試程序,但是上面的程序無法直接使用 Debug。剛開始運行的程序碰到很多問題,無奈之下,只能選擇最原始的辦法,打印錯誤日誌。後來查看 arthas 的文檔,發現上面一篇文章介紹使用 IDEA Remote Debug 模式調試程序。
首先我們需要在 HelloService JVM 參數加入以下參數:
-Xrunjdwp:transport=dt_socket,server=y,address=8001
此時程序將會被阻塞,直到遠程調試程序連接上 8001 端口,輸出如下:
然後在 Agent-main 這個工程增加一個 remote 調試。
圖中參數如下:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8001
在 Agent-main 工程打上斷點,運行遠程調試, HelloService 程序將會被啟動。
最後在命令行窗口運行 Agent-main 程序,遠程調試將會暫停到相應斷點處,接下來調試就跟普通 Debug 模式一樣,不再敘述。
由於 Attach API 位於 tools.jar 中,而在 JDK8 之前 tools.jar 與我們常用JDK jar 包並不在同一個位置,所以編譯與運行過程可能找不到該 jar 包,從而導致報錯。
如果 maven 編譯與運行都使用 JDK9 之後,不用擔心下面問題。
maven 編譯問題
maven 編譯過程可能發生如下錯誤。
解決辦法為在 pom 下加入 tools.jar 。
<dependency>
<groupId>jdk.tools</groupId>
<artifactId>jdk.tools</artifactId>
<scope>system</scope>
<version>1.6</version>
<systemPath>${java.home}/../lib/tools.jar</systemPath>
</dependency>
或者使用下面依賴。
<dependency>
<groupId>com.github.olivergondza</groupId>
<artifactId>maven-jdk-tools-wrapper</artifactId>
<version>0.1</version>
<scope>provided</scope>
<optional>true</optional>
</dependency>
程序運行過程 tools.jar 找不到
運行程序時拋出 java.lang.NoClassDefFoundError,主要原因還是系統未找到 tools.jar 導致。
在運行參數加入 -Xbootclasspath/a:${java_home}/lib/tools.jar,完整運行命令如下:
並不是所有改動熱更新都將會成功,當前使用 Instrumentation#redefineClasses 還是存在一些限制。我們僅只能修改方法內部邏輯,屬性值等,不能添加,刪除方法或字段,也不能更改方法的簽名或繼承關係。
寫完熱更新代碼,收到一封系統郵件提示 xxx bug 待修復。恩,說好的少提 Bug 呢 o(╥﹏╥)o。
歡迎關注我的公眾號:程序通事,獲得日常乾貨推送。如果您對我的專題內容感興趣,也可以關注我的博客:
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能
※評比前十大台北網頁設計、台北網站設計公司知名案例作品心得分享
※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選
※評比南投搬家公司費用收費行情懶人包大公開