日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

java agent_如何脚踏实地构建Java Agent

發(fā)布時間:2023/12/3 java 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java agent_如何脚踏实地构建Java Agent 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

java agent

在構(gòu)建Plumbr的多年中,我們遇到了許多具有挑戰(zhàn)性的問題。 在其他方面,使Plumbr Java Agent可靠地執(zhí)行而不會危及客戶的應(yīng)用程序,是一個特別棘手的問題。 從實時系統(tǒng)中安全地收集所有需要的遙測會帶來很多問題。 其中一些非常簡單,而另一些則非常不明顯。

在此博客文章中,我們想與您分享一些示例,這些示例演示了在為我們的探員需要處理的一些看似簡單的方面提供支持時遇到的復(fù)雜性。 這些示例進(jìn)行了簡化,但摘錄自我們前一段時間需要解決的現(xiàn)實問題。 實際上,這些只是等待嘗試使用字節(jié)碼工具或JVMTI的人的冰山一角。

示例1:檢測一個簡單的Web應(yīng)用程序

讓我們從一個非常簡單的hello world網(wǎng)絡(luò)應(yīng)用開始 :

@Controller public class HelloWorldController {@RequestMapping("/hello")@ResponseBodyString hello() {return "Hello, world!";} }

如果啟動應(yīng)用程序并訪問相關(guān)的控制器,則會看到以下內(nèi)容:

$ curl localhost:8080/hello Hello, world!

作為一個簡單的練習(xí),讓我們將返回值更改為“ Hello,transformed world”。 自然,我們真正的Java代理不會對您的應(yīng)用程序執(zhí)行此類操作:我們的目標(biāo)是在不更改觀察到的行為的情況下進(jìn)行監(jiān)視。 但是為了使這個演示簡短而簡潔,請與我們聯(lián)系。 要更改返回的響應(yīng),我們將使用ByteBuddy :

public class ServletAgent {public static void premain(String arguments, Instrumentation instrumentation) { // (1)new AgentBuilder.Default().type(isSubTypeOf(Servlet.class)) // (2).transform((/* … */) ->builder.method(named("service")) // (3).intercept(MethodDelegation.to(Interceptor.class) // (4))).installOn(instrumentation); // (5)}}

這里發(fā)生了什么事:

  • 與Java代理一樣,我們提供了一個pre-main方法。 這將在實際應(yīng)用程序啟動之前執(zhí)行。 如果您想了解更多信息,ZeroTurnaround上有一篇很好的文章,提供了有關(guān)檢測Java代理如何工作的更多信息。
  • 我們發(fā)現(xiàn)所有類都是Servlet類的子類。 Spring的魔力最終也將融入Servlet。
  • 我們找到一種名為“服務(wù)”的方法
  • 我們攔截對該方法的調(diào)用,并將其委托給我們的自定義攔截器,該攔截器僅顯示“ Hello,transformed world!” 到ServletOutputStream。
  • 最后,我們告訴ByteBuddy根據(jù)上面的規(guī)則來檢測加載到JVM中的類
  • las,如果我們嘗試運行此命令,則應(yīng)用程序?qū)⒉辉賳?#xff0c;并引發(fā)以下錯誤:

