本文檔描述了使用RMI Spy會對你的應用程式的執行產生怎樣的影響。
在大多數情況下,你不會注意到我們程式執行時的任何不同。但是,如果你的程式沒有按照你預期去執行,此時,你將會意識到RMI Spy能為你偵錯工具帶來的方便了。這是一個技術文檔,而不是一個RMI Spy協助文檔。
1,RMI Spy是什嗎?
RMI Spy負責收集和顯示你的應用程式運行時產生的和RMI相關的事件。具體的說,它監控所有的遠程調用(包括你應用程式產生的外部調用和其他應用程式調用你的應用程式提供的遠程服務)。它同時可以顯示類載入事件,從而協助你調試"類載入"問題,這些問題通常會出現在RMI系統開發的過程中。
2,RMI Spy是如何工作的?
i)介紹:
RMI Spy的工作基於Logging API,這些Logging API被RMI介面使用。如果RMI Spy沒有被開啟,你可以手動開啟"logging properties"(你可以在RMI回合組態的"RMI Launch"標籤裡勾選開啟)以及用來監控輸出的控制台視窗。
比如:開啟"java.rmi.server.logCalls"屬性,產生類似下面的輸出(為顯示清楚,添加了分行符號):
20/05/2006 13:35:06 sun.rmi.server.UnicastServerRef logCallFINER: RMI TCP Connection(2)-192.168.2.100: [192.168.2.100: \ demo.rmi.print.server.RemotePrinterImpl[1]: \ public abstract int demo.rmi.print.server.RemotePrinter.submitJob( \ java.lang.String) throws java.rmi.RemoteException]
這樣的輸出並不利於閱讀,也沒有提供任何有意義的資訊。
ii)RMI Spy介面
RMI Spy並不剖析器的輸出(儘管理論上它能夠分析),因為這個方法並不可靠---程式的輸出可能會干擾RMI日誌。取而代之的是,它與RMI的日誌系統銜接,並能在事件產生時及時捕獲。RMI Spy運行組件(作為應用程式的一部分運行)使用日誌API(Logging API)來註冊它自己的代理從而收集RMI事件並將它們推送給RMI外掛程式進行分析並顯示在RMI Spy視圖中。
為了避免修改應用程式代碼,RMI Spy使用了一個啟動封裝器(launch wrapper)。這意味著RMI Spy的運行組件是運行在你的程式內部的(當然,前提是RMI Spy被啟用了)。當應用程式啟動後,RMI Spy JAR會被添加到classpath,launch wrapper(類net.genady.rmi.logger.Runner)將被作為主類(main class)。應用程式的主類和參數會被當做參數傳遞到launch wrapper。
launch wrapper 負責主持日誌代理(logging handlers),同RMI 外掛程式建立一個TCP串連,並且經控制權傳遞給真正的應用程式。顯而易見的是,在同一個VM進程中同時運行wrapper,這對於你的應用程式是有影響的。
下一節就會討論這些影響的細節。
iii)儀器的使用(The use of instrumentation)
RMI外掛程式使用位元組碼儀器(ASM庫)來執行一些進階功能(比如時間測量)。它將不會對你的程式產生任何特別的影響,因為它只執行非常非常少的一些系統類別。需要說明的是,RMI外掛程式必須使用JDK1.5或者JDK1.6版本(如果使用的版本不對,外掛程式將自動關閉),這意味著如果你使用自己的儀器工具(-javaagent)的話,你就要多加小心了,當然,在大多數情況下,這個不是問題。
RMI Spy會調用某些對象的一些方法,這些對象會在遠程調用過程中作為值傳遞的參數或者傳回值。在以下類中,它會選擇調用toString()方法:所有的原始類型,封裝類,RULs和URIs,InetAddress,枚舉類型,字元序列( CharSequence)的實現和數字類(Number class)的子類。它同樣會在集(Collection)的實現中調用size()方法。這些方法的調用會產生無法預期的副作用,比如擷取鎖/監視器,建立網路連接等等。
3,運行模式和偵錯模式的不同
RMI Spy沒有使用調試API,因此,在運行模式和偵錯模式下,RMI Spy的操作沒有任何區別。
4,支援的JDK/JVM供應商
RMI Spy依賴於Sun的內部API。但是,很多運行RMI的JDK提供者都是由Sun授權許可的,因此,大多數標準JVM都可以運行RMI Spy。要擷取最新的相容性列表,請訪問website
5,堆疊追蹤
RMI Spy使用一個簡單的啟動封裝器來運行一些配置,然後通過reflection APIs將控制權交個你的主類(main class)。因此,所有由主線程中產生的堆棧追蹤會有以下的幾行提示(假設你的主類是:demo.rmi.print.client.PrintClient):
at demo.rmi.print.client.PrintClient.main(PrintClient.java:35) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke( NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke( DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:324) at net.genady.rmi.logger.Runner.main(Runner.java:138)
堆棧追蹤在其他的線程裡產生,並且不會產生影響。
6,輔助線程
應用程式和RMI外掛程式的通訊時通過本地TCP串連進行的。儘管是本地串連,它仍舊有可能因為各種原因而被阻塞(比如本地防火牆)。因此,當有事件要傳送給RMI外掛程式是,運行組件會把那個事件放到事件隊列中,專用守護線程會執行所有的通訊工作。通過這種方法,應用程式線程永遠不會被RMI外掛程式阻塞,而對應用程式的影響將會降到最低。這個專用守護線程的名字是"RMI Plug-in for Eclipse Log Events Reporter",大多數時候,它是閒置。
7,關閉鉤子(A Shutdown hook)
一個應用程式調用方法System.exit()或者相似方法來結束執行的情況是常見的。在這種情況下,RMI Spy的運行組件必須確保所有被收集的事件都已經被傳送給運行在eclipse中的RMI Spy部分了。為了達到這個目的,RMI外掛程式使用了"shutdown hooks"功能。因此,這可能會花費較長的事件去關閉一個應用程式(直到所有的應用程式都被傳送)。通常,這個過程花費幾毫秒,但對於RMI密集型程式,這個過程會多用10到100毫秒直到程式終止。
8,使用RMI的Logging屬性(Logging properties)
RMI Spy沒有直接使用任何logging屬性,因此,你可以開啟他們來查看正常的基於控制台的日誌。但是,設定某些屬性,比如"sun.rmi.server.suppressStackTraces"會導致RMI Spy丟失某些資訊。因此最好讓RMI Spy來顯示這些日誌資訊兵,要避免直接修改這些日誌屬性。
9,使用日誌API
(這需要更多的技術和對Logging APIs的瞭解)RMI Spy把RMI loggers的logging level修改為"ALL"。你之所在控制台上看不到RMI的日誌是因為RMI日誌的控制者擁有更高的等級(預設是"SILENT")。如果因為某些原因日誌控制者等級被修改了,或者另一個控制者被註冊到RMI日誌,他們將擷取他們本不會擷取到的事件(如果RMI
Spy沒有被使用的話)。當然,如果你手動修改了RMI日誌等級,你就可以影響RMI Spy的行為了。
英語原文:http://www.genady.net/rmi/v20/docs/spy/spy_effects.html