亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JSP > 正文

開發一個調試JSP的Eclipse插件

2024-09-05 00:20:00
字體:
來源:轉載
供稿:網友
  本文通過開發一個jsp 編輯器插件的示例,介紹了 eclipse 中設置 jsp 斷點的方法,以及如何遠程調試 jsp。作為基礎知識,本文的前兩部分描述了 java debug 和 jsr-45 的基本原理。

  環境要求: 本文的代碼是在 eclipse3.0.0,jdk1.4.2 和 tomcat5.0.5 上測試過的。

  java 調試框架(jpda)簡介

  jpda 是一個多層的調試框架,包括 jvmdi、jdwp、jdi 三個層次。java 虛擬機提供了 jpda 的實現。其開發工具作為調試客戶端,可以方便的與虛擬機通訊,進行調試。eclipse 正是利用 jpda 調試 java 應用,事實上,所有 java 開發工具都是這樣做的。sun jdk 還帶了一個比較簡單的調試工具以及示例。
  • jvmdi 定義了虛擬機需要實現的本地接口
  • jdwp 定義了jvm與調試客戶端之間的通訊協議

    調試客戶端和jvm 既可以在同一臺機器上,也可以遠程調試。jdk 會包含一個默認的實現 jdwp.dll,jvm 允許靈活的使用其他協議代替 jdwp。sun jdk 有兩種方式傳輸通訊協議:socket 和共享內存(后者僅僅針對 windows),一般我們都采用 socket 方式。

    你可以用下面的參數,以調試模式啟動jvm

      -xdebug -xnoagent -xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n   -xrunjdwp     jvm 加載 jdwp.dll     transport=dt_socket   使用 socket 傳輸    address      表示調試端口號    server=y     表示 jvm 作為服務器,建立 socket    suspend=n    表示啟動過程中,jvm 不會掛起去等待調試客戶端連接

  • jdi 則是一組java接口

    如果是一個 java 的調試客戶端,只要實現 jdi 接口,利用jdwp協議,與虛擬機通訊,就可以調用jvmdi了。
  下圖為 jpda 的基本架構:

                           components                        debugger interface                               /    |-----------------------|                /     |     vm       |  debuggee ----(      |-----------------------|  <------- jvmdi - java vm debug interface                /     |   back-end     |                 /    |-----------------------|                 /           |   comm channel -(           |  <--------------- jdwp - java debug wire protocol                 /           |                      |---------------------|                      | front-end      |                      |---------------------|  <------- jdi - java debug interface                      |      ui      |                      |---------------------|              

  參見:http://java.sun.com/j2se/1.4.2/docs/guide/jpda/architecture.html

  eclipse作為一個基于 java 的調試客戶端,利用 org.eclipse.jdt.debug plugin 提供了jdi 的具體實現。jdi 接口主要包含下面 4 個包
com.sun.jdi  com.sun.jdi.connect  com.sun.jdi.event  com.sun.jdi.request 
  本文不對 jdi 進行深入闡述,這里重點介紹 jdi 中與斷點相關的接口。
  • com.sun.jdi

    主要是jvm(virtualmachine) 線程(threadreference) 調用棧(stackframe) 以及類型、實例的描述。利用這組接口,調試客戶端可以用類似類反射的方式,得到所有類型的定義,動態調用 class 的方法。
  • com.sun.jdi.event

    封裝了jvm 產生的事件, jvm 正是將這些事件通知給調試客戶端的。例如 breakpointevent 就是 jvm 執行到斷點的時候,發出的事件;classprepareevent就是 class 被加載時發出的事件。

  • com.sun.jdi.request

    封裝了調試客戶端可以向 jvm發起的請求。例如 breakpointrequest 向 jvm 發起一個添加斷點的請求;classpreparerequest 向 jvm 注冊一個類加載請求,jvm 在加載指定 class 的時候,就會發出一個 classprepareevent 事件。
  jsr-45規范

  jsr-45(debugging support for other languages)為那些非 java 語言寫成,卻需要編譯成 java 代碼,運行在 jvm 中的程序,提供了一個進行調試的標準機制。也許字面的意思有點不好理解,什么算是非 java 語言呢?其實 jsp 就是一個再好不過的例子,jsr-45 的樣例就是一個 jsp。

  jsp的調試一直依賴于具體應用服務器的實現,沒有一個統一的模式,jsr-45 針對這種情況,提供了一個標準的模式。我們知道,java 的調試中,主要根據行號作為標志,進行定位。但是 jsp 被編譯為 java 代碼之后,java 行號與 jsp 行號無法一一對應,怎樣解決呢?

  jsr-45 是這樣規定的:jsp 被編譯成 java 代碼時,同時生成一份 jsp 文件名和行號與 java 行號之間的對應表(smap)。jvm 在接受到調試客戶端請求后,可以根據這個對應表(smap),從 jsp 的行號轉換到 java 代碼的行號;jvm 發出事件通知前, 也根據對應表(smap)進行轉化,直接將 jsp 的文件名和行號通知調試客戶端。

  我們用 tomcat 5.0 做個測試,有兩個 jsp,hello.jsp 和 greeting.jsp,前者 include 后者。tomcat會將他們編譯成 java 代碼(hello_jsp.java),java class(hello_jsp.class) 以及 jsp 文件名/行號和 java 行號之間的對應表(smap)。

  hello.jsp:

           1    <html>               2    <head>               3    <title>hello example</title>               4    </head>               5    <body>               6    <%@ include file="greeting.jsp" %>               7    </body>               8    </html>             

  greeting.jsp:

1 hello there!<p> 2 goodbye on <%= new java.util.date() %>

  jsp 編譯后產生的hello_jsp.java 如下:

hello_jsp.java: 1      package org.apache.jsp; 2 3      import javax.servlet.*; 4      import javax.servlet.http.*; 5      import javax.servlet.jsp.*; 6       7      public final class hello_jsp extends org.apache.jasper.runtime.httpjspbase 8          implements org.apache.jasper.runtime.jspsourcedependent { 9       10        private static java.util.vector _jspx_dependants; 11       12        static { 13          _jspx_dependants = new java.util.vector(1); 14          _jspx_dependants.add("/greeting.jsp"); 15        } 16       17        public java.util.list getdependants() { 18          return _jspx_dependants; 19        } 20       21  public void _jspservice(httpservletrequest request, httpservletresponse response) 22              throws java.io.ioexception, servletexception { 23       24          jspfactory _jspxfactory = null; 25          pagecontext pagecontext = null; 26          httpsession session = null; 27          servletcontext application = null; 28          servletconfig config = null; 29          jspwriter out = null; 30          object page = this; 31          jspwriter _jspx_out = null; 32       33       34          try { 35            _jspxfactory = jspfactory.getdefaultfactory(); 36            response.setcontenttype("text/html"); 37            pagecontext = _jspxfactory.getpagecontext(this, request, response, 38               null, true, 8192, true); 39            application = pagecontext.getservletcontext(); 40            config = pagecontext.getservletconfig(); 41            session = pagecontext.getsession(); 42            out = pagecontext.getout(); 43            _jspx_out = out; 44       45            out.write("<html>    /r/n"); 46            out.write("<head>    /r/n"); 47            out.write("<title>hello example"); 48            out.write("</title>    /r/n"); 49            out.write("</head>    /r/n"); 50            out.write("<body>    /r/n"); 51            out.write("hello there!"); 52            out.write("<p>    /r/ngoodbye on "); 53            out.write(string.valueof( new java.util.date() )); 54            out.write("  /r/n"); 55            out.write("    /r/n"); 56            out.write("</body>    /r/n"); 57            out.write("</html>  /r/n"); 58          } catch (throwable t) { 59            if (!(t instanceof javax.servlet.jsp.skippageexception)){ 60              out = _jspx_out; 61              if (out != null && out.getbuffersize() != 0) 62                out.clearbuffer(); 63              if (pagecontext != null) pagecontext.handlepageexception(t); 64            } 65          } finally { 66     if (_jspxfactory != null) _jspxfactory.releasepagecontext ( pagecontext); 67          } 68        } 69      }

  tomcat 又將這個 java 代碼編譯為 hello_jsp.class,他們位于: $tomcat_install_path$/work/standalone/localhost/_ 目錄下。但是 jsp 文件名/行號和 java 行號的對應表(以下簡稱smap) 在哪里呢?答案是,它保存在 class 中。如果用 ultraedit 打開這個 class 文件,就可以找到 sourcedebugextension 屬性,這個屬性用來保存 smap。

  jvm 規范定義了 classfile 中可以包含 sourcedebugextension 屬性,保存 smap:

sourcedebugextension_attribute {   u2 attribute_name_index;   u4 attribute_length;   u1 debug_extension[attribute_length]; } 

  我用 javassist 做了一個測試(javassist可是一個好東東,它可以動態改變class的結構,jboss 的 aop就利用了javassist,這里我們只使用它讀取classfile的屬性)

 public static void main(string[] args) throws exception{    string[]files = {    "e://tomcat5_0_5//work//catalina//localhost//_//org//apache//jsp//hello_jsp.class",    };                   for(int k = 0; k < files.length; k++){     string file = files[k];     system.out.println("class : " + file);     classfile classfile = new classfile(new datainputstream(new fileinputstream(file)));                 attributeinfo attributeinfo = classfile.getattribute("sourcedebugextension");     system.out.println("attribute name :" + attributeinfo.getname() + "]/n/n");     byte[]bytes = attributeinfo.get();     string str = new string(bytes);     system.out.println(str);       } } 

  這段代碼顯示了sourcedebugextension 屬性,你可以看到smap 的內容。編譯jsp后,smap 就被寫入 class 中, 你也可以利用 javassist 修改 classfile 的屬性。

  下面就是 hello_jsp.class 中保存的 smap 內容:

smap e:/tomcat5_0_5/work/catalina/localhost/_/org/apache/jsp/hello_jsp.java jsp *s jsp *f + 0 hello.jsp /hello.jsp + 1 greeting.jsp /greeting.jsp *l 1:45 2:46 3:47 3:48 4:49 5:50 1#1:51 1:52 2:53 7#0:56 8:57 *e

  首先注明java代碼的名稱:hello_jsp.java,然后是 stratum 名稱: jsp。隨后是兩個jsp文件的名稱 :hello.jsp、greeting.jsp。兩個jsp文件共10行,產生的hello_jsp共69行代碼。最后也是最重要的內容就是源文件文件名/行號和目標文件行號的對應關系(*l 與 *e之間的部分)

  在規范定義了這樣的格式:

  源文件行號 # 源文件代號,重復次數 : 目標文件開始行號,目標文件行號每次增加的數量
(inputstartline # linefileid , repeatcount : outputstartline , outputlineincrement)

  源文件行號(inputstartline) 目標文件開始行號(outputstartline) 是必須的。下面是對這個smap具體的說明:

 1:45  2:46  3:47  3:48  4:49  5:50(沒有源文件代號,默認為hello.jsp)                    開始行號   結束行號 hello.jsp:    1 ->  hello_jsp.java:    45               2 ->                     46               3 ->                     47           48               4 ->                     49               5 ->                     50 1#1:51  1:52  2:53(1#1表示 greeting.jsp 的第1行) greeting.jsp:    1 ->  hello_jsp.java:       51           52                  2 ->                     53           7#0:56  8:57(7#0表示 hello.jsp 的第7行) hello.jsp:     7 ->  hello_jsp.java:       56                8 ->                     57 
  開發一個jsp編輯器

  eclipse 提供了 texteditor,作為文本編輯器的父類。由于 editor 的開發不是本文的重點,不做具體論述。我們可以利用 eclipse 的 plugin 項目向導,生成一個簡單的 jsp 編輯器:

  (1)點擊 file 菜單,new -> project -> plug-in project ;

  (2)輸入項目名稱 jsp_debug,下一步;

  (3)輸入 plugin id : com.jsp.debug
    plugin class name : com.jsp.debug.jsp_debugplugin

  (4)選擇用模板創建

  使用 plug-in with editor,輸入

  java package name :com.jsp.editors

  editor class name :jspeditor

  file extension :jsp

  一個 jsp editor 就產生了。

  運行這個plugin,新建一個java項目,新建一個 hello.jsp 和 greeting.jsp,在 navigator 視圖雙擊 jsp,這個editor就打開了。

  在jsp編輯器中設置斷點

  在編輯器中添加斷點的操作方式有兩種,一種是在編輯器左側垂直標尺上雙擊,另一種是在左側垂直標尺上點擊鼠標右鍵,選擇菜單"添加/刪除斷點"。

  在 eclipse 的實現中,添加斷點實際上就是為 ifile 添加一個marker ,類型是ibreakpoint.breakpoint_marker,然后將斷點注冊到 breakpointmanager。

  breakpointmanager 將產生一個 breakpointrequest,通知正在運行的jvm target,如果此時還沒有啟動 jvm,會在 jvm 啟動的時候,將所有斷點一起通知 jvm target。

  添加斷點使用一個 abstractruleractiondelegate,重載 createaction 方法,返回一個 iaction managebreakpointruleraction動作:

public class managebreakpointruleractiondelegate extends abstractruleractiondelegate{  protected iaction createaction(itexteditor editor, iverticalrulerinfo rulerinfo) {   return new managebreakpointruleraction(rulerinfo, editor);  } } 

  為了將 managebreakpointruleractiondelegate 添加到文本編輯器左側標尺的鼠標右鍵菜單,并且能夠處理左側標尺的鼠標雙擊事件,在 plugin.xml 中加入定義。

  處理雙擊事件:

<extension  point="org.eclipse.ui.editoractions">  <editorcontribution       targetid="com.jiaoly.editors.jspeditor"       id="com.jiaoly.debug.managebreakpointruleractiondelegate">    <action          label="添加/刪除斷點"          class="com.jiaoly.debug.managebreakpointruleractiondelegate"          actionid="rulerdoubleclick"          id="com.jiaoly.debug.managebreakpointruleractiondelegate">    </action>  </editorcontribution> </extension>        

  添加右鍵菜單:

<extension point="org.eclipse.ui.popupmenus">  <viewercontribution      targetid="#textrulercontext"      id="com.jiaoly.debug.managebreakpointruleractiondelegate">      <action        label="添加/刪除斷點"        class="com.jiaoly.debug.managebreakpointruleractiondelegate"        menubarpath="addition"        id="com.jiaoly.debug.managebreakpointruleractiondelegate">     </action>  </viewercontribution> </extension> 

  managebreakpointruleraction 是實際添加斷點的action,實現了 iupdate 接口,這個action的工作,就是判斷當前選中行是否存在斷點類型的 marker,如果不存在創建一個,如果存在,將它刪除。

public class managebreakpointruleraction extends action implements iupdate{            private iverticalrulerinfo rulerinfo;      private itexteditor texteditor;           private string bpmarkertype ;     //當點marker的類型      private list allmarkers;       //當前鼠標點擊行所有的marker      private string addbp;   //action 的顯示名稱      public managebreakpointruleraction(iverticalrulerinfo ruler, itexteditor editor){      this.rulerinfo = ruler;      this.texteditor = editor;      bpmarkertype = ibreakpoint.breakpoint_marker;      addbp = "添加/刪除斷點"; //$non-nls-1$      settext(this.addbp); }      public void update() {   this.allmarkers = this.fetchbpmarkerlist();  }      public void run(){  if(this.allmarkers.isempty())    this.addmarker();  else    this.removemarkers(this.allmarkers); } }   

  update 方法會在點擊時首先調用,這時就可以收集當前選中行是否有marker了(調用fetchbpmarkerlist方法),如果有,就保存在 變量allmarkers 中。由于managebreakpointruleraction每一次都產生一個新的實例,因此不會產生沖突。

  下面是update的調用棧,可以看出,update方法是在鼠標點擊事件中被調用的:

 managebreakpointruleraction.update() line: 55 managebreakpointruleractiondelegate(abstractruleractiondelegate).update() line: 114 managebreakpointruleractiondelegate(abstractruleractiondelegate).mousedown(mouseevent) line: 139 

  updae被調用后,會執行 run 方法,就可以根據 allmarkers.isempty() 確定要刪除還是添加 marker 了。

  添加斷點的時候,首先利用 iverticalrulerinfo,獲取鼠標點擊的行號,根據行號,從 document 模型中取得該行的描述iregion,得到開始字符位置和結束字符位置,創建一個 jsp 斷點。

   protected void addmarker() {   ieditorinput editorinput= this.gettexteditor().geteditorinput();      idocument document= this.getdocument();   //the line number of the last mouse button activity   int rulerline= this.getrulerinfo().getlineoflastmousebuttonactivity();   try{    int linenum = rulerline + 1;    if(linenum > 0){        //returns a description of the specified line     iregion iregion = document.getlineinformation(linenum - 1);     int charstart = iregion.getoffset();     int charend = (charstart + iregion.getlength()) - 1;     jspdebugutility.createjsplinebreakpoint(this.getresource(),               linenum, charstart, charend);    }   }catch(coreexception coreexception){    coreexception.printstacktrace();   }   catch(badlocationexception badlocationexception){    badlocationexception.printstacktrace();   }    }  

  注冊 jsp 斷點為支持 jsr-45 規范,eclipse 中提供了 javastratumlinebreakpoint。不過它目前是一個 internal 的實現,在以后的版本中不能保證不作修改。這里為了簡單起見,直接從 javastratumlinebreakpoint 繼承。

         public class jspbreakpoint extends javastratumlinebreakpoint {         public jspbreakpoint(iresource resource, string stratum, string sourcename,                 string sourcepath, string classnamepattern, int linenumber,                 int charstart, int charend, int hitcount, boolean register,                 map attributes) throws debugexception {             super(resource, stratum, sourcename, sourcepath, classnamepattern,                     linenumber, charstart, charend, hitcount, register, attributes);         }     } 

  查看 javastratumlinebreakpoint 的源代碼可以知道,創建 javastratumlinebreakpoint 的時候做了兩件事情:

  (1) 創建斷點類型的 marker, 并且設置了marker的屬性resource.createmarker(markertype);

  (2) 將斷點注冊到斷點管理器

  debugplugin.getdefault().getbreakpointmanager().addbreakpoint(this); 斷點管理器負責產生一個 breakpointrequest,通知正在運行的jvm target 如果此時還沒有啟動 jvm,會在 jvm 啟動的時候,將所有斷點一起通知 jvm target。

  下面是 javastratumlinebreakpoint 構造函數中的代碼:

     iworkspacerunnable wr= new iworkspacerunnable() {    public void run(iprogressmonitor monitor) throws coreexception {     // create the marker     setmarker(resource.createmarker(markertype));         // modify pattern     string pattern = classnamepattern;     if (pattern != null && pattern.length() == 0) {      pattern = null;     }     // add attributes     addlinebreakpointattributes(attributes, getmodelidentifier(), true,            linenumber, charstart, charend);     addstratumpatternandhitcount(attributes, stratum, sourcename,  sourcepath, pattern, hitcount);     // set attributes     ensuremarker().setattributes(attributes);          register(register);    }   };   run(null, wr);          protected void register(boolean register) throws coreexception {   if (register) {    debugplugin.getdefault().getbreakpointmanager().addbreakpoint(this);   } else {    setregistered(false);   }  }   

  移除斷點的時候,根據 marker 找到相應的 ibreakpoint,從 breakpointmanager 中移除 breakpointmanager 會自動刪除 marker,通知 jvm target。

breakpointmanager  = debugplugin.getdefault().getbreakpointmanager(); ibreakpoint breakpoint = breakpointmanager.getbreakpoint(imarker); breakpointmanager.removebreakpoint(breakpoint, true);         

  jspbreakpoint 重載了父類的addtotarget(jdidebugtarget target) 方法。重載這個方法的目的是根據不同的應用服務器,設置不同的 referencetypename和sourcepath。我們知道,每種應用服務器編譯 jsp 產生java class 名稱的規則都不相同,例如tomcat編譯hello.jsp 產生的java 類名為 org.apache.jsp. hello_jsp,而websphere6.0 卻是 com.ibm._jsp._hello。只有確定服務器類型,才能知道referencetypename 和souecepath應該是什么。目前通過啟動 jvm 時target 名稱來判斷應用服務器類型: string targetstring = target.getlaunch().getlaunchconfiguration().getname(); 如果targetstring 包含 tomcat ,就認為是 tomcat。

  產生 referencetypename 后首先創建一個 classpreparerequest 通知,然后從vm中取出所有的classes,如果是當前的 class,再創建一個添加斷點通知。之所以這樣做,是因為有可能這個 class 還沒有被 jvm 加載,直接通知 jvm 沒有任何意義。在 class 被加載的時候,jvm 會通知 eclipse,這個時候,才產生添加斷點通知。需要指出的是,本文示例代碼獲取 referencetypename 的方法不是很完善:

  (1) 僅僅實現了tomcat 讀者有興趣可以實現更多的web容器,例如 jboss3 以上,websphere6.0

  (2) 一些特殊情況沒有處理例如 路徑名為package的jsp,路徑名或文件名帶有數字的jsp

   public void addtotarget(jdidebugtarget target) throws coreexception {   imarker marker = this.getmarker();      iresource resource = marker.getresource();      string targetstring = target.getlaunch().getlaunchconfiguration().getname();   ijspnameutil util = jspdebugutility.getjspnameutil(targetstring);         // pre-notification   fireadding(target);        string referencetypename;   try {    referencetypename = getpattern();    //如果沒有設置 pattern, 根據 server 的類型, 產生新的 pattern     if(referencetypename == null ||        "".equals(referencetypename.trim()) ||       "*".equals(referencetypename.trim())){        referencetypename = util.referencetypename(resource);    }       } catch (coreexception e) {    jdidebugplugin.log(e);    return;   }      this.ensuremarker().setattribute(type_name, referencetypename);   string sourcepath = util.sourcepath(resource);   this.ensuremarker().setattribute(jspbreakpoint.source_path, sourcepath);      string classpreparetypename= referencetypename;      //如果這時 class 還沒有被加載, 注冊一個 classpreparerequest 請求   //   //當 class 加載的時候, 首先會觸發 javabreakpoint 的 handleclassprepareevent 方法   //調用 createrequest(target, event.referencetype()) --> newrequest() -->   //    createlinebreakpointrequest() 創建 enable或disable 斷點的請求   //   //  設置 enable/disable 動作在 configurerequest() --> updateenabledstate(request) 方法中   //  根據 getmarker().getattribute(enabled, false) 確定斷點是否有效      registerrequest(target.createclasspreparerequest(classpreparetypename), target);      // create breakpoint requests for each class currently loaded   virtualmachine vm = target.getvm();   if (vm == null) {    target.requestfailed("unable_to_add_breakpoint_-_vm_disconnected._1"),     null);   }   list classes = null;   try {    classes= vm.allclasses();   } catch (runtimeexception e) {    target.targetrequestfailed("javapatternbreakpoint.0"), e);    }   if (classes != null) {    iterator iter = classes.iterator();    while (iter.hasnext()) {     referencetype type= (referencetype)iter.next();     if (installablereferencetype(type, target)) {      createrequest(target, type);     }    }   }  } 
  調試jsp

  現在我們可以調試 jsp 了。

  (1)運行 jsp_debug plugin

  首先在 run -> run 中添加一個 run-time workbench,點擊 run 按鈕,eclipse 的plugin開發環境會啟動一個新的eclipse,這個新啟動的 eclipse 中,我們創建的 jsp_debug plugin 就可以使用了。新建 一個 java 項目 test (注意,一定要是java項目),新建一個 hello.jsp 和 greeting.jsp,打開hello.jsp,在編輯器左側標尺雙擊,就出現了一個斷點。

  (2)以 debug 模式啟動tomcat:

  windows 開始 -> 運行,鍵入 cmd,啟動一個命令行窗口:

  cd e:/tomcat5_0_5/bin

  (我的 tomcat 安裝在 e:/tomcat5_0_5 目錄,jdk 安裝在 d:/j2sdk1.4.2)

     d:/j2sdk1.4.2/bin/java   -xdebug -xnoagent -xrunjdwp:transport=dt_socket,address=8888,server=y,
suspend=n -djava.endorsed.dirs="../common/endorsed" -classpath "d:/j2sdk1.4.2/lib/tools.jar;../bin/bootstrap.jar" -dcatalina.base=".." -dcatalina.home=".." -djava.io.tmpdir="../temp" org.apache.catalina.startup.bootstrap start

  -xdebug -xnoagent -xrunjdwp:transport=dt_socket,address=8888,server=y,suspend=n 表示以調試方式啟動,端口號是 8888 classpath中要加入 d:/j2sdk1.4.2/lib/tools.jar,因為我是 tomcat5.0.5,如果是5.5就不需要了。

  (3) 測試hello.jsp

  將 hello.jsp 和 greeting.jsp 拷貝到 e:/tomcat5_0_5/webapps/root 目錄,從瀏覽器訪問 hello.jsp http://localhost:8000/hello.jsp。成功的話就可以繼續下面的工作了,如果失敗,檢查你的tomcat設置。

  (4)啟動遠程調試

  在 eclipse 中啟動遠程調試,將 eclipse 作為一個 debug 客戶端,連接到 tomcat 。在 java 透視圖中,點擊 run -> debug ,添加一個 remote java application,名稱是 start tomcat server(不能錯,因為我們要根據這個名稱,判斷當前的 web server 類型)

  project是創建的 test 項目

  port 為 8888,和啟動 tomcat 時設置的一樣



  點擊 debug 按鈕,就可以連接到 tomcat 上了。切換到 debug 透視圖,在debug 視圖中,能夠看到所有 tomcat 中線程的列表。

  (5)調試hello.jsp

  為 hello.jsp 添加斷點,然后從瀏覽器訪問hello.jsp,就可以在斷點處掛起了。你可以使用單步執行,也可以在variables視圖查看jsp中的變量信息。

  由于 eclipse 自身的實現,現在的 jsp editor 有一個問題,單步執行到 include jsp 行后,會從hello.jsp的1行再次執行。這是因為 eclipse jdt debug視圖緩存了 stackframe 中已經打開的editor,stackframe不改變時,不會再重新計算當前調試的是否是其他resource。本來應該打開 greeting.jsp的,現在卻從 hello.jsp 的第 1 行開始執行了。

  結束語

  很多集成開發環境都支持 jsp 的調試,在 eclipse 中也有 myeclipse 這樣的插件完成類似的功能。但是在 jsr-45 規范產生前,每種應用服務器對 jsp debug 的實現是不一樣的,例如 websphere 5 就是在 jsp 編譯產生的 java 代碼中加入了兩個數組,表示源文件和行號的對應信息。tomcat 率先實現了 jsr-45 規范,websphere 6.0 現在也采取這種模式, 有興趣的話,可以查看 websphere 6.0 編譯的 class,和 tomcat 不一樣,smap 文件會和java代碼同時產生。

  但是啟動server前,需要設置 jvm 參數 was.debug.mode = true

  同時在 ibm-web-ext.xmi 中設置

<jspattributes xmi:id="jspattribute_0" name="keepgenerated" value="true"/> <jspattributes xmi:id="jspattribute_1" name="createdebugclassfiles" value="true"/> <jspattributes xmi:id="jspattribute_2" name="debugenabled" value="true"/>      

  利用本文的基本原理,我們也可以開發其他基于 java 腳本語言的編輯器(例如 groovy),為這個編譯器加入 debug 的功能。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品自产拍在线观看| 欧美成人激情图片网| 亚洲精品资源在线| 欧美成人一区二区三区电影| 亚洲欧洲在线免费| 黑人巨大精品欧美一区二区免费| 欧美专区福利在线| 另类天堂视频在线观看| 日韩欧美在线视频日韩欧美在线视频| 日韩av手机在线观看| 青草成人免费视频| 欧美亚洲伦理www| 国产乱人伦真实精品视频| 欧美午夜美女看片| 日本不卡视频在线播放| 国产精品成人免费电影| 精品久久久久久久久久久久| 精品福利在线视频| 亚洲精品一区中文字幕乱码| 国产精品在线看| 国产精品99久久久久久久久久久久| 久久久女人电视剧免费播放下载| 久久av在线播放| 久久精品91久久香蕉加勒比| 国产精品普通话| 国产亚洲精品一区二555| 国内精品久久影院| 日韩大片在线观看视频| 亚洲视屏在线播放| 亚洲一区二区三区sesese| 欧美成年人视频网站| 欧美综合在线第二页| 欧美日韩性生活视频| 日韩在线观看免费全| 中文字幕欧美精品日韩中文字幕| 97视频免费在线观看| 亚洲а∨天堂久久精品9966| 亚洲精品国精品久久99热| 国产91精品最新在线播放| 亚洲男人天堂九九视频| 亚洲97在线观看| 国产色视频一区| 欧美第一页在线| 午夜精品久久久久久久白皮肤| 精品亚洲aⅴ在线观看| 亚洲丝袜在线视频| 久久人人爽人人| 久久精品国产69国产精品亚洲| 久久中文字幕一区| 成人女保姆的销魂服务| 亚洲欧美日韩综合| 日韩一区二区三区国产| 国内成人精品一区| 国产精品欧美日韩一区二区| 国产精品久久久久aaaa九色| 亚洲伦理中文字幕| 久久久亚洲天堂| 一区二区成人av| 2019国产精品自在线拍国产不卡| 欧美性受xxxx黑人猛交| 精品国偷自产在线视频| 久久久亚洲精品视频| 国产精品十八以下禁看| 中文字幕一区二区三区电影| 日韩中文字幕在线精品| 亚洲国内精品在线| 国产欧美日韩中文| 国产成人一区二区三区| 日本精品视频网站| 国产精品v片在线观看不卡| 亚洲精品久久久久久久久久久| 国产精品久久婷婷六月丁香| 午夜精品久久久久久久男人的天堂| 2021国产精品视频| 奇米影视亚洲狠狠色| 久久成人国产精品| 揄拍成人国产精品视频| 国产精品入口尤物| 国产日韩精品在线观看| 国产欧美一区二区三区在线看| 97香蕉超级碰碰久久免费的优势| 亲子乱一区二区三区电影| 久久av中文字幕| 国产国语刺激对白av不卡| 91精品视频专区| 国产精品69精品一区二区三区| 91国内免费在线视频| 欧美亚洲一级片| 国产香蕉一区二区三区在线视频| 久久久最新网址| 久久精品99无色码中文字幕| 亚洲欧美日韩区| 亚洲欧美日本另类| 日韩在线观看免费网站| 亚洲精品欧美日韩专区| 日韩高清电影好看的电视剧电影| 精品国产美女在线| 久久免费视频这里只有精品| 欧美极品少妇与黑人| 久久影视电视剧凤归四时歌| 久久精品国产欧美激情| 全亚洲最色的网站在线观看| 国产在线精品播放| 91在线精品播放| 亚洲国产又黄又爽女人高潮的| 日韩中文娱乐网| 欧美黑人一级爽快片淫片高清| 日韩av不卡电影| 国产成人精品一区二区在线| 韩国福利视频一区| 一本大道亚洲视频| 久久精品99久久久香蕉| 青青草原一区二区| 午夜精品美女自拍福到在线| 欧美性xxxx| 欧美裸体xxxx极品少妇| 中文字幕精品久久| 国产精品久久网| 亚洲缚视频在线观看| 欧美激情视频在线免费观看 欧美视频免费一| 5278欧美一区二区三区| 成人网页在线免费观看| 国产亚洲精品一区二555| 欧美日本中文字幕| 亚洲女人天堂色在线7777| 日韩免费观看网站| www.国产精品一二区| 色综合影院在线| 亚洲人a成www在线影院| 欧美激情按摩在线| 欧美国产日韩中文字幕在线| 中文字幕欧美国内| 日韩欧美中文免费| 国产精品中文字幕在线观看| 欧美有码在线观看| 国产精品一区久久久| 97热在线精品视频在线观看| 亚洲精品国产美女| 亚洲3p在线观看| 国产成人精品久久二区二区| 性亚洲最疯狂xxxx高清| 欧美国产日韩精品| 在线观看不卡av| 亚洲国产另类久久精品| 亚洲精品美女在线观看| 国产日韩中文在线| 日韩动漫免费观看电视剧高清| 国产成人一区二区在线| 亚洲人成在线一二| 国产在线高清精品| 热门国产精品亚洲第一区在线| 亚洲区中文字幕| 亚洲图片欧美午夜| 欧美精品日韩www.p站| 国产精品视频免费在线| 亚洲aⅴ男人的天堂在线观看| 欧美成年人网站| 亚洲美女激情视频| 1769国内精品视频在线播放| 青青精品视频播放| 久久久国产精品x99av| 欧美激情精品久久久久| 欧美最猛黑人xxxx黑人猛叫黄| 精品国产乱码久久久久久婷婷|