    java.lang.NoSuchMethodError: javax.servlet.ServletContext.getVirtualServerName()Ljava/lang/String;at org.apache.catalina.authenticator.AuthenticatorBase.startInternal(AuthenticatorBase.java:1137)at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)

    發(fā)生了什么? 我們只觸摸了“ Servlet”類上的“ service”方法,但是現(xiàn)在JVM無法在另一個類上找到另一個方法。 腥。 讓我們嘗試看看在兩種情況下該類的加載位置。 為此,我們可以將-XX:+ TraceClassLoading參數(shù)添加到JVM啟動腳本中。 如果沒有Java代理,則從Tomcat加載有問題的類:

    [Loaded javax.servlet.ServletContext from jar:file:app.jar!/BOOT-INF/lib/tomcat-embed-core-8.5.11.jar!/]

    但是,如果再次啟用Java代理,則會從其他位置加載它:

    [Loaded javax.servlet.ServletContext from file:agent.jar]

    啊哈! 實際上,我們的代理直接依賴于Gradle構(gòu)建腳本中定義的servlet API:

    agentCompile "javax.servlet:servlet-api:2.5"

    可悲的是,此版本與Tomcat期望的版本不匹配,因此出現(xiàn)錯誤。 我們用這種依賴性指定哪些類儀器:isSubTypeOf(Servlet ),但是這也造成了我們加載的servlet庫的不兼容版本。 要擺脫這種情況實際上并不那么容易:要檢查我們嘗試檢測的類是否是另一種類型的子類型,我們必須知道其所有父類或接口。

    盡管有關(guān)直接父代的信息存在于字節(jié)碼中,但傳遞繼承卻不存在。 實際上,在進(jìn)行檢測時,相關(guān)的類甚至可能尚未加載。 要解決此問題,我們必須在運行時找出客戶端應(yīng)用程序的整個類層次結(jié)構(gòu)。 有效地收集類層次結(jié)構(gòu)是一項艱巨的任務(wù),它本身就有很多陷阱,但是這里的教訓(xùn)很明顯:規(guī)范不應(yīng)加載客戶端應(yīng)用程序可能也要加載的類,尤其是來自不兼容版本的類。

    這只是一條小小的龍,當(dāng)您嘗試使用字節(jié)碼或嘗試與類加載器混為一談時,它已遠(yuǎn)離軍團(tuán)等待著您。 我們已經(jīng)看到了許多其他問題:類裝入死鎖,驗證程序錯誤,多個代理之間的沖突,本機(jī)JVM結(jié)構(gòu)膨脹,就這樣吧!

    但是,我們的代理并不限于使用Instrumentation API。 要實現(xiàn)某些功能,我們必須更深入。

    示例2:使用JVMTI收集有關(guān)類的信息

    可以采用多種不同方法來確定類型層次結(jié)構(gòu),但是在本文中,我們僅關(guān)注其中之一-JVMTI (JVM工具接口)。 它使我們能夠編寫一些本機(jī)代碼,以訪問JVM的更底層的遙測和工具功能。 除其他外,可以為應(yīng)用程序或JVM本身中發(fā)生的各種事件訂閱JVMTI回調(diào)。 我們當(dāng)前感興趣的是ClassLoad回調(diào)。 這是一個如何使用它來訂閱類加載事件的示例 :

    static void register_class_loading_callback(jvmtiEnv* jvmti) {jvmtiEventCallbacks callbacks;jvmtiError error;memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));callbacks.ClassLoad = on_class_loaded;(*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));(*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, (jthread)NULL); }

    這將使JVM在類加載的早期階段執(zhí)行我們定義的on_class_loaded函數(shù)。 然后,我們可以編寫此函數(shù),以便它通過JNI調(diào)用代理的java方法,如下所示:

    void JNICALL on_class_loaded(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread, jclass klass) {(*jni)->CallVoidMethod(jni, agent_in_java, on_class_loaded_method, klass); }

    為了簡單起見,在Java Agent中,我們將只打印類的名稱:

    public static void onClassLoaded(Class clazz) {System.out.println("Hello, " + clazz); }

    閉上你的眼睛一分鐘,嘗試想象這里可能出什么問題。

    你們中許多人可能認(rèn)為這將崩潰。 畢竟,您在本機(jī)代碼中犯的每個錯誤都有可能通過段錯誤使整個應(yīng)用程序崩潰。 但是,在這個特定示例中,我們實際上將獲得一些JNI錯誤和一個Java異常:

    Error: A JNI error has occurred, please check your installation and try again Error: A JNI error has occurred, please check your installation and try again Hello, class java.lang.Throwable$PrintStreamOrWriter Hello, class java.lang.Throwable$WrappedPrintStream Hello, class java.util.IdentityHashMap Hello, class java.util.IdentityHashMap$KeySet Exception in thread "main" java.lang.NullPointerExceptionAt JvmtiAgent.onClassLoaded(JvmtiAgent.java:23)

    讓我們暫時將JNI錯誤放在一邊,然后集中討論Java異常。 真令人驚訝 在這里什么可以為空? 選項不多,所以讓我們檢查一下并再次運行:

    public static void onClassLoaded(Class clazz) {if(System.out == null) {throw new AssertionError("System.out is null");}if(clazz == null) {throw new AssertionError("clazz is null");}System.out.println("Hello, " + clazz); }

    但是,a,我們?nèi)匀粫龅较嗤漠惓?#xff1a;

    Exception in thread "main" java.lang.NullPointerExceptionAt JvmtiAgent.onClassLoaded(JvmtiAgent.java:31)

    讓我們稍等一下,然后對代碼進(jìn)行另一個簡單的更改:

    public static void onClassLoaded(Class clazz) {System.out.println("Hello, " + clazz.getSimpleName()); }

    輸出格式的這種看似微不足道的變化導(dǎo)致了行為上的巨大變化:

    Error: A JNI error has occurred, please check your installation and try again Error: A JNI error has occurred, please check your installation and try again Hello, WrappedPrintWriter Hello, ClassCircularityError # # A fatal error has been detected by the Java Runtime Environment: # # Internal Error (systemDictionary.cpp:806), pid=82384, tid=0x0000000000001c03 # guarantee((!class_loader.is_null())) failed: dup definition for bootstrap loader?

    啊,終于崩潰了! 真高興! 實際上,這為我們提供了很多信息,有助于查明根本原因。 具體來說,現(xiàn)在明顯的ClassCircularityError和內(nèi)部錯誤消息非常明顯。 如果要查看JVM源代碼的相關(guān)部分,您會發(fā)現(xiàn)一個非常復(fù)雜且混合在一起的算法,用于解析類。 它確實可以單獨運行,但仍然很脆弱,但是通過執(zhí)行一些不尋常的操作(如覆蓋ClassLoader.loadClass或拋出一些JVMTI回調(diào))很容易被破壞。

    我們在這里所做的是將類加載潛入加載類的中間,這似乎是一項冒險的業(yè)務(wù)。 跳過故障排除過程,而該故障排除過程將自己撰寫一篇博客文章,涉及很多本機(jī)挖掘工作,讓我們僅概述第一個示例中發(fā)生的事情:

  • 我們嘗試加載一個類,例如launcher.LauncherHelper
  • 為了打印出來,我們嘗試加載io.PrintStream類,遞歸到相同的方法。 由于遞歸是通過JVM內(nèi)部以及JVMTI和JNI進(jìn)行的,因此在任何堆棧跟蹤中都看不到它。
  • 現(xiàn)在也必須打印出PrintStream。 但是還沒有完全加載,所以我們收到一個JNI錯誤
  • 現(xiàn)在,我們繼續(xù)嘗試?yán)^續(xù)打印。 要連接字符串,我們需要加載lang.StringBuilder。 重復(fù)同樣的故事。
  • 最后,由于類加載不多,我們得到了一個空指針異常。
  • 好吧,那很復(fù)雜。 但是畢竟,JVMTI文檔非常明確地表示我們應(yīng)該格外小心:

    “此事件是在加載課程的早期階段發(fā)送的。 因此,該類應(yīng)謹(jǐn)慎使用。 請注意,例如,方法和字段尚未加載,因此對方法,字段,子類等的查詢不會給出正確的結(jié)果。 請參見Java語言規(guī)范中的“類和接口的加載”。 對于大多數(shù)目的, ClassPrepare 事件將更加有用。”

    確實,如果我們使用此回調(diào),那么就不會有這樣的困難。 但是,在設(shè)計用于監(jiān)視目的的Java代理時,有時會被迫進(jìn)入JVM的非常暗的區(qū)域以支持我們所需的產(chǎn)品功能,而開銷卻足以降低生產(chǎn)部署的成本。

    帶走

    這些示例說明了一些看似無辜的設(shè)置和構(gòu)建Java代理的幼稚方法如何以令人驚訝的方式讓您大吃一驚。 實際上,以上內(nèi)容幾乎不涉及我們多年來發(fā)現(xiàn)的內(nèi)容。

    再加上數(shù)量眾多的不同平臺,此類代理將需要完美運行(不同的JVM供應(yīng)商,不同的Java版本,不同的操作系統(tǒng)),并且本來就很復(fù)雜的任務(wù)變得更具挑戰(zhàn)性。

    但是,通過盡職調(diào)查和適當(dāng)?shù)谋O(jiān)視,構(gòu)建可靠的Java代理是一項可以由一組敬業(yè)工程師解決的任務(wù)。 我們在自己的產(chǎn)品中自信地運行Plumbr Agent,并且不會因此而睡不著。

    翻譯自: https://www.javacodegeeks.com/2017/06/shoot-foot-building-java-agent.html

    java agent

    總結(jié)

    以上是生活随笔為你收集整理的java agent_如何脚踏实地构建Java Agent的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 亚洲一区二区三区激情 | 亚洲欧美另类图片 | 国偷自拍| 性xxx法国hd极品 | 曰韩一级片 | 丰满人妻一区二区三区免费 | 永久免费看片在线播放 | 国产女教师bbwbbwbbw | www.99视频| 天天透天天干 | 日本一本一道 | 天天色视频 | 中文字幕一区二区三区在线不卡 | 福利视频大全 | 热久久国产精品 | 看av网| xxx一区| 久久综合九色综合网站 | 日本一区电影 | 91成人在线视频 | 日韩操 | 国产99页| 91免费看片网站 | 久久成人网18网站 | 日韩一区二区免费在线观看 | 青青草久久 | 欧美日韩视频在线观看免费 | 亚洲影视一区二区 | 成人污 | 欧美无砖区 | 亚洲在线成人 | 欧美极品三级 | 靠逼在线观看 | 国产精品伦 | 福利小视频在线播放 | a级一片 | 特级精品毛片免费观看 | x88av在线 | 天堂综合网久久 | 欧美性jizz18性欧美 | 亚洲视频精品一区 | 国内自拍一区 | 三上悠亚亚洲一区 | 欧美xxx性 | 国产乱真实合集 | 亚洲少妇一区二区 | 国产三级在线观看完整版 | 亚洲色图首页 | 久久久久国产精品人妻 | 女同一区二区 | 国产激情一区二区三区在线观看 | 国产东北露脸精品视频 | 福利免费在线观看 | 吃奶av| 久久久一级黄色片 | 91久久国产综合久久 | 五级黄高潮片90分钟视频 | 久久天天躁狠狠躁夜夜躁2014 | 成人午夜sm精品久久久久久久 | 性三级视频 | 黄网站在线观看视频 | 日日夜夜爽 | 国产美女免费无遮挡 | 欧美黄色大片免费看 | 欧美日韩视频在线观看免费 | 午夜免费在线 | 日韩成人短视频 | 天堂福利在线 | 久久久国产成人一区二区三区 | 中国女人做爰视频 | 色午夜av | 欧美91看片特黄aaaa | 天堂在线中文 | 国产又粗又猛又爽又黄的网站 | 黄色avv| 欧美日韩亚洲一区 | 精品99久久久久成人网站免费 | 曰曰操 | 国产精品视频一二三区 | 日本一本在线观看 | 亚洲再线 | 婷婷色中文网 | 国产剧情av在线 | 夜色一区二区 | 青青毛片 | 黄色片视频免费看 | 色中文在线 | 亚洲国产精品无码久久久久高潮 | 久久久精品蜜桃 | 亚洲精品理论 | 97人人澡| 亚欧视频在线观看 | 人物动物互动39集免费观看 | 尤物视频网站在线观看 | 五月天中文字幕 | 日韩在线视频免费 | 中国新婚夫妻性猛交 | 黄网www | 又粗又猛又爽又黄的视频 |