您是否編寫有錯誤的代碼? 不,當然不。 對于我們其余的確實會編寫帶有錯誤的代碼的凡人,我想解決一個非常敏感的問題:調試在生產服務器上運行的應用程序。
因此,您的應用程序已準備好進行部署。 單元測試全部成功, 測試人員發現了一些立即修復的小錯誤,與其他部門的模塊進行的集成測試非常順利, QA部門沒有任何投訴,而UAT則以鮮艷的色彩通過了。 因此,您的精妙代碼現在已啟動并在生產服務器上運行。
當不可思議的事情發生時。 您的客戶注意到應用程序上的一些錯誤行為,并且他的一些客戶已經開始抱怨。 似乎有些討厭的小錯誤設法通過了所有測試過程,并投入到了實際系統中。 客戶的用戶向客戶施加壓力,客戶經理向您的經理施加壓力,并且,您的經理開始向您施加壓力。
您啟動測試服務器并嘗試重現該錯誤 。 las,所有內容都可以在測試服務器上正常運行,因此可能是一個奇怪的配置問題或一個導致問題行為的邊緣情況。 最重要的是,您無法使用測試床來跟蹤錯誤。
一個貧窮的開發商應該怎么做? 調試在生產服務器上運行的應用程序。 請注意,這是萬不得已的方法,并且在發現該錯誤的所有其他嘗試均失敗時。 確保在生產服務器(為大量用戶提供服務)上進行任何細微的錯誤舉動都會嚴重影響應用程序,并導致更大的問題或整個服務中斷。
因此,如果您決定走高風險之路,請繼續閱讀該如何做。 開始之前的一些基本準則。 首先,讓您的客戶知道您將連接到生產系統并“執行一些檢查”。 您不必具體說明將要做什么,但是在沒有通知客戶的情況下當然也不會做任何事情。 其次,選擇實際流量盡可能低的時間。 這是不費吹灰之力的事情,您希望受影響的用戶越少越好,而且您不希望服務器在高負載下運行。 第三,要小心,不要倉促行事。 可能會有壓力,但是要花點時間,這將更容易找出問題所在。
我將使用JBoss AS和Eclipse,以提供有關如何執行調試的動手示例。 我們將通過在JBoss上部署簡單的代碼并執行特定的方法來模擬正在運行的應用程序。 在大多數基于Java的應用程序服務器中,啟動啟用了遠程調試的JVM只是配置問題。 然后,使用您喜歡的IDE(在我的情況下為Eclipse)在服務器端口上附加調試器并開始調試。 請注意,啟用遠程調試對性能的影響很小,但是我通常更喜歡啟用調試選項,以便可以隨意連接到服務器。 在另一種情況下,為了應用新設置,需要重新啟動JVM,從而重新啟動服務器。
首先,讓我們創建執行調試的代碼。 我們將使用Java MBean ,該Java MBean部署在JBoss上并具有預定義的生命周期。 MBean是托管Bean,代表要管理的資源的Java對象。 JBoss實際上提供了MBean Server的實現,因此可以在其上部署MBean。
最簡單的方法是擴展ServiceMBeanSupport抽象類并實現符合ServiceMBean接口的服務 。 首先,我們創建一個名為“ SimpleMBeanProject”的Eclipse項目。 然后,我們將創建一個服務必須實現的接口。 源代碼是:
package com.javacodegeeks.jboss;import org.jboss.system.ServiceMBean;public interface SimpleServiceMBean extends ServiceMBean {void start() throws Exception;void stop();String getName();void execute(String input);}
然后,我們創建適當的實現類:
package com.javacodegeeks.jboss;import org.jboss.system.ServiceMBeanSupport;public class SimpleService extends ServiceMBeanSupport implements SimpleServiceMBean { @Overridepublic void start() throws Exception {System.out.println("Starting SimpleService MBean");}@Overridepublic void stop() {System.out.println("Stopping SimpleService MBean");}@Overridepublic String getName() {return SimpleService.class.getCanonicalName();}public void execute(String input) {System.out.println("Executing with input " + input);}}
該代碼確實很簡單,但是具有足夠的功能來進行演示。 “執行”方法是為了模擬正在運行的應用程序而將被調用的方法。
部署MBean的一種方法是將兩個類捆綁到Service Archive(SAR)文件中。 該文件是一個壓縮文件,其中包括MBean類和相應的部署描述符,在這種情況下,該文件是名為“ jboss-service.xml”的文件,其內容如下:
<?xml version="1.0" encoding="UTF-8"?><service><mbean code="com.javacodegeeks.jboss.SimpleService"name="javacodegeeks:name=SimpleService"></mbean></service>
“ jboss-service.xml”文件必須位于SAR捆綁包內名為“ META-INF”的文件夾內。 然后,必須將歸檔文件放在<jboss-base-dir> / server / default / deploy目錄中,以便部署MBean。 存檔可以手動創建,畢竟它只是一個壓縮文件,但是更優雅的方法是創建一個ANT腳本來自動執行該過程。
<?xml version="1.0" encoding="UTF-8"?><project name="SimpleService Project Build" default="build-sar"><target name="init"><property name="base.dir" value="."/><property name="lib.dir" value="${base.dir}/lib"/><property name="bin.dir" value="${base.dir}/bin"/><property name="src.dir" value="${base.dir}/src" /><property name="dist.dir" value="${base.dir}/dist" /><delete dir="${dist.dir}"/><mkdir dir="${dist.dir}"/></target><target name="compile" depends="init"><echo message="Compiling source files..." /><javac destdir="${bin.dir}" debug="on"><src path="${src.dir}" /><classpath><fileset dir="${lib.dir}"><include name="**/*.jar" /></fileset></classpath><include name="**/*.java" /></javac></target><target name="build-sar" depends="compile"><jar destfile="dist/SimpleService.sar"><zipfileset dir="bin"><include name="com/javacodegeeks/**/*.class" /></zipfileset><zipfileset dir="resources" prefix="META-INF"><include name="jboss-service.xml" /></zipfileset></jar></target></project>
部署SAR后,“ SimpleService” MBean將出現在服務器的JMX控制臺上。 這是一個Web界面,可以通過以下URL訪問(相應地替換主機):
http://主機:8080 / jmx-console
向下滾動,直到找到“ name = SimpleService”條目,然后單擊鏈接。 Mbean的屬性以及操作列表將顯示在此處。
您可以使用String參數手動調用“ execute”方法,相應的輸入將被寫入標準輸出。
好的,在部署SAR之后,就該開始調試了。 第一步是使JBoss的JVM在啟用遠程套接字調試的情況下啟動。 當然,這是通過JVM的參數完成的,并且要配置它,您必須執行以下操作:
Linux平臺:打開文件/bin/run.conf并取消注釋讀取的行(刪除“#”)
JAVA_OPTS =” $ JAVA_OPTS -Xrunjdwp:transport = dt_socket,address = 8787,server = y,suspend = n”
Windows平臺:打開文件/bin/run.bat并取消注釋該行(刪除“ rem”關鍵字) 設置JAVA_OPTS = -Xdebug -Xrunjdwp:transport = dt_socket,地址= 8787,服務器= y,暫掛= n%JAVA_OPTS%
將使用的端口是8787。請確保將“ suspend”參數設置為“ n”(禁用),或者在另一種情況下,當服務器首次啟動時它將停止并等待遠程調試器執行在繼續操作之前先附加。
之后,正常啟動服務器。 現在是時候通過Eclipse連接到服務器了。 轉到“運行? 調試配置…”,然后雙擊“遠程Java應用程序”選項。 在“連接”選項卡上,確保選擇“ SimpleMBeanProject”,提供遠程“主機” IP地址或主機名(在我的情況下為“ localhost”)和服務器偵聽傳入的調試會話的“端口”(8787)按照之前的配置)。 最后,請確保未選擇“允許終止遠程VM”,因為如果選擇了“允許終止遠程VM”,則服務器的JVM將在斷開調試時關閉。 生產服務器確實不是一件好事。 好的,點擊“調試”按鈕繼續。
如果未啟用遠程調試,或者存在連接問題(也許是防火墻問題),您將看到以下圖像:
但是,如果一切正常,Eclipse調試器會將其自身附加到服務器,您應該能夠看到類似以下內容的信息:
如您所見,受監視的線程顯示在“調試”視圖中。 如果未顯示該視圖,請轉到“窗口? 顯示視圖? 其他…”,然后在“調試”類別下進行搜索。
現在,假設“ SimpleService”類的“ execute”方法模擬在每個傳入請求下在生產服務器上執行的代碼。 如果要在測試服務器上執行調試,那么您要做的就是在方法內部添加一個斷點,觸發請求并繼續進行調試。 但是,類似的事情絕對不會在生產服務器上運行。 切換斷點時,所有請求將暫停并等待您的操作(如果執行路徑當然是通過該方法傳遞的)。 這將停止請求的執行,并且很可能會引起用戶的注意。 此外,您將不得不同時監控的請求數量使您不知所措。
您要做的是添加一個條件斷點,該斷點僅在提供特定輸入(即您提供的輸入)時停止。 因此,斷開與遠程服務器的連接,然后在“ execute”方法內添加一個斷點(在第23行)。 然后,右鍵單擊斷點,然后從出現的菜單中選擇“斷點屬性”(最后一個)。
屬性菜單將會出現。 選中“啟用條件”復選框,然后在文本區域內輸入條件。 斷點將是有效的,并且僅在該條件為真時才掛起執行。 請注意,您實際上是在文本區域內編寫Java代碼,并且可以為此使用熟悉的代碼幫助(使用Ctrl + Space)。 Eclipse是一個不可思議的工具嗎? 我們希望僅在方法的參數為“ myinput”時才插入斷點。
再次啟動遠程調試,現在您可以確定在提供您自己的輸入時將暫停執行。 為了演示這一點,請返回JMX控制臺和“ SimpleService” MBean視圖。 在“執行”方法中,使用隨機參數:
點擊“調用”按鈕,注意Eclipse沒有暫停執行。 現在,使用“ myinput”作為輸入值,單擊“ Invoke”,然后注意Eclipse捕獲了執行。
現在,您可以繼續使用眾所周知的調試選項(進入方法,觀察變量值等),而不必擔心系統用戶會受到影響。
您可以在此處下載Eclipse項目。
快樂尋找蟲子!
- JBoss 4.2.x Spring 3 JPA Hibernate教程
- GWT EJB3 Maven JBoss 5.1集成教程
- JBoss Portal上的“ Hello World” portlet
翻譯自: https://www.javacodegeeks.com/2010/06/debug-production-server-eclipse.html