菠蘿三國

          大江東去,浪淘盡...
          隨筆 - 34, 文章 - 47, 評(píng)論 - 22, 引用 - 0
          數(shù)據(jù)加載中……

          2008年1月18日

          用instsrv與srvany在windows 建立服務(wù)

          用instsrv與srvany在windows 建立服務(wù)

          instsrv.exe  srvany.exe

          這兩個(gè)文件是MS批量生產(chǎn)的,網(wǎng)上應(yīng)該能爛下載。

          首先將這兩個(gè)文件放到自定的路徑中。例如放在C:\根目錄下

          在CMD對(duì)話框中輸入 c:\instsrv.exe  servername c:\ srvany.exe 回車

          其中servername是你所需要的服務(wù)名。

          之后你需要進(jìn)入注冊(cè)表進(jìn)行相應(yīng)的設(shè)置,在注冊(cè)表的:

          HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\servername

          中簡歷Parameters子項(xiàng),然后在其中建立一個(gè)字符串Application,雙擊該字符串,輸入如下格式的語句:

          C:\ABC\DEF\XXX.exe +Xms256M +Xmx256M -nodbcheck -minspan60 -retry1000

          其中的256M與服務(wù)占用內(nèi)存大小有關(guān),這就要看機(jī)器的配置了。

          修改結(jié)束后推出,使用命令services.msc進(jìn)入服務(wù)界面,找到你剛剛定制的服務(wù),雙擊進(jìn)入,之后選擇“登陸”,再選中“本地登陸”并確定。之后手動(dòng)啟動(dòng)服務(wù)即可。

          C:\service\instsrv.exe adslSrv "C:\service\srvany.exe"

          posted @ 2009-04-19 14:44 菠蘿 閱讀(1150) | 評(píng)論 (0)編輯 收藏

          網(wǎng)上在線字典詞典大全

          翻譯類字典詞典

          posted @ 2008-04-07 12:26 菠蘿 閱讀(533) | 評(píng)論 (0)編輯 收藏

          XP/2003訪問XP的用戶驗(yàn)證問題


            首先關(guān)于啟用Guest為什么不能訪問的問題:  
             
            1、默認(rèn)情況下,XP   禁用Guest帳戶  
            2、默認(rèn)情況下,XP的本地安全策略禁止Guest用戶從網(wǎng)絡(luò)訪問  
            3、默認(rèn)情況下,XP的   本地安全策略   ->   安全選項(xiàng)   里,"帳戶:使用空密碼用戶只能進(jìn)行控制臺(tái)登陸"是啟用的,也就是說,空密碼的任何帳戶都不能從網(wǎng)絡(luò)訪問只能本地登陸,Guest默認(rèn)空密碼......  
             
            所以,如果需要使用Guest用戶訪問XP的話,要進(jìn)行上面的三個(gè)設(shè)置:啟用Guest、修改安全策略允許Guest從網(wǎng)絡(luò)訪問、禁用3里面的安全策略或者給Guest加個(gè)密碼。  
             
            有時(shí)還會(huì)遇到另外一種情況:訪問XP的時(shí)候,登錄對(duì)話框中的用戶名是灰的,始終是Guest用戶,不能輸入別的用戶帳號(hào)。  
             
            原因是這個(gè)安全策略在作怪。默認(rèn)情況下,XP的訪問方式是"僅來賓"的方式,那么你訪問它,當(dāng)然就固定為Guest不能輸入其他用戶帳號(hào)了。  
             
            所以,訪問XP最簡單的方法就是:不用啟用Guest,僅修改上面的安全策略為"經(jīng)典"就行了。別的系統(tǒng)訪問XP就可以自己輸入帳戶信息。  
             
            至于訪問2003,默認(rèn)情況下2003禁用Guest,但是沒有   XP   那個(gè)討厭的默認(rèn)自相矛盾的來賓方式共享,所以可以直接輸入用戶名密碼訪問。

          posted @ 2008-03-07 20:43 菠蘿 閱讀(403) | 評(píng)論 (0)編輯 收藏

          RSS的格式及解釋(轉(zhuǎn))

               摘要:   閱讀全文

          posted @ 2008-01-30 09:27 菠蘿 閱讀(2158) | 評(píng)論 (1)編輯 收藏

          AJAX讀取rss的代碼(轉(zhuǎn))

           
          2007-02-02 15:48

          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
            " <html xmlns=" <head>
          <title>this is test</title>

          <script type="text/javascript">
          var xmlHttp;

          function createXMLHttpRequest() {
              if (window.ActiveXObject) {
                  xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
              } 
              else if (window.XMLHttpRequest) {
                  xmlHttp = new XMLHttpRequest();
              }
          }

          function readRSS(url) {
              createXMLHttpRequest();
              xmlHttp.onreadystatechange = handleStateChange;
              xmlHttp.open("GET", url, true);
              xmlHttp.send(null);
            
            
          }
              
          function handleStateChange() {
              if(xmlHttp.readyState == 4) {
                  if(xmlHttp.status == 200) {
                      ResultSet();
                  }
              }
          }

          function ResultSet() {
              var results = xmlHttp.responseXML;
              var title = null;
              var item = null;
              var link=null;
              //得到channel
              var ccc=results.getElementsByTagName("channel");
               var headtitle=ccc[0].getElementsByTagName("title")[0].firstChild.nodeValue;
               var headlink=ccc[0].getElementsByTagName("link")[0].firstChild.nodeValue;
               var cell = document.createElement("div");
                  cell.innerHTML="<h1><a href="+headlink+" target=_blank>"+headtitle+"</a></h1><br>";
                  document.getElementById("result").appendChild(cell);
                 //得到items
              var items = results.getElementsByTagName("item");
              for(var i = 0; i < items.length; i++) {
                  item = items[i];
                  link=item.getElementsByTagName("link")[0].firstChild.nodeValue;
                  title = item.getElementsByTagName("title")[0].firstChild.nodeValue;
                  var cell = document.createElement("div");
                  cell.innerHTML="<a href="+link+" target=_blank>"+title+"</a><br>";
                 document.getElementById("result").appendChild(cell);
              }

          }
          function readrss1()
          {
              var url=document.getElementById("txturl").value;
              if(url=="")
              {
                  alert("請(qǐng)輸入RSS地址");
                  }
              else
                  {
                      readRSS(url);
                      }
              }

          </script>
          </head>

          <body">
            <h1>ajax讀rss示例</h1>
            <form >
                
            <a href="javascript:readRSS('http://www.aygfsteel.com/rss.aspx')">blogjava原創(chuàng)區(qū) </a>&nbsp     
             <a href="javascript:readRSS('http://beginner.blogjava.net/rss.aspx')">blogjava新手區(qū) </a> &nbsp 
              <a href="javascript:readRSS('http://life.blogjava.net/rss.aspx')">blogjava非技術(shù)區(qū) </a> &nbsp 
               <a href="javascript:readRSS('http://general.blogjava.net/rss.aspx')">綜合區(qū) </a>
               <br>
               輸入一個(gè)RSS地址:<input type="text" value="
          http://www.aygfsteel.com/wujun/rss.aspx" size=50 id="txturl">
               <input type="button" value="查 看" onclick="readrss1()">
               
            </form>
              <div id="result"></div>
          </body>
          </html>

          posted @ 2008-01-29 22:49 菠蘿 閱讀(359) | 評(píng)論 (0)編輯 收藏

          Session機(jī)制

          摘要:

          雖然session機(jī)制在web應(yīng)用程序中被采用已經(jīng)很長時(shí)間了,但是仍然有很多人不清楚session機(jī)制的本質(zhì),以至不能正確的應(yīng)用這一技術(shù)。本文將詳細(xì)討論session的工作機(jī)制并且對(duì)在Java web application中應(yīng)用session機(jī)制時(shí)常見的問題作出解答。
           
          一、術(shù)語session
          在我的經(jīng)驗(yàn)里,session這個(gè)詞被濫用的程度大概僅次于transaction,更加有趣的是transaction與session在某些語境下的含義是相同的。

          session,中文經(jīng)常翻譯為會(huì)話,其本來的含義是指有始有終的一系列動(dòng)作/消息,比如打電話時(shí)從拿起電話撥號(hào)到掛斷電話這中間的一系列過程可以稱之為一個(gè) session。有時(shí)候我們可以看到這樣的話“在一個(gè)瀏覽器會(huì)話期間,...”,這里的會(huì)話一詞用的就是其本義,是指從一個(gè)瀏覽器窗口打開到關(guān)閉這個(gè)期間 ①。最混亂的是“用戶(客戶端)在一次會(huì)話期間”這樣一句話,它可能指用戶的一系列動(dòng)作(一般情況下是同某個(gè)具體目的相關(guān)的一系列動(dòng)作,比如從登錄到選購商品到結(jié)賬登出這樣一個(gè)網(wǎng)上購物的過程,有時(shí)候也被稱為一個(gè)transaction),然而有時(shí)候也可能僅僅是指一次連接,也有可能是指含義①,其中的差別只能靠上下文來推斷②。

          然而當(dāng)session一詞與網(wǎng)絡(luò)協(xié)議相關(guān)聯(lián)時(shí),它又往往隱含了“面向連接”和/或“保持狀態(tài)”這樣兩個(gè)含義, “面向連接”指的是在通信雙方在通信之前要先建立一個(gè)通信的渠道,比如打電話,直到對(duì)方接了電話通信才能開始,與此相對(duì)的是寫信,在你把信發(fā)出去的時(shí)候你并不能確認(rèn)對(duì)方的地址是否正確,通信渠道不一定能建立,但對(duì)發(fā)信人來說,通信已經(jīng)開始了。“保持狀態(tài)”則是指通信的一方能夠把一系列的消息關(guān)聯(lián)起來,使得消息之間可以互相依賴,比如一個(gè)服務(wù)員能夠認(rèn)出再次光臨的老顧客并且記得上次這個(gè)顧客還欠店里一塊錢。這一類的例子有“一個(gè)TCP session”或者 “一個(gè)POP3 session”③。

          而到了web服務(wù)器蓬勃發(fā)展的時(shí)代,session在web開發(fā)語境下的語義又有了新的擴(kuò)展,它的含義是指一類用來在客戶端與服務(wù)器之間保持狀態(tài)的解決方案④。有時(shí)候session也用來指這種解決方案的存儲(chǔ)結(jié)構(gòu),如“把xxx保存在session 里”⑤。由于各種用于web開發(fā)的語言在一定程度上都提供了對(duì)這種解決方案的支持,所以在某種特定語言的語境下,session也被用來指代該語言的解決方案,比如經(jīng)常把Java里提供的javax.servlet.http.HttpSession簡稱為session⑥。

          鑒于這種混亂已不可改變,本文中session一詞的運(yùn)用也會(huì)根據(jù)上下文有不同的含義,請(qǐng)大家注意分辨。
          在本文中,使用中文“瀏覽器會(huì)話期間”來表達(dá)含義①,使用“session機(jī)制”來表達(dá)含義④,使用“session”表達(dá)含義⑤,使用具體的“HttpSession”來表達(dá)含義⑥

          二、HTTP協(xié)議與狀態(tài)保持
          HTTP 協(xié)議本身是無狀態(tài)的,這與HTTP協(xié)議本來的目的是相符的,客戶端只需要簡單的向服務(wù)器請(qǐng)求下載某些文件,無論是客戶端還是服務(wù)器都沒有必要紀(jì)錄彼此過去的行為,每一次請(qǐng)求之間都是獨(dú)立的,好比一個(gè)顧客和一個(gè)自動(dòng)售貨機(jī)或者一個(gè)普通的(非會(huì)員制)大賣場(chǎng)之間的關(guān)系一樣。

          然而聰明(或者貪心?)的人們很快發(fā)現(xiàn)如果能夠提供一些按需生成的動(dòng)態(tài)信息會(huì)使web變得更加有用,就像給有線電視加上點(diǎn)播功能一樣。這種需求一方面迫使HTML逐步添加了表單、腳本、DOM等客戶端行為,另一方面在服務(wù)器端則出現(xiàn)了CGI規(guī)范以響應(yīng)客戶端的動(dòng)態(tài)請(qǐng)求,作為傳輸載體的HTTP協(xié)議也添加了文件上載、 cookie這些特性。其中cookie的作用就是為了解決HTTP協(xié)議無狀態(tài)的缺陷所作出的努力。至于后來出現(xiàn)的session機(jī)制則是又一種在客戶端與服務(wù)器之間保持狀態(tài)的解決方案。

          讓我們用幾個(gè)例子來描述一下cookie和session機(jī)制之間的區(qū)別與聯(lián)系。筆者曾經(jīng)常去的一家咖啡店有喝5杯咖啡免費(fèi)贈(zèng)一杯咖啡的優(yōu)惠,然而一次性消費(fèi)5杯咖啡的機(jī)會(huì)微乎其微,這時(shí)就需要某種方式來紀(jì)錄某位顧客的消費(fèi)數(shù)量。想象一下其實(shí)也無外乎下面的幾種方案:
          1、該店的店員很厲害,能記住每位顧客的消費(fèi)數(shù)量,只要顧客一走進(jìn)咖啡店,店員就知道該怎么對(duì)待了。這種做法就是協(xié)議本身支持狀態(tài)。
          2、發(fā)給顧客一張卡片,上面記錄著消費(fèi)的數(shù)量,一般還有個(gè)有效期限。每次消費(fèi)時(shí),如果顧客出示這張卡片,則此次消費(fèi)就會(huì)與以前或以后的消費(fèi)相聯(lián)系起來。這種做法就是在客戶端保持狀態(tài)。
          3、發(fā)給顧客一張會(huì)員卡,除了卡號(hào)之外什么信息也不紀(jì)錄,每次消費(fèi)時(shí),如果顧客出示該卡片,則店員在店里的紀(jì)錄本上找到這個(gè)卡號(hào)對(duì)應(yīng)的紀(jì)錄添加一些消費(fèi)信息。這種做法就是在服務(wù)器端保持狀態(tài)。

          由于HTTP協(xié)議是無狀態(tài)的,而出于種種考慮也不希望使之成為有狀態(tài)的,因此,后面兩種方案就成為現(xiàn)實(shí)的選擇。具體來說cookie機(jī)制采用的是在客戶端保持狀態(tài)的方案,而session機(jī)制采用的是在服務(wù)器端保持狀態(tài)的方案。同時(shí)我們也看到,由于采用服務(wù)器端保持狀態(tài)的方案在客戶端也需要保存一個(gè)標(biāo)識(shí),所以session機(jī)制可能需要借助于cookie機(jī)制來達(dá)到保存標(biāo)識(shí)的目的,但實(shí)際上它還有其他選擇。

          三、理解cookie機(jī)制
          cookie機(jī)制的基本原理就如上面的例子一樣簡單,但是還有幾個(gè)問題需要解決:“會(huì)員卡”如何分發(fā);“會(huì)員卡”的內(nèi)容;以及客戶如何使用“會(huì)員卡”。

          正統(tǒng)的cookie分發(fā)是通過擴(kuò)展HTTP協(xié)議來實(shí)現(xiàn)的,服務(wù)器通過在HTTP的響應(yīng)頭中加上一行特殊的指示以提示瀏覽器按照指示生成相應(yīng)的cookie。然而純粹的客戶端腳本如JavaScript或者VBScript也可以生成cookie。

          而cookie 的使用是由瀏覽器按照一定的原則在后臺(tái)自動(dòng)發(fā)送給服務(wù)器的。瀏覽器檢查所有存儲(chǔ)的cookie,如果某個(gè)cookie所聲明的作用范圍大于等于將要請(qǐng)求的資源所在的位置,則把該cookie附在請(qǐng)求資源的HTTP請(qǐng)求頭上發(fā)送給服務(wù)器。意思是麥當(dāng)勞的會(huì)員卡只能在麥當(dāng)勞的店里出示,如果某家分店還發(fā)行了自己的會(huì)員卡,那么進(jìn)這家店的時(shí)候除了要出示麥當(dāng)勞的會(huì)員卡,還要出示這家店的會(huì)員卡。

          cookie的內(nèi)容主要包括:名字,值,過期時(shí)間,路徑和域。
          其中域可以指定某一個(gè)域比如.google.com,相當(dāng)于總店招牌,比如寶潔公司,也可以指定一個(gè)域下的具體某臺(tái)機(jī)器比如www.google.com或者froogle.google.com,可以用飄柔來做比。
          路徑就是跟在域名后面的URL路徑,比如/或者/foo等等,可以用某飄柔專柜做比。
          路徑與域合在一起就構(gòu)成了cookie的作用范圍。
          如果不設(shè)置過期時(shí)間,則表示這個(gè)cookie的生命期為瀏覽器會(huì)話期間,只要關(guān)閉瀏覽器窗口,cookie就消失了。這種生命期為瀏覽器會(huì)話期的 cookie被稱為會(huì)話cookie。會(huì)話cookie一般不存儲(chǔ)在硬盤上而是保存在內(nèi)存里,當(dāng)然這種行為并不是規(guī)范規(guī)定的。如果設(shè)置了過期時(shí)間,瀏覽器就會(huì)把cookie保存到硬盤上,關(guān)閉后再次打開瀏覽器,這些cookie仍然有效直到超過設(shè)定的過期時(shí)間。

          存儲(chǔ)在硬盤上的cookie 可以在不同的瀏覽器進(jìn)程間共享,比如兩個(gè)IE窗口。而對(duì)于保存在內(nèi)存里的cookie,不同的瀏覽器有不同的處理方式。對(duì)于IE,在一個(gè)打開的窗口上按 Ctrl-N(或者從文件菜單)打開的窗口可以與原窗口共享,而使用其他方式新開的IE進(jìn)程則不能共享已經(jīng)打開的窗口的內(nèi)存cookie;對(duì)于 Mozilla Firefox0.8,所有的進(jìn)程和標(biāo)簽頁都可以共享同樣的cookie。一般來說是用javascript的window.open打開的窗口會(huì)與原窗口共享內(nèi)存cookie。瀏覽器對(duì)于會(huì)話cookie的這種只認(rèn)cookie不認(rèn)人的處理方式經(jīng)常給采用session機(jī)制的web應(yīng)用程序開發(fā)者造成很大的困擾。

          下面就是一個(gè)goolge設(shè)置cookie的響應(yīng)頭的例子
          HTTP/1.1 302 Found
          Location: http://www.google.com/intl/zh-CN/
          Set-Cookie: PREF=ID=0565f77e132de138:NW=1:TM=1098082649:LM=1098082649:S=KaeaCFPo49RiA_d8; expires=Sun, 17-Jan-2038 19:14:07 GMT; path=/; domain=.google.com
          Content-Type: text/html


          image
          這是使用HTTPLook這個(gè)HTTP Sniffer軟件來俘獲的HTTP通訊紀(jì)錄的一部分

          image
          瀏覽器在再次訪問goolge的資源時(shí)自動(dòng)向外發(fā)送cookie

          image
          用Firefox可以很容易的觀察現(xiàn)有的cookie的值
          使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理。

          image
          IE也可以設(shè)置在接受cookie前詢問

          四、理解session機(jī)制

          session機(jī)制是一種服務(wù)器端的機(jī)制,服務(wù)器使用一種類似于散列表的結(jié)構(gòu)(也可能就是使用散列表)來保存信息。

          當(dāng)程序需要為某個(gè)客戶端的請(qǐng)求創(chuàng)建一個(gè)session的時(shí)候,服務(wù)器首先檢查這個(gè)客戶端的請(qǐng)求里是否已包含了一個(gè)session標(biāo)識(shí) - 稱為 session id,如果已包含一個(gè)session id則說明以前已經(jīng)為此客戶端創(chuàng)建過session,服務(wù)器就按照session id把這個(gè) session檢索出來使用(如果檢索不到,可能會(huì)新建一個(gè)),如果客戶端請(qǐng)求不包含session id,則為此客戶端創(chuàng)建一個(gè)session并且生成一個(gè)與此session相關(guān)聯(lián)的session id,session id的值應(yīng)該是一個(gè)既不會(huì)重復(fù),又不容易被找到規(guī)律以仿造的字符串,這個(gè) session id將被在本次響應(yīng)中返回給客戶端保存。

          保存這個(gè)session id的方式可以采用cookie,這樣在交互過程中瀏覽器可以自動(dòng)的按照規(guī)則把這個(gè)標(biāo)識(shí)發(fā)揮給服務(wù)器。一般這個(gè)cookie的名字都是類似于SEEESIONID,而。比如weblogic對(duì)于web應(yīng)用程序生成的cookie,JSESSIONID= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764,它的名字就是 JSESSIONID。

          由于cookie可以被人為的禁止,必須有其他機(jī)制以便在cookie被禁止時(shí)仍然能夠把session id傳遞回服務(wù)器。經(jīng)常被使用的一種技術(shù)叫做URL重寫,就是把session id直接附加在URL路徑的后面,附加方式也有兩種,一種是作為URL路徑的附加信息,表現(xiàn)形式為http://...../xxx;jsessionid= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
          另一種是作為查詢字符串附加在URL后面,表現(xiàn)形式為http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
          這兩種方式對(duì)于用戶來說是沒有區(qū)別的,只是服務(wù)器在解析的時(shí)候處理的方式不同,采用第一種方式也有利于把session id的信息和正常程序參數(shù)區(qū)分開來。
          為了在整個(gè)交互過程中始終保持狀態(tài),就必須在每個(gè)客戶端可能請(qǐng)求的路徑后面都包含這個(gè)session id。

          另一種技術(shù)叫做表單隱藏字段。就是服務(wù)器會(huì)自動(dòng)修改表單,添加一個(gè)隱藏字段,以便在表單提交時(shí)能夠把session id傳遞回服務(wù)器。比如下面的表單
          <form name="testform" action="/xxx">
          <input type="text">
          </form>


          在被傳遞給客戶端之前將被改寫成
          <form name="testform" action="/xxx">
          <input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
          <input type="text">
          </form>


          這種技術(shù)現(xiàn)在已較少應(yīng)用,筆者接觸過的很古老的iPlanet6(SunONE應(yīng)用服務(wù)器的前身)就使用了這種技術(shù)。
          實(shí)際上這種技術(shù)可以簡單的用對(duì)action應(yīng)用URL重寫來代替。

          在談?wù)搒ession機(jī)制的時(shí)候,常常聽到這樣一種誤解“只要關(guān)閉瀏覽器,session就消失了”。其實(shí)可以想象一下會(huì)員卡的例子,除非顧客主動(dòng)對(duì)店家提出銷卡,否則店家絕對(duì)不會(huì)輕易刪除顧客的資料。對(duì)session來說也是一樣的,除非程序通知服務(wù)器刪除一個(gè)session,否則服務(wù)器會(huì)一直保留,程序一般都是在用戶做log off的時(shí)候發(fā)個(gè)指令去刪除session。然而瀏覽器從來不會(huì)主動(dòng)在關(guān)閉之前通知服務(wù)器它將要關(guān)閉,因此服務(wù)器根本不會(huì)有機(jī)會(huì)知道瀏覽器已經(jīng)關(guān)閉,之所以會(huì)有這種錯(cuò)覺,是大部分session機(jī)制都使用會(huì)話cookie來保存session id,而關(guān)閉瀏覽器后這個(gè) session id就消失了,再次連接服務(wù)器時(shí)也就無法找到原來的session。如果服務(wù)器設(shè)置的cookie被保存到硬盤上,或者使用某種手段改寫瀏覽器發(fā)出的HTTP請(qǐng)求頭,把原來的session id發(fā)送給服務(wù)器,則再次打開瀏覽器仍然能夠找到原來的session。

          恰恰是由于關(guān)閉瀏覽器不會(huì)導(dǎo)致session被刪除,迫使服務(wù)器為seesion設(shè)置了一個(gè)失效時(shí)間,當(dāng)距離客戶端上一次使用session的時(shí)間超過這個(gè)失效時(shí)間時(shí),服務(wù)器就可以認(rèn)為客戶端已經(jīng)停止了活動(dòng),才會(huì)把session刪除以節(jié)省存儲(chǔ)空間。

          五、理解javax.servlet.http.HttpSession
          HttpSession是Java平臺(tái)對(duì)session機(jī)制的實(shí)現(xiàn)規(guī)范,因?yàn)樗鼉H僅是個(gè)接口,具體到每個(gè)web應(yīng)用服務(wù)器的提供商,除了對(duì)規(guī)范支持之外,仍然會(huì)有一些規(guī)范里沒有規(guī)定的細(xì)微差異。這里我們以BEA的Weblogic Server8.1作為例子來演示。

          首先,Weblogic Server提供了一系列的參數(shù)來控制它的HttpSession的實(shí)現(xiàn),包括使用cookie的開關(guān)選項(xiàng),使用URL重寫的開關(guān)選項(xiàng),session持久化的設(shè)置,session失效時(shí)間的設(shè)置,以及針對(duì)cookie的各種設(shè)置,比如設(shè)置cookie的名字、路徑、域, cookie的生存時(shí)間等。

          一般情況下,session都是存儲(chǔ)在內(nèi)存里,當(dāng)服務(wù)器進(jìn)程被停止或者重啟的時(shí)候,內(nèi)存里的session也會(huì)被清空,如果設(shè)置了session的持久化特性,服務(wù)器就會(huì)把session保存到硬盤上,當(dāng)服務(wù)器進(jìn)程重新啟動(dòng)或這些信息將能夠被再次使用, Weblogic Server支持的持久性方式包括文件、數(shù)據(jù)庫、客戶端cookie保存和復(fù)制。

          復(fù)制嚴(yán)格說來不算持久化保存,因?yàn)閟ession實(shí)際上還是保存在內(nèi)存里,不過同樣的信息被復(fù)制到各個(gè)cluster內(nèi)的服務(wù)器進(jìn)程中,這樣即使某個(gè)服務(wù)器進(jìn)程停止工作也仍然可以從其他進(jìn)程中取得session。

          cookie生存時(shí)間的設(shè)置則會(huì)影響瀏覽器生成的cookie是否是一個(gè)會(huì)話cookie。默認(rèn)是使用會(huì)話cookie。有興趣的可以用它來試驗(yàn)我們?cè)诘谒墓?jié)里提到的那個(gè)誤解。

          cookie的路徑對(duì)于web應(yīng)用程序來說是一個(gè)非常重要的選項(xiàng),Weblogic Server對(duì)這個(gè)選項(xiàng)的默認(rèn)處理方式使得它與其他服務(wù)器有明顯的區(qū)別。后面我們會(huì)專題討論。

          關(guān)于session的設(shè)置參考[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869

          六、HttpSession常見問題
          (在本小節(jié)中session的含義為⑤和⑥的混合)

          1、session在何時(shí)被創(chuàng)建
          一個(gè)常見的誤解是以為session在有客戶端訪問時(shí)就被創(chuàng)建,然而事實(shí)是直到某server端程序調(diào)用 HttpServletRequest.getSession(true)這樣的語句時(shí)才被創(chuàng)建,注意如果JSP沒有顯示的使用 <% @page session="false"%> 關(guān)閉session,則JSP文件在編譯成Servlet時(shí)將會(huì)自動(dòng)加上這樣一條語句 HttpSession session = HttpServletRequest.getSession(true);這也是JSP中隱含的 session對(duì)象的來歷。

          由于session會(huì)消耗內(nèi)存資源,因此,如果不打算使用session,應(yīng)該在所有的JSP中關(guān)閉它。

          2、session何時(shí)被刪除
          綜合前面的討論,session在下列情況下被刪除a.程序調(diào)用HttpSession.invalidate();或b.距離上一次收到客戶端發(fā)送的session id時(shí)間間隔超過了session的超時(shí)設(shè)置;或c.服務(wù)器進(jìn)程被停止(非持久session)

          3、如何做到在瀏覽器關(guān)閉時(shí)刪除session
          嚴(yán)格的講,做不到這一點(diǎn)。可以做一點(diǎn)努力的辦法是在所有的客戶端頁面里使用javascript代碼window.oncolose來監(jiān)視瀏覽器的關(guān)閉動(dòng)作,然后向服務(wù)器發(fā)送一個(gè)請(qǐng)求來刪除session。但是對(duì)于瀏覽器崩潰或者強(qiáng)行殺死進(jìn)程這些非常規(guī)手段仍然無能為力。

          4、有個(gè)HttpSessionListener是怎么回事
          你可以創(chuàng)建這樣的listener去監(jiān)控session的創(chuàng)建和銷毀事件,使得在發(fā)生這樣的事件時(shí)你可以做一些相應(yīng)的工作。注意是session的創(chuàng)建和銷毀動(dòng)作觸發(fā)listener,而不是相反。類似的與HttpSession有關(guān)的listener還有 HttpSessionBindingListener,HttpSessionActivationListener和 HttpSessionAttributeListener。

          5、存放在session中的對(duì)象必須是可序列化的嗎
          不是必需的。要求對(duì)象可序列化只是為了session能夠在集群中被復(fù)制或者能夠持久保存或者在必要時(shí)server能夠暫時(shí)把session交換出內(nèi)存。在 Weblogic Server的session中放置一個(gè)不可序列化的對(duì)象在控制臺(tái)上會(huì)收到一個(gè)警告。我所用過的某個(gè)iPlanet版本如果 session中有不可序列化的對(duì)象,在session銷毀時(shí)會(huì)有一個(gè)Exception,很奇怪。

          6、如何才能正確的應(yīng)付客戶端禁止cookie的可能性
          對(duì)所有的URL使用URL重寫,包括超鏈接,form的action,和重定向的URL,具體做法參見[6]
          http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770

          7、開兩個(gè)瀏覽器窗口訪問應(yīng)用程序會(huì)使用同一個(gè)session還是不同的session
          參見第三小節(jié)對(duì)cookie的討論,對(duì)session來說是只認(rèn)id不認(rèn)人,因此不同的瀏覽器,不同的窗口打開方式以及不同的cookie存儲(chǔ)方式都會(huì)對(duì)這個(gè)問題的答案有影響。

          8、如何防止用戶打開兩個(gè)瀏覽器窗口操作導(dǎo)致的session混亂
          這個(gè)問題與防止表單多次提交是類似的,可以通過設(shè)置客戶端的令牌來解決。就是在服務(wù)器每次生成一個(gè)不同的id返回給客戶端,同時(shí)保存在session里,客戶端提交表單時(shí)必須把這個(gè)id也返回服務(wù)器,程序首先比較返回的id與保存在session里的值是否一致,如果不一致則說明本次操作已經(jīng)被提交過了。可以參看《J2EE核心模式》關(guān)于表示層模式的部分。需要注意的是對(duì)于使用javascript window.open打開的窗口,一般不設(shè)置這個(gè)id,或者使用單獨(dú)的id,以防主窗口無法操作,建議不要再window.open打開的窗口里做修改操作,這樣就可以不用設(shè)置。

          9、為什么在Weblogic Server中改變session的值后要重新調(diào)用一次session.setValue
          做這個(gè)動(dòng)作主要是為了在集群環(huán)境中提示W(wǎng)eblogic Server session中的值發(fā)生了改變,需要向其他服務(wù)器進(jìn)程復(fù)制新的session值。

          10、為什么session不見了
          排除session正常失效的因素之外,服務(wù)器本身的可能性應(yīng)該是微乎其微的,雖然筆者在iPlanet6SP1加若干補(bǔ)丁的Solaris版本上倒也遇到過;瀏覽器插件的可能性次之,筆者也遇到過3721插件造成的問題;理論上防火墻或者代理服務(wù)器在cookie處理上也有可能會(huì)出現(xiàn)問題。
          出現(xiàn)這一問題的大部分原因都是程序的錯(cuò)誤,最常見的就是在一個(gè)應(yīng)用程序中去訪問另外一個(gè)應(yīng)用程序。我們?cè)谙乱还?jié)討論這個(gè)問題。

          七、跨應(yīng)用程序的session共享

          常常有這樣的情況,一個(gè)大項(xiàng)目被分割成若干小項(xiàng)目開發(fā),為了能夠互不干擾,要求每個(gè)小項(xiàng)目作為一個(gè)單獨(dú)的web應(yīng)用程序開發(fā),可是到了最后突然發(fā)現(xiàn)某幾個(gè)小項(xiàng)目之間需要共享一些信息,或者想使用session來實(shí)現(xiàn)SSO(single sign on),在session中保存login的用戶信息,最自然的要求是應(yīng)用程序間能夠訪問彼此的session。

          然而按照Servlet規(guī)范,session的作用范圍應(yīng)該僅僅限于當(dāng)前應(yīng)用程序下,不同的應(yīng)用程序之間是不能夠互相訪問對(duì)方的session的。各個(gè)應(yīng)用服務(wù)器從實(shí)際效果上都遵守了這一規(guī)范,但是實(shí)現(xiàn)的細(xì)節(jié)卻可能各有不同,因此解決跨應(yīng)用程序session共享的方法也各不相同。

          首先來看一下Tomcat是如何實(shí)現(xiàn)web應(yīng)用程序之間session的隔離的,從 Tomcat設(shè)置的cookie路徑來看,它對(duì)不同的應(yīng)用程序設(shè)置的cookie路徑是不同的,這樣不同的應(yīng)用程序所用的session id是不同的,因此即使在同一個(gè)瀏覽器窗口里訪問不同的應(yīng)用程序,發(fā)送給服務(wù)器的session id也可以是不同的。

          image
          image

          根據(jù)這個(gè)特性,我們可以推測(cè)Tomcat中session的內(nèi)存結(jié)構(gòu)大致如下。
          image

          筆者以前用過的iPlanet也采用的是同樣的方式,估計(jì)SunONE與iPlanet之間不會(huì)有太大的差別。對(duì)于這種方式的服務(wù)器,解決的思路很簡單,實(shí)際實(shí)行起來也不難。要么讓所有的應(yīng)用程序共享一個(gè)session id,要么讓應(yīng)用程序能夠獲得其他應(yīng)用程序的session id。

          iPlanet中有一種很簡單的方法來實(shí)現(xiàn)共享一個(gè)session id,那就是把各個(gè)應(yīng)用程序的cookie路徑都設(shè)為/(實(shí)際上應(yīng)該是/NASApp,對(duì)于應(yīng)用程序來講它的作用相當(dāng)于根)。
          <session-info>
          <path>/NASApp</path>
          </session-info>


          需要注意的是,操作共享的session應(yīng)該遵循一些編程約定,比如在session attribute名字的前面加上應(yīng)用程序的前綴,使得 setAttribute("name", "neo")變成setAttribute("app1.name", "neo"),以防止命名空間沖突,導(dǎo)致互相覆蓋。

          在Tomcat中則沒有這么方便的選擇。在Tomcat版本3上,我們還可以有一些手段來共享session。對(duì)于版本4以上的Tomcat,目前筆者尚未發(fā)現(xiàn)簡單的辦法。只能借助于第三方的力量,比如使用文件、數(shù)據(jù)庫、JMS或者客戶端cookie,URL參數(shù)或者隱藏字段等手段。

          我們?cè)倏匆幌耊eblogic Server是如何處理session的。
          image
          image

          從截屏畫面上可以看到Weblogic Server對(duì)所有的應(yīng)用程序設(shè)置的cookie的路徑都是/,這是不是意味著在Weblogic Server中默認(rèn)的就可以共享session了呢?然而一個(gè)小實(shí)驗(yàn)即可證明即使不同的應(yīng)用程序使用的是同一個(gè)session,各個(gè)應(yīng)用程序仍然只能訪問自己所設(shè)置的那些屬性。這說明Weblogic Server中的session的內(nèi)存結(jié)構(gòu)可能如下
          image

          對(duì)于這樣一種結(jié)構(gòu),在 session機(jī)制本身上來解決session共享的問題應(yīng)該是不可能的了。除了借助于第三方的力量,比如使用文件、數(shù)據(jù)庫、JMS或者客戶端 cookie,URL參數(shù)或者隱藏字段等手段,還有一種較為方便的做法,就是把一個(gè)應(yīng)用程序的session放到ServletContext中,這樣另外一個(gè)應(yīng)用程序就可以從ServletContext中取得前一個(gè)應(yīng)用程序的引用。示例代碼如下,

          應(yīng)用程序A
          context.setAttribute("appA", session);
          


          應(yīng)用程序B
          contextA = context.getContext("/appA");
          HttpSession sessionA = (HttpSession)contextA.getAttribute("appA");


          值得注意的是這種用法不可移植,因?yàn)楦鶕?jù)ServletContext的JavaDoc,應(yīng)用服務(wù)器可以處于安全的原因?qū)τ赾ontext.getContext("/appA");返回空值,以上做法在Weblogic Server 8.1中通過。

          那么Weblogic Server為什么要把所有的應(yīng)用程序的cookie路徑都設(shè)為/呢?原來是為了SSO,凡是共享這個(gè)session的應(yīng)用程序都可以共享認(rèn)證的信息。一個(gè)簡單的實(shí)驗(yàn)就可以證明這一點(diǎn),修改首先登錄的那個(gè)應(yīng)用程序的描述符weblogic.xml,把cookie路徑修改為/appA 訪問另外一個(gè)應(yīng)用程序會(huì)重新要求登錄,即使是反過來,先訪問cookie路徑為/的應(yīng)用程序,再訪問修改過路徑的這個(gè),雖然不再提示登錄,但是登錄的用戶信息也會(huì)丟失。注意做這個(gè)實(shí)驗(yàn)時(shí)認(rèn)證方式應(yīng)該使用FORM,因?yàn)闉g覽器和web服務(wù)器對(duì)basic認(rèn)證方式有其他的處理方式,第二次請(qǐng)求的認(rèn)證不是通過 session來實(shí)現(xiàn)的。具體請(qǐng)參看[7] secion 14.8 Authorization,你可以修改所附的示例程序來做這些試驗(yàn)。

          八、總結(jié)
          session機(jī)制本身并不復(fù)雜,然而其實(shí)現(xiàn)和配置上的靈活性卻使得具體情況復(fù)雜多變。這也要求我們不能把僅僅某一次的經(jīng)驗(yàn)或者某一個(gè)瀏覽器,服務(wù)器的經(jīng)驗(yàn)當(dāng)作普遍適用的經(jīng)驗(yàn),而是始終需要具體情況具體分析。
          摘要:雖然session機(jī)制在web應(yīng)用程序中被采用已經(jīng)很長時(shí)間了,但是仍然有很多人不清楚session機(jī)制的本質(zhì),以至不能正確的應(yīng)用這一技術(shù)。本文將詳細(xì)討論session的工作機(jī)制并且對(duì)在Java web application中應(yīng)用session機(jī)制時(shí)常見的問題作出解答。

          posted @ 2008-01-26 09:53 菠蘿 閱讀(339) | 評(píng)論 (0)編輯 收藏

          URLClassLoader加載class到當(dāng)前線程類加載器(轉(zhuǎn))

          我們知道,Java利用ClassLoader將類載入內(nèi)存,并且在同一應(yīng)用中,可以有很多個(gè)ClassLoader,通過委派機(jī)制,把裝載的任務(wù)傳遞給上級(jí)的裝載器的,依次類推,直到啟動(dòng)類裝載器(沒有上級(jí)類裝載器)。如果啟動(dòng)類裝載器能夠裝載這個(gè)類,那么它會(huì)首先裝載。如果不能,則往下傳遞。當(dāng)父類為null時(shí),JVM內(nèi)置的類(稱為:bootstrap class loader)就會(huì)充當(dāng)父類。想想眼下的越來越多用XML文件做配置文件或者是描述符、部署符。其實(shí)這些通過XML文檔描述的配置信息最終都要變成Java類,基實(shí)都是通過ClassLoader來完成的。URLClassLoader是ClassLoader的子類,它用于從指向 JAR 文件和目錄的 URL 的搜索路徑加載類和資源。也就是說,通過URLClassLoader就可以加載指定jar中的class到內(nèi)存中。
          下面來看一個(gè)例子,在該例子中,我們要完成的工作是利用URLClassLoader加載jar并運(yùn)行其中的類的某個(gè)方法。

          首先我們定義一個(gè)接口,使所有繼承它的類都必須實(shí)現(xiàn)action方法,如下:

            public   interface  ActionInterface  {
               public  String action();
          }
          完成后將其打包為testInterface.jar文件。

          接下來新建一工程,為了編譯通過,引入之前打好的testInterface.jar包。并創(chuàng)建TestAction類,使它實(shí)現(xiàn)ActionInterface接口。如下:


            public   class  TestAction  implements  ActionInterface  {
               public  String action()  {
                   return   " com.mxjava.TestAction.action " ;
              }
          }
           
          完成后將其打包為test.jar,放在c盤根目錄下。下面要做的就是利用URLClassLoader加載并運(yùn)行TestAction的action方法,并將返回的值打印在控制臺(tái)上。

          新建一工程,引入testInterface.jar包。并創(chuàng)建一可執(zhí)行類(main方法),在其中加入如下代碼:

           URL url  =   new  URL(“file:C: / test.jar”);
          URLClassLoader myClassLoader  =   new  URLClassLoader( new  URL[]  { url } );
          Class myClass  =  myClassLoader.loadClass(“com.mxjava.TestAction”);
          ActionInterface action  =  (ActionInterface)myClass.newInstance();
          System.out.println(action.action());
            在上面的例子中,首先利用URLClassLoader加載了C:\test.jar包,將其中的com.mxjava.TestAction類載入內(nèi)存,將其強(qiáng)制轉(zhuǎn)型為testInterface包中的ActionInterface類型,最后調(diào)用其action方法,并打印到控制臺(tái)中。

            執(zhí)行程序后,在控制臺(tái)上如期打印出我們想要的內(nèi)容。但是,事情并沒有那么簡單,當(dāng)我們將該代碼移動(dòng)web應(yīng)用中時(shí),就會(huì)拋出異常。原來,Java為我們提供了三種可選擇的ClassLoader:
          1. 系統(tǒng)類加載器或叫作應(yīng)用類加載器 (system classloader or application classloader)
          2. 當(dāng)前類加載器
          3. 當(dāng)前線程類加載器

            在上例中我們使用javac命令來運(yùn)行該程序,這時(shí)候使用的是系統(tǒng)類加載器 (system classloader)。這個(gè)類加載器處理 -classpath下的類加載工作,可以通過ClassLoader.getSystemClassLoader()方法調(diào)用。 ClassLoader 下所有的 getSystemXXX()的靜態(tài)方法都是通過這個(gè)方法定義的。在代碼中,應(yīng)該盡量少地調(diào)用這個(gè)方法,以其它的類加載器作為代理。否則代碼將只能工作在簡單的命令行應(yīng)用中。當(dāng)在web應(yīng)用中時(shí),服務(wù)器也是利用ClassLoader來加載class的,由于ClassLoader的不同,所以在強(qiáng)制轉(zhuǎn)型時(shí)JVM認(rèn)定不是同一類型。(在JAVA中,一個(gè)類用其完全匹配類名(fully qualified class name)作為標(biāo)識(shí),這里指的完全匹配類名包括包名和類名。但在JVM中一個(gè)類用其全名和一個(gè)加載類ClassLoader的實(shí)例作為唯一標(biāo)識(shí)。因此,如果一個(gè)名為Pg的包中,有一個(gè)名為Cl的類,被類加載器KlassLoader的一個(gè)實(shí)例kl1加載,Cl的實(shí)例,即C1.class在JVM中表示為(Cl, Pg, kl1)。這意味著兩個(gè)類加載器的實(shí)例(Cl, Pg, kl1) 和 (Cl, Pg, kl2)是不同的,被它們所加載的類也因此完全不同,互不兼容的。)為了能夠使程序正確運(yùn)行,我們首要解決的問題就是,如何將URLClassLoader加載的類,同當(dāng)前ClassLoader保持在同一類加載器中。解決方法很簡單,利用java提供的第三種ClassLoader—當(dāng)前線程類加載器即可。jdk api文檔就會(huì)發(fā)現(xiàn),URLClassLoader提供了三種構(gòu)造方式:

           // 使用默認(rèn)的委托父 ClassLoader 為指定的 URL 構(gòu)造一個(gè)新 URLClassLoader。 
           URLClassLoader(URL[] urls)
          // 為給定的 URL 構(gòu)造新 URLClassLoader。 
          URLClassLoader(URL[] urls, ClassLoader parent)
          // 為指定的 URL、父類加載器和 URLStreamHandlerFactory 創(chuàng)建新 URLClassLoader。
           URLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) 
          接下來要做的就是,在構(gòu)造URLClassLoader時(shí),將當(dāng)前線程類加載器置入即可。如下:

          URLClassLoader myClassLoader  =   new  URLClassLoader( new  URL[]  { url } , Thread.currentThread().getContextClassLoader());
          總結(jié):
            Java是利用ClassLoader來加載類到內(nèi)存的,ClassLoader本身是用java語言寫的,所以我們可以擴(kuò)展自己的ClassLoader。利用URLClassLoader可以加載指定jar包中的類到內(nèi)存。在命行上利用URLClassLoader加載jar時(shí),是使用系統(tǒng)類加載器來加載class的,所以在web環(huán)境下,就會(huì)出錯(cuò)。這是因?yàn)镴VM中一個(gè)類用其全名和一個(gè)加載類ClassLoader的實(shí)例作為唯一標(biāo)識(shí)的。我們只要利用URLClassLoader的第二種構(gòu)造方法并傳入當(dāng)前線程類加載器即可解決。

          posted @ 2008-01-26 09:51 菠蘿 閱讀(462) | 評(píng)論 (0)編輯 收藏

          了解Java ClassLoader

           

          【原文地址:https://www6.software.ibm.com/developerworks/cn/education/java/j-classloader/tutorial/】
          1.介紹
          2.ClassLoader的結(jié)構(gòu)
          3.Compiling ClassLoader
          4.java2 中ClassLoader的變動(dòng)
          5.源代碼
          ---------------------------------------------------------------------------

          第一章 介紹

          什么是 ClassLoader

          在流行的商業(yè)化編程語言中,Java 語言由于在 Java 虛擬機(jī) (JVM) 上運(yùn)行而顯得與眾不同。這意味著已編譯的程序是一種特殊的、獨(dú)立于平臺(tái)的格式,并非依賴于它們所運(yùn)行的機(jī)器。在很大程度上,這種格式不同于傳統(tǒng)的可執(zhí)行程序格式。

          與 C 或 C++ 編寫的程序不同,Java 程序并不是一個(gè)可執(zhí)行文件,而是由許多獨(dú)立的類文件組成,每一個(gè)文件對(duì)應(yīng)于一個(gè) Java 類。

          此外,這些類文件并非立即全部都裝入內(nèi)存,而是根據(jù)程序需要裝入內(nèi)存。ClassLoader 是 JVM 中將類裝入內(nèi)存的那部分。

          而且,Java ClassLoader 就是用 Java 語言編寫的。這意味著創(chuàng)建您自己的 ClassLoader 非常容易,不必了解 JVM 的微小細(xì)節(jié)。

          為什么編寫 ClassLoader?

          如果 JVM 已經(jīng)有一個(gè) ClassLoader,那么為什么還要編寫另一個(gè)呢?問得好。缺省的 ClassLoader 只知道如何從本地文件系統(tǒng)裝入類文件。不過這只適合于常規(guī)情況,即已全部編譯完 Java 程序,并且計(jì)算機(jī)處于等待狀態(tài)。

          但 Java 語言最具新意的事就是 JVM 可以非常容易地從那些非本地硬盤或從網(wǎng)絡(luò)上獲取類。例如,瀏覽者可以使用定制的 ClassLoader 從 Web 站點(diǎn)裝入可執(zhí)行內(nèi)容。

          有許多其它方式可以獲取類文件。除了簡單地從本地或網(wǎng)絡(luò)裝入文件以外,可以使用定制的 ClassLoader 完成以下任務(wù):

          • 在執(zhí)行非置信代碼之前,自動(dòng)驗(yàn)證數(shù)字簽名
          • 使用用戶提供的密碼透明地解密代碼
          • 動(dòng)態(tài)地創(chuàng)建符合用戶特定需要的定制化構(gòu)建類
          任何您認(rèn)為可以生成 Java 字節(jié)碼的內(nèi)容都可以集成到應(yīng)用程序中。

          定制 ClassLoader 示例

          如果使用過 JDK 或任何基于 Java 瀏覽器中的 Applet 查看器,那么您差不多肯定使用過定制的 ClassLoader。

          Sun 最初發(fā)布 Java 語言時(shí),其中最令人興奮的一件事是觀看這項(xiàng)新技術(shù)是如何執(zhí)行在運(yùn)行時(shí)從遠(yuǎn)程的 Web 服務(wù)器裝入的代碼。(此外,還有更令人興奮的事 -- Java 技術(shù)提供了一種便于編寫代碼的強(qiáng)大語言。)更一些令人激動(dòng)的是它可以執(zhí)行從遠(yuǎn)程 Web 服務(wù)器通過 HTTP 連接發(fā)送過來的字節(jié)碼。

          此項(xiàng)功能歸功于 Java 語言可以安裝定制 ClassLoader。Applet 查看器包含一個(gè) ClassLoader,它不在本地文件系統(tǒng)中尋找類,而是訪問遠(yuǎn)程服務(wù)器上的 Web 站點(diǎn),經(jīng)過 HTTP 裝入原始的字節(jié)碼文件,并把它們轉(zhuǎn)換成 JVM 內(nèi)的類。

          瀏覽器和 Applet 查看器中的 ClassLoaders 還可以做其它事情:它們支持安全性以及使不同的 Applet 在不同的頁面上運(yùn)行而互不干擾。

          Luke Gorrie 編寫的 Echidna 是一個(gè)開放源碼包,它可以使您在單個(gè)虛擬機(jī)上運(yùn)行多個(gè) Java 應(yīng)用程序。(請(qǐng)參閱進(jìn)一步了解和參考資料。)它使用定制的 ClassLoader,通過向每個(gè)應(yīng)用程序提供該類文件的自身副本,以防止應(yīng)用程序互相干擾。


          我們的 ClassLoader 示例

          了解了 ClassLoader 如何工作以及如何編寫 ClassLoader 之后,我們將創(chuàng)建稱作 CompilingClassLoader (CCL) 的 Classloader。CCL 為我們編譯 Java 代碼,而無需要我們干涉這個(gè)過程。它基本上就類似于直接構(gòu)建到運(yùn)行時(shí)系統(tǒng)中的 "make" 程序。

          注:進(jìn)一步了解之前,應(yīng)注意在 JDK 版本 1.2 中已改進(jìn)了 ClassLoader 系統(tǒng)的某些方面(即 Java 2 平臺(tái))。本教程是按 JDK 版本 1.0 和 1.1 寫的,但也可以在以后的版本中運(yùn)行。

          Java 2 中 ClassLoader 的變動(dòng)描述了 Java 版本 1.2 中的變動(dòng),并提供了一些詳細(xì)信息,以便修改 ClassLoader 來利用這些變動(dòng)。

           


           

          ------------------------------------------------------------------------------------------------------

          第二章.ClassLoader的結(jié)構(gòu)



          ClassLoader 的基本目標(biāo)是對(duì)類的請(qǐng)求提供服務(wù)。當(dāng) JVM 需要使用類時(shí),它根據(jù)名稱向 ClassLoader 請(qǐng)求這個(gè)類,然后 ClassLoader 試圖返回一個(gè)表示這個(gè)類的 Class 對(duì)象。

          通過覆蓋對(duì)應(yīng)于這個(gè)過程不同階段的方法,可以創(chuàng)建定制的 ClassLoader。

          在本章的其余部分,您會(huì)學(xué)習(xí) Java ClassLoader 的關(guān)鍵方法。您將了解每一個(gè)方法的作用以及它是如何適合裝入類文件這個(gè)過程的。您也會(huì)知道,創(chuàng)建自己的 ClassLoader 時(shí),需要編寫什么代碼。

          在下一章中,您將會(huì)利用這些知識(shí)來使用我們的 ClassLoader 示例 -- CompilingClassLoader。


          方法 loadClass


          ClassLoader.loadClass() 是 ClassLoader 的入口點(diǎn)。其特征如下:

           

          Class loadClass( String name, boolean resolve );

          name 參數(shù)指定了 JVM 需要的類的名稱,該名稱以包表示法表示,如 Foojava.lang.Object

          resolve 參數(shù)告訴方法是否需要解析類。在準(zhǔn)備執(zhí)行類之前,應(yīng)考慮類解析。并不總是需要解析。如果 JVM 只需要知道該類是否存在或找出該類的超類,那么就不需要解析。

          在 Java 版本 1.1 和以前的版本中,loadClass 方法是創(chuàng)建定制的 ClassLoader 時(shí)唯一需要覆蓋的方法。(Java 2 中 ClassLoader 的變動(dòng)提供了關(guān)于 Java 1.2 中 findClass() 方法的信息。)


          方法 defineClass

          defineClass 方法是 ClassLoader 的主要訣竅。該方法接受由原始字節(jié)組成的數(shù)組并把它轉(zhuǎn)換成 Class 對(duì)象。原始數(shù)組包含如從文件系統(tǒng)或網(wǎng)絡(luò)裝入的數(shù)據(jù)。

          defineClass 管理 JVM 的許多復(fù)雜、神秘和倚賴于實(shí)現(xiàn)的方面 -- 它把字節(jié)碼分析成運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)、校驗(yàn)有效性等等。不必?fù)?dān)心,您無需親自編寫它。事實(shí)上,即使您想要這么做也不能覆蓋它,因?yàn)樗驯粯?biāo)記成最終的。


          方法 findSystemClass

          findSystemClass 方法從本地文件系統(tǒng)裝入文件。它在本地文件系統(tǒng)中尋找類文件,如果存在,就使用 defineClass 將原始字節(jié)轉(zhuǎn)換成 Class 對(duì)象,以將該文件轉(zhuǎn)換成類。當(dāng)運(yùn)行 Java 應(yīng)用程序時(shí),這是 JVM 正常裝入類的缺省機(jī)制。(Java 2 中 ClassLoader 的變動(dòng)提供了關(guān)于 Java 版本 1.2 這個(gè)過程變動(dòng)的詳細(xì)信息。)

          對(duì)于定制的 ClassLoader,只有在嘗試其它方法裝入類之后,再使用 findSystemClass。原因很簡單:ClassLoader 是負(fù)責(zé)執(zhí)行裝入類的特殊步驟,不是負(fù)責(zé)所有類。例如,即使 ClassLoader 從遠(yuǎn)程的 Web 站點(diǎn)裝入了某些類,仍然需要在本地機(jī)器上裝入大量的基本 Java 庫。而這些類不是我們所關(guān)心的,所以要 JVM 以缺省方式裝入它們:從本地文件系統(tǒng)。這就是 findSystemClass 的用途。

          其工作流程如下:

           

          • 請(qǐng)求定制的 ClassLoader 裝入類。
          • 檢查遠(yuǎn)程 Web 站點(diǎn),查看是否有所需要的類。
          • 如果有,那么好;抓取這個(gè)類,完成任務(wù)。
          • 如果沒有,假定這個(gè)類是在基本 Java 庫中,那么調(diào)用 findSystemClass,使它從文件系統(tǒng)裝入該類。

          在大多數(shù)定制 ClassLoaders 中,首先調(diào)用 findSystemClass 以節(jié)省在本地就可以裝入的許多 Java 庫類而要在遠(yuǎn)程 Web 站點(diǎn)上查找所花的時(shí)間。然而,正如,在下一章節(jié)所看到的,直到確信能自動(dòng)編譯我們的應(yīng)用程序代碼時(shí),才讓 JVM 從本地文件系統(tǒng)裝入類。


          方法 resolveClass

          正如前面所提到的,可以不完全地(不帶解析)裝入類,也可以完全地(帶解析)裝入類。當(dāng)編寫我們自己的 loadClass 時(shí),可以調(diào)用 resolveClass,這取決于 loadClassresolve 參數(shù)的值。

          方法 findLoadedClass

          findLoadedClass 充當(dāng)一個(gè)緩存:當(dāng)請(qǐng)求 loadClass 裝入類時(shí),它調(diào)用該方法來查看 ClassLoader 是否已裝入這個(gè)類,這樣可以避免重新裝入已存在類所造成的麻煩。應(yīng)首先調(diào)用該方法。

          組裝

           

           

           

          讓我們看一下如何組裝所有方法。

          我們的 loadClass 實(shí)現(xiàn)示例執(zhí)行以下步驟。(這里,我們沒有指定生成類文件是采用了哪種技術(shù) -- 它可以是從 Net 上裝入、或者從歸檔文件中提取、或者實(shí)時(shí)編譯。無論是哪一種,那是種特殊的神奇方式,使我們獲得了原始類文件字節(jié)。)

           

          • 調(diào)用 findLoadedClass 來查看是否存在已裝入的類。

          • 如果沒有,那么采用那種特殊的神奇方式來獲取原始字節(jié)。

          • 如果已有原始字節(jié),調(diào)用 defineClass 將它們轉(zhuǎn)換成 Class 對(duì)象。

          • 如果沒有原始字節(jié),然后調(diào)用 findSystemClass 查看是否從本地文件系統(tǒng)獲取類。

          • 如果 resolve 參數(shù)是 true,那么調(diào)用 resolveClass 解析 Class 對(duì)象。

          • 如果還沒有類,返回 ClassNotFoundException

          • 否則,將類返回給調(diào)用程序。
          推想

          現(xiàn)在您已經(jīng)了解了 ClassLoader 的工作原理,現(xiàn)在該構(gòu)建一個(gè)了。在下一章中,我們將討論 CCL。

          ---------------------------------------------------------------------------------------------

          第三章:Compiling ClassLoader

          CCL 揭密

          我們的 ClassLoader (CCL) 的任務(wù)是確保代碼被編譯和更新。

          下面描述了它的工作方式:

           

          • 當(dāng)請(qǐng)求一個(gè)類時(shí),先查看它是否在磁盤的當(dāng)前目錄或相應(yīng)的子目錄。

          • 如果該類不存在,但源碼中有,那么調(diào)用 Java 編譯器來生成類文件。

          • 如果該類已存在,檢查它是否比源碼舊。如果是,調(diào)用 Java 編譯器來重新生成類文件。

          • 如果編譯失敗,或者由于其它原因不能從現(xiàn)有的源碼中生成類文件,返回 ClassNotFoundException

          • 如果仍然沒有該類,也許它在其它庫中,所以調(diào)用 findSystemClass 來尋找該類。

          • 如果還是沒有,則返回 ClassNotFoundException

          • 否則,返回該類。
          Java 編譯的工作方式

           

          在深入討論之前,應(yīng)該先退一步,討論 Java 編譯。通常,Java 編譯器不只是編譯您要求它編譯的類。它還會(huì)編譯其它類,如果這些類是您要求編譯的類所需要的類。

          CCL 逐個(gè)編譯應(yīng)用程序中的需要編譯的每一個(gè)類。但一般來說,在編譯器編譯完第一個(gè)類后,CCL 會(huì)查找所有需要編譯的類,然后編譯它。為什么?Java 編譯器類似于我們正在使用的規(guī)則:如果類不存在,或者與它的源碼相比,它比較舊,那么它需要編譯。其實(shí),Java 編譯器在 CCL 之前的一個(gè)步驟,它會(huì)做大部分的工作。

          當(dāng) CCL 編譯它們時(shí),會(huì)報(bào)告它正在編譯哪個(gè)應(yīng)用程序上的類。在大多數(shù)的情況下,CCL 會(huì)在程序中的主類上調(diào)用編譯器,它會(huì)做完所有要做的 -- 編譯器的單一調(diào)用已足夠了。

          然而,有一種情形,在第一步時(shí)不會(huì)編譯某些類。如果使用 Class.forName 方法,通過名稱來裝入類,Java 編譯器會(huì)不知道這個(gè)類時(shí)所需要的。在這種情況下,您會(huì)看到 CCL 再次運(yùn)行 Java 編譯器來編譯這個(gè)類。在源代碼中演示了這個(gè)過程。

          使用 CompilationClassLoader

          要使用 CCL,必須以特殊方式調(diào)用程序。不能直接運(yùn)行該程序,如:

           

          % java Foo arg1 arg2

          應(yīng)以下列方式運(yùn)行它:

           

          % java CCLRun Foo arg1 arg2

          CCLRun 是一個(gè)特殊的存根程序,它創(chuàng)建 CompilingClassLoader 并用它來裝入程序的主類,以確保通過 CompilingClassLoader 來裝入整個(gè)程序。CCLRun 使用 Java Reflection API 來調(diào)用特定類的主方法并把參數(shù)傳遞給它。有關(guān)詳細(xì)信息,請(qǐng)參閱源代碼

          運(yùn)行示例

          源碼包括了一組小類,它們演示了工作方式。主程序是 Foo 類,它創(chuàng)建類 Bar 的實(shí)例。類 Bar 創(chuàng)建另一個(gè)類 Baz 的實(shí)例,它在 baz 包內(nèi),這是為了展示 CCL 是如何處理子包里的代碼。Bar 也是通過名稱裝入的,其名稱為 Boo,這用來展示它也能與 CCL 工作。

          每個(gè)類都聲明已被裝入并運(yùn)行。現(xiàn)在用源代碼來試一下。編譯 CCLRun 和 CompilingClassLoader。確保不要編譯其它類(FooBarBazBoo),否則將不會(huì)使用 CCL,因?yàn)檫@些類已經(jīng)編譯過了。

           


          % java CCLRun Foo arg1 arg2
          CCL: Compiling Foo.java...
          foo! arg1 arg2
          bar! arg1 arg2
          baz! arg1 arg2
          CCL: Compiling Boo.java...
          Boo!

          請(qǐng)注意,首先調(diào)用編譯器,Foo.java 管理 Barbaz.Baz。直到 Bar 通過名稱來裝入 Boo 時(shí),被調(diào)用它,這時(shí) CCL 會(huì)再次調(diào)用編譯器來編譯它。

           

           

           

           

          --------------------------------------------------------------------------------------

          第四章:java2 中ClassLoader的變動(dòng)


          概述

          在 Java 版本 1.2 和以后的版本中,對(duì) ClassLoader 做了一些改進(jìn)。任何為老系統(tǒng)編寫的代碼可以在新版本中運(yùn)行,但新系統(tǒng)為您提供了一些便利。

          新模型是委托模型,這意味著如果 ClassLoader 不能找到類,它會(huì)請(qǐng)求父代 ClassLoader 來執(zhí)行此項(xiàng)任務(wù)。所有 ClassLoaders 的根是系統(tǒng) ClassLoader,它會(huì)以缺省方式裝入類 -- 即,從本地文件系統(tǒng)。

          loadClass 的缺省實(shí)現(xiàn)

          定制編寫的 loadClass 方法一般嘗試幾種方式來裝入所請(qǐng)求的類,如果您編寫許多類,會(huì)發(fā)現(xiàn)一次次地在相同的、很復(fù)雜的方法上編寫變量。

          在 Java 1.2 中 loadClass 的實(shí)現(xiàn)嵌入了大多數(shù)查找類的一般方法,并使您通過覆蓋 findClass 方法來定制它,在適當(dāng)?shù)臅r(shí)候 findClass 會(huì)調(diào)用 loadClass

          這種方式的好處是您可能不一定要覆蓋 loadClass;只要覆蓋 findClass 就行了,這減少了工作量。

          新方法:findClass

          loadClass 的缺省實(shí)現(xiàn)調(diào)用這個(gè)新方法。findClass 的用途包含您的 ClassLoader 的所有特殊代碼,而無需要復(fù)制其它代碼(例如,當(dāng)專門的方法失敗時(shí),調(diào)用系統(tǒng) ClassLoader)。

          新方法:getSystemClassLoader

          如果覆蓋 findClassloadClassgetSystemClassLoader 使您能以實(shí)際 ClassLoader 對(duì)象來訪問系統(tǒng) ClassLoader(而不是固定的從 findSystemClass 調(diào)用它)。

          新方法:getParent

          為了將類請(qǐng)求委托給父代 ClassLoader,這個(gè)新方法允許 ClassLoader 獲取它的父代 ClassLoader。當(dāng)使用特殊方法,定制的 ClassLoader 不能找到類時(shí),可以使用這種方法。

          父代 ClassLoader 被定義成創(chuàng)建該 ClassLoader 所包含代碼的對(duì)象的 ClassLoader。

          ----------------------------------------------------------------------------------

           

           

           

          第五章.源代碼

           

          CompilingClassLoader.java

          以下是 CompilingClassLoader.java 的源代碼

          // $Id$
          import java.io.*;
          /*
          A CompilingClassLoader compiles your Java source on-the-fly. It checks
          for nonexistent .class files, or .class files that are older than their
          corresponding source code.*/
          public class CompilingClassLoader extends ClassLoader
          {
          // Given a filename, read the entirety of that file from disk
          // and return it as a byte array.
          private byte[] getBytes( String filename ) throws IOException {
          // Find out the length of the file
          File file = new File( filename );
          long len = file.length();
          // Create an array that's just the right size for the file's
          // contents
          byte raw[] = new byte[(int)len];
          // Open the file
          FileInputStream fin = new FileInputStream( file );
          // Read all of it into the array; if we don't get all,
          // then it's an error.
          int r = fin.read( raw );
          if (r != len)
          throw new IOException( "Can't read all, "+r+" != "+len );
          // Don't forget to close the file!
          fin.close();
          // And finally return the file contents as an array
          return raw;
          }
          // Spawn a process to compile the java source code file
          // specified in the 'javaFile' parameter. Return a true if
          // the compilation worked, false otherwise.
          private boolean compile( String javaFile ) throws IOException {
          // Let the user know what's going on
          System.out.println( "CCL: Compiling "+javaFile+"..." );
          // Start up the compiler
          Process p = Runtime.getRuntime().exec( "javac "+javaFile );
          // Wait for it to finish running
          try {
          p.waitFor();
          } catch( InterruptedException ie ) { System.out.println( ie ); }
          // Check the return code, in case of a compilation error
          int ret = p.exitValue();
          // Tell whether the compilation worked
          return ret==0;
          }
          // The heart of the ClassLoader -- automatically compile
          // source as necessary when looking for class files
          public Class loadClass( String name, boolean resolve )
          throws ClassNotFoundException {

          // Our goal is to get a Class object
          Class clas = null;

          // First, see if we've already dealt with this one
          clas = findLoadedClass( name );

          //System.out.println( "findLoadedClass: "+clas );

          // Create a pathname from the class name
          // E.g. java.lang.Object => java/lang/Object
          String fileStub = name.replace( '.', '/' );

          // Build objects pointing to the source code (.java) and object
          // code (.class)
          String javaFilename = fileStub+".java";
          String classFilename = fileStub+".class";

          File javaFile = new File( javaFilename );
          File classFile = new File( classFilename );

          //System.out.println( "j "+javaFile.lastModified()+" c "+
          // classFile.lastModified() );

          // First, see if we want to try compiling. We do if (a) there
          // is source code, and either (b0) there is no object code,
          // or (b1) there is object code, but it's older than the source
          if (javaFile.exists() &&
          (!classFile.exists() ||
          javaFile.lastModified() > classFile.lastModified())) {

          try {
          // Try to compile it. If this doesn't work, then
          // we must declare failure. (It's not good enough to use
          // and already-existing, but out-of-date, classfile)
          if (!compile( javaFilename ) || !classFile.exists()) {
          throw new ClassNotFoundException( "Compile failed: "+javaFilename );
          }
          } catch( IOException ie ) {

          // Another place where we might come to if we fail
          // to compile
          throw new ClassNotFoundException( ie.toString() );
          }
          }

          // Let's try to load up the raw bytes, assuming they were
          // properly compiled, or didn't need to be compiled
          try {

          // read the bytes
          byte raw[] = getBytes( classFilename );

          // try to turn them into a class
          clas = defineClass( name, raw, 0, raw.length );
          } catch( IOException ie ) {
          // This is not a failure! If we reach here, it might
          // mean that we are dealing with a class in a library,
          // such as java.lang.Object
          }

          //System.out.println( "defineClass: "+clas );

          // Maybe the class is in a library -- try loading
          // the normal way
          if (clas==null) {
          clas = findSystemClass( name );
          }

          //System.out.println( "findSystemClass: "+clas );

          // Resolve the class, if any, but only if the "resolve"
          // flag is set to true
          if (resolve && clas != null)
          resolveClass( clas );

          // If we still don't have a class, it's an error
          if (clas == null)
          throw new ClassNotFoundException( name );

          // Otherwise, return the class
          return clas;
          }
           }
          CCRun.java


          以下是 CCRun.java 的源代碼


          // $Id$

          import java.lang.reflect.*;

          /*

          CCLRun executes a Java program by loading it through a
          CompilingClassLoader.

          */

          public class CCLRun
          {
          static public void main( String args[] ) throws Exception {

          // The first argument is the Java program (class) the user
          // wants to run
          String progClass = args[0];

          // And the arguments to that program are just
          // arguments 1..n, so separate those out into
          // their own array
          String progArgs[] = new String[args.length-1];
          System.arraycopy( args, 1, progArgs, 0, progArgs.length );

          // Create a CompilingClassLoader
          CompilingClassLoader ccl = new CompilingClassLoader();

          // Load the main class through our CCL
          Class clas = ccl.loadClass( progClass );

          // Use reflection to call its main() method, and to
          // pass the arguments in.

          // Get a class representing the type of the main method's argument
          Class mainArgType[] = { (new String[0]).getClass() };

          // Find the standard main method in the class
          Method main = clas.getMethod( "main", mainArgType );

          // Create a list containing the arguments -- in this case,
          // an array of strings
          Object argsArray[] = { progArgs };

          // Call the method
          main.invoke( null, argsArray );
          }
          }
          Foo.java


          以下是 Foo.java 的源代碼



          // $Id$

          public class Foo
          {
          static public void main( String args[] ) throws Exception {
          System.out.println( "foo! "+args[0]+" "+args[1] );
          new Bar( args[0], args[1] );
          }
          }
          Bar.java


          以下是 Bar.java 的源代碼


          // $Id$

          import baz.*;

          public class Bar
          {
          public Bar( String a, String b ) {
          System.out.println( "bar! "+a+" "+b );
          new Baz( a, b );

          try {
          Class booClass = Class.forName( "Boo" );
          Object boo = booClass.newInstance();
          } catch( Exception e ) {
          e.printStackTrace();
          }
          }
          }
          baz/Baz.java


          以下是 baz/Baz.java 的源代碼


          // $Id$

          package baz;

          public class Baz
          {
          public Baz( String a, String b ) {
          System.out.println( "baz! "+a+" "+b );
          }
          }

          Boo.java


          以下是 Boo.java 的源代碼


          // $Id$

          public class Boo
          {
          public Boo() {
          System.out.println( "Boo!" );
          }
          }

          posted @ 2008-01-25 13:52 菠蘿 閱讀(330) | 評(píng)論 (0)編輯 收藏

          eclipse配置weblogic(轉(zhuǎn))

          安裝WebLogic8.1
          安裝WebLogic比較容易,在這里就不再累述了,大家可以參閱相關(guān)文檔。現(xiàn)在著重講一下WebLogic的配置,因?yàn)楹竺嬖谂渲肕yEclipse時(shí)將用到這里的有關(guān)信息。
          (1)運(yùn)行開始\程序\BEA WebLogic PlatFORM 8.1\Configuration Wizard。
          (2)選擇Create a new WebLogic configuration,下一步。
          (3)選擇Basic WebLogic Server Domain,下一步。
          (4)選擇Custom,下一步。
          (5)在Name處輸入admin,Listen Address處選擇localhost,以下兩個(gè)Port均采用默認(rèn)值,下一步。
          (6)選擇Skip跳過Multiple Servers,Clusters,and Machines Options,下一步。
          (7)選擇Skip跳過JDBC連接池的配置(注:JDBC連接池的配置可以在啟動(dòng)WebLogic后到控制臺(tái)上進(jìn)行,大家可以參閱相關(guān)文檔),下一步。
          (選擇Skip跳過JMS的配置(同樣留到控制臺(tái)上做),下一步。
          (9)繼續(xù)跳過,下一步。
          (10)選擇Yes,下一步。
          (11)在User頁點(diǎn)擊Add,隨意添加一個(gè)用戶user,密碼12345678,下一步。
          (12)將用戶user分配到Administrators組(還可以同時(shí)分配到其它組,方法是選中待加入的組,然后勾中user前的復(fù)選框即可),下一步。
          (13)直接點(diǎn)擊下一步跳過。
          (14)設(shè)置用戶user的權(quán)限,選中Admin,勾中user前的復(fù)選框(要指定其它權(quán)限依次類推),下一步。
          (15)采用默認(rèn)設(shè)置,直接點(diǎn)擊下一步跳過。
          (16)同樣采用默認(rèn)設(shè)置,直接點(diǎn)擊下一步跳過。
          (17)配置JDK,采用WebLogic的默認(rèn)值,直接點(diǎn)擊下一步跳過。
          (1最后在Configuration Name處輸入dev,然后點(diǎn)擊Create生成配置,完畢點(diǎn)擊Done關(guān)閉Configuration Wizard對(duì)話框。
          5.配置MyEclipse的WebLogic服務(wù)器
          MyEclipse默認(rèn)的應(yīng)用服務(wù)器為JBoss3,這里我們使用WebLogic8.1。啟動(dòng)Eclipse,選擇“窗口\首選項(xiàng)”菜單,打開首選項(xiàng)對(duì)話框。展開MyEclipse下的Application Servers結(jié)點(diǎn),點(diǎn)擊JBoss 3,選中右面的Disable單選按鈕,停用JBoss 3。然后點(diǎn)擊WebLogic 8,選中右邊的Enable單選按鈕,啟用WebLogic服務(wù)器。同時(shí)下面的配置如下:
          (1)BEA home directory:D:\BEA。假定WebLogic安裝在D:\BEA文件夾中。
          (2)WebLogic installation directory:D:\BEA\weblogic81。
          (3)Admin username:user。
          (4)Admin password:12345678。
          (5)Execution domain root:D:\BEA\user_projects\dev。
          (6)Execution domain name:dev。
          (7)Execution server name:admin。
          (8)Hostname:PortNumber:localhost:7001。
          (9)Security policy file:D:\BEA\weblogic81\server\lib\weblogic.policy。
          (10)JAAS login configuration file:省略。
          接著展開WebLogic 8結(jié)點(diǎn),點(diǎn)擊JDK,在右邊的WLS JDK name處選擇WebLogic 8的默認(rèn)JDK。這里組合框中缺省為j2re1.4.2_03,即之前單獨(dú)安裝的jre。單擊Add按鈕,彈出WebLogic > Add JVM對(duì)話框,在JRE名稱處隨便輸入一個(gè)名字,如jre1.4.1_02。然后在JRE主目錄處選擇WebLogic安裝文件夾中的JDK文件夾,如D:\BEA\jdk141_02,程序會(huì)自動(dòng)填充Javadoc URL文本框和JRE系統(tǒng)庫列表框。單擊確定按鈕關(guān)閉對(duì)話框。這時(shí)候就可以在WLS JDK name組合框中選擇jre1.4.1_02了。之后還要在下面的Optional Java VM arguments,如-ms64m -mx64m -Djava.library.path="D:/BEA/weblogic81/server/bin" -Dweblogic.management.discover=false -Dweblogic.ProductionModeEnabled=false
          最后點(diǎn)擊Paths,在右邊的Prepend to classpath列表框中,通過Add JAR/ZIP按鈕,加入D:\BEA\weblogic81\server\lib\weblogic.jar、D:\BEA\weblogic81\server\lib\webservices.jar。如果用到數(shù)據(jù)庫,還需把數(shù)據(jù)庫的驅(qū)動(dòng)類庫加進(jìn)來,這里我們用WebLogic自帶的SQL Server數(shù)據(jù)庫驅(qū)動(dòng)庫D:\BEA\weblogic81\server\lib\mssqlserver4v65.jar。
          至此,MyEclipse中WebLogic8的配置工作就算完成了。下面可以看看在Eclipse中能否啟動(dòng)WebLogic了?自從安裝了MyEclipse之后,Eclipse工具欄中就會(huì)有一個(gè)Run/Stop Servers下拉按鈕。點(diǎn)擊該按鈕的下拉部分,選擇“WebLogic 8\Start”菜單,即開始啟動(dòng)WebLogic了。通過查看下面的控制臺(tái)消息,就可以知道啟動(dòng)是否成功,或有什么異常發(fā)生。停止WebLogic可選擇“WebLogic\Stop”菜單。 

          posted @ 2008-01-24 15:33 菠蘿 閱讀(995) | 評(píng)論 (0)編輯 收藏

          J2EE配置WebLogic-Eclipse插件(轉(zhuǎn))

          Eclipse插件設(shè)計(jì)用于從Eclipse IDE運(yùn)行 WebLogic Server.借助WebLogic Server插件,可以從Eclipse中啟動(dòng)和停止WebLogic Server,可以通過 Eclipse調(diào)試WebLogic Server中部署的應(yīng)用程序。在Eclipse中安裝WebLogic插件,并在Eclipse中設(shè)置服務(wù)器類路徑和JVM選項(xiàng)后,即可通過Eclipse IDE配置和管理WebLogic Server.

            概述

            J2EE開發(fā)人員經(jīng)常需要管理WebLogic Server并調(diào)試WebLogic Server上部署的應(yīng)用程序。 WebLogic Server管理控制臺(tái)雖然能夠啟動(dòng)和停止WebLogic Server,卻不能設(shè)置JVM選項(xiàng)和服務(wù)器類路徑。必須使用startWebLogic腳本來設(shè)置JVM選項(xiàng)和服務(wù)器類路徑。而要調(diào)試WebLogic Server上部署的應(yīng)用程序,則需要帶遠(yuǎn)程調(diào)試器的IDE.有了WebLogic插件后,就可以通過Eclipse IDE管理WebLogic Server. 在文本中,我們將開發(fā)一個(gè)包括會(huì)話EJB和servlet的J2EE應(yīng)用程序、通過Eclipse IDE在WebLogic Server中部署應(yīng)用程序、在Eclipse中調(diào)試應(yīng)用程序。

            安裝準(zhǔn)備

            下載并安裝Eclipse 3.0 IDE:www.eclipse.org

            下載并安裝WebLogic Server 8.1:

            www.bea.com/framework.jsp?CNT=index.htm&FP=/content/products/weblogic/server

            安裝WebLogic-Eclipse插件

            現(xiàn)在安裝WebLogic-Eclipse IDE.在Eclipse IDE上,選擇Help>Software Updates>Find and Install,將顯示Install/Update窗體。選擇Search for new features to install,然后單擊Next按鈕。在顯示的Install窗體中,單擊New Remote Site按鈕指定要從其安裝插件的更新Web站點(diǎn)。在New Update Site窗體中,指定名稱和安裝WebLogic-Eclipse插件的URL.WebLogic-Eclipse插件的URL是

            選擇許可條款并單擊Next按鈕。在Install location窗體中指定將安裝WebLogic-Eclipse插件的目錄。單擊Finish按鈕完成WebLogic插件的配置。在顯示的JAR Verification窗體中,單擊Install按鈕安裝WebLogic-Eclipse插件。重啟Eclipse工作臺(tái)完成插件安裝。現(xiàn)在WebLogic-Eclipse插件便安裝在 Eclipse IDE中了。Eclipse中新添了Run>Start WebLogic和Run>Stop WebLogic兩個(gè)功能。

            配置WebLogic-Eclipse插件

            安裝了WebLogic-Eclipse插件后,我們將在Eclipse IDE中配置該插件。首先,創(chuàng)建一個(gè)用于配置WebLogic插件的項(xiàng)目。選擇File>New>Project.在New Project窗體中選擇Java>Java Project,然后單擊Next按鈕。在Create a Java project窗體中指定項(xiàng)目名稱,然后單擊Next按鈕。在Java Settings窗體中為項(xiàng)目添加源文件夾。單擊Add Folder按鈕。在New Source Folder窗體中指定文件夾名稱。出現(xiàn)一個(gè)消息窗體提示設(shè)置bin文件夾作為構(gòu)建輸出文件夾。接下來,添加項(xiàng)目所需的庫。示例應(yīng)用程序需要在類路徑中添加J2EE JAR.選擇Libraries選項(xiàng)卡,然后單擊Add External JARs按鈕。

            為項(xiàng)目添加J2EE 1.4 j2ee.jar文件。1.4 j2ee.jar將在項(xiàng)目庫中列出。單擊Finish按鈕完成項(xiàng)目配置。這樣便將一個(gè)項(xiàng)目添加到Eclipse IDE Package Explorer視圖中。

            接下來指定WebLogic Server配置。選擇Window>Preferences.在出現(xiàn)的Preferences窗體中,選擇WebLogic節(jié)點(diǎn)。在WebLogic preference頁面,選擇要配置的WebLogic Server版本。指定不同的字段值,如 表1 所示。由于安裝服務(wù)器和配置域的目錄不同,值也有所不同。單擊Apply按鈕應(yīng)用指定的值。

            字段描述值

            表1 WebLogic-Eclipse插件

            如果必須向服務(wù)器類路徑添加JAR文件,請(qǐng)選擇WebLogic>Classpath節(jié)點(diǎn)。可以在添加WebLogic庫之前或之后添加JAR/Zip文件或目錄。選擇WebLogic>JavaVM Options節(jié)點(diǎn)指定JavaVM選項(xiàng)。例如,修改weblogic.ProductionModeEnabled屬性。將屬性值設(shè)置為false可使用開發(fā)模式啟動(dòng)服務(wù)器。單擊Apply按鈕應(yīng)用JavaVM選項(xiàng)。

            接下來,指定要使用WebLogic Server配置進(jìn)行調(diào)試的項(xiàng)目。單擊Add按鈕,選擇要添加到插件配置的項(xiàng)目。若要調(diào)試某個(gè)項(xiàng)目,該項(xiàng)目必須位于插件配置中。單擊OK按鈕。

            這樣便將選擇的項(xiàng)目添加到項(xiàng)目列表中了。單擊Apply按鈕,然后單擊OK按鈕,使用項(xiàng)目和WebLogic Server完成WebLogic插件的配置。

            開發(fā)和調(diào)試WebLogic應(yīng)用程序

            配置了WebLogic插件后,將開發(fā)一個(gè)J2EE應(yīng)用程序在WebLogic Server中進(jìn)行部署和調(diào)試。示例J2EE應(yīng)用程序由Session EJB和客戶端servlet組成。可從資源zip文件中獲取該 J2EE應(yīng)用程序(關(guān)于本文的源代碼,可在線查看WLDJ歸檔文件中的文章 http://wldj.sys-con.com/read/issue/archives/,Vol. 5,iss. 2)。將資源zip文件提取到目錄。在上文中配置的Eclipse項(xiàng)目EclipseWebLogic中,選擇File>Import導(dǎo)入J2EE應(yīng)用程序的src目錄。在Import窗體中,選擇File System節(jié)點(diǎn),然后單擊Next按鈕。在File system窗體中,選擇directories/files添加項(xiàng)目,然后單擊Finish按鈕(見圖1)。

          配置WebLogic-Eclipse插件 圖-1

            圖1

            這樣便將示例J2EE應(yīng)用程序文件添加到項(xiàng)目中。使用Ant build.xml文件構(gòu)建項(xiàng)目。右鍵單擊build.xml,選擇Run>Ant Build即可構(gòu)建J2EE應(yīng)用程序并將其部署在WebLogic Server應(yīng)用程序目錄中。接下來,選擇Run>Start WebLogic在Eclipse IDE中啟動(dòng)WebLogic Server.這樣便將Session EJB/Servlet應(yīng)用程序部署在 WebLogic Server中,如應(yīng)用程序節(jié)點(diǎn)所示。

            在瀏覽器中輸入U(xiǎn)RL http://localhost:7001/weblogic/webLogicPlug-in運(yùn)行WebLogicServlet. servlet的輸出將在瀏覽器中顯示。接下來向客戶端servlet添加一個(gè)異常(NullPointerException),以驗(yàn)證WebLogic插件的調(diào)試功能。在WebLogicServlet servlet中將:

            out.println(sessionEJB.getEclipsePlug-in());

            替換為:

            String str=null;

            out.println(str.toString());

            選擇Run>Add Java Exception Breakpoint向servlet添加一個(gè)斷點(diǎn)。在Add Java Exception Breakpoint窗體中,選擇NullPointerException.刪除之前構(gòu)建的目錄并使用build.xml構(gòu)建應(yīng)用程序。選擇Debug perspective.在Debug perspective可以看到WebLogic Server正運(yùn)行在localhost主機(jī)中。

            在瀏覽器中運(yùn)行示例servlet(帶NullPointerException)。因?yàn)閟ervlet帶有異常,所以服務(wù)器被中斷,并且Debug perspective顯示NullPointerException.使用Run菜單項(xiàng)中的調(diào)試功能可以調(diào)試應(yīng)用程序。

            結(jié)束語

            綜上所述,使用WebLogic插件可以通過Eclipse IDE管理WebLogic Server,還可通過Eclipse IDE調(diào)試服務(wù)器中部署的應(yīng)用程序。WebLogic插件的局限性在于不支持JSP調(diào)試。該插件的2.0版本將有更多功能。

          J2EE配置WebLogic-Eclipse插件

          posted @ 2008-01-24 15:32 菠蘿 閱讀(456) | 評(píng)論 (0)編輯 收藏

          C3P0連接池詳細(xì)配置(轉(zhuǎn))

          <c3p0-config>
          <default-config>
          <!--當(dāng)連接池中的連接耗盡的時(shí)候c3p0一次同時(shí)獲取的連接數(shù)。Default: 3 -->
          <property name="acquireIncrement">3</property>

          <!--定義在從數(shù)據(jù)庫獲取新連接失敗后重復(fù)嘗試的次數(shù)。Default: 30 -->
          <property name="acquireRetryAttempts">30</property>

          <!--兩次連接中間隔時(shí)間,單位毫秒。Default: 1000 -->
          <property name="acquireRetryDelay">1000</property>

          <!--連接關(guān)閉時(shí)默認(rèn)將所有未提交的操作回滾。Default: false -->
          <property name="autoCommitOnClose">false</property>

          <!--c3p0將建一張名為Test的空表,并使用其自帶的查詢語句進(jìn)行測(cè)試。如果定義了這個(gè)參數(shù)那么
          屬性preferredTestQuery將被忽略。你不能在這張Test表上進(jìn)行任何操作,它將只供c3p0測(cè)試
          使用。Default: null-->
          <property name="automaticTestTable">Test</property>

          <!--獲取連接失敗將會(huì)引起所有等待連接池來獲取連接的線程拋出異常。但是數(shù)據(jù)源仍有效
          保留,并在下次調(diào)用getConnection()的時(shí)候繼續(xù)嘗試獲取連接。如果設(shè)為true,那么在嘗試
          獲取連接失敗后該數(shù)據(jù)源將申明已斷開并永久關(guān)閉。Default: false-->
          <property name="breakAfterAcquireFailure">false</property>

          <!--當(dāng)連接池用完時(shí)客戶端調(diào)用getConnection()后等待獲取新連接的時(shí)間,超時(shí)后將拋出
          SQLException,如設(shè)為0則無限期等待。單位毫秒。Default: 0 -->
          <property name="checkoutTimeout">100</property>

          <!--通過實(shí)現(xiàn)ConnectionTester或QueryConnectionTester的類來測(cè)試連接。類名需制定全路徑。
          Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester-->
          <property name="connectionTesterClassName"></property>

          <!--指定c3p0 libraries的路徑,如果(通常都是這樣)在本地即可獲得那么無需設(shè)置,默認(rèn)null即可
          Default: null-->
          <property name="factoryClassLocation">null</property>

          <!--Strongly disrecommended. Setting this to true may lead to subtle and bizarre bugs.
          (文檔原文)作者強(qiáng)烈建議不使用的一個(gè)屬性-->
          <property name="forceIgnoreUnresolvedTransactions">false</property>

          <!--每60秒檢查所有連接池中的空閑連接。Default: 0 -->
          <property name="idleConnectionTestPeriod">60</property>

          <!--初始化時(shí)獲取三個(gè)連接,取值應(yīng)在minPoolSize與maxPoolSize之間。Default: 3 -->
          <property name="initialPoolSize">3</property>

          <!--最大空閑時(shí)間,60秒內(nèi)未使用則連接被丟棄。若為0則永不丟棄。Default: 0 -->
          <property name="maxIdleTime">60</property>

          <!--連接池中保留的最大連接數(shù)。Default: 15 -->
          <property name="maxPoolSize">15</property>

          <!--JDBC的標(biāo)準(zhǔn)參數(shù),用以控制數(shù)據(jù)源內(nèi)加載的PreparedStatements數(shù)量。但由于預(yù)緩存的statements
          屬于單個(gè)connection而不是整個(gè)連接池。所以設(shè)置這個(gè)參數(shù)需要考慮到多方面的因素。
          如果maxStatements與maxStatementsPerConnection均為0,則緩存被關(guān)閉。Default: 0-->
          <property name="maxStatements">100</property>

          <!--maxStatementsPerConnection定義了連接池內(nèi)單個(gè)連接所擁有的最大緩存statements數(shù)。Default: 0 -->
          <property name="maxStatementsPerConnection"></property>

          <!--c3p0是異步操作的,緩慢的JDBC操作通過幫助進(jìn)程完成。擴(kuò)展這些操作可以有效的提升性能
          通過多線程實(shí)現(xiàn)多個(gè)操作同時(shí)被執(zhí)行。Default: 3-->
          <property name="numHelperThreads">3</property>

          <!--當(dāng)用戶調(diào)用getConnection()時(shí)使root用戶成為去獲取連接的用戶。主要用于連接池連接非c3p0
          的數(shù)據(jù)源時(shí)。Default: null-->
          <property name="overrideDefaultUser">root</property>

          <!--與overrideDefaultUser參數(shù)對(duì)應(yīng)使用的一個(gè)參數(shù)。Default: null-->
          <property name="overrideDefaultPassword">password</property>

          <!--密碼。Default: null-->
          <property name="password"></property>

          <!--定義所有連接測(cè)試都執(zhí)行的測(cè)試語句。在使用連接測(cè)試的情況下這個(gè)一顯著提高測(cè)試速度。注意:
          測(cè)試的表必須在初始數(shù)據(jù)源的時(shí)候就存在。Default: null-->
          <property name="preferredTestQuery">select id from test where id=1</property>

          <!--用戶修改系統(tǒng)配置參數(shù)執(zhí)行前最多等待300秒。Default: 300 -->
          <property name="propertyCycle">300</property>

          <!--因性能消耗大請(qǐng)只在需要的時(shí)候使用它。如果設(shè)為true那么在每個(gè)connection提交的
          時(shí)候都將校驗(yàn)其有效性。建議使用idleConnectionTestPeriod或automaticTestTable
          等方法來提升連接測(cè)試的性能。Default: false -->
          <property name="testConnectionOnCheckout">false</property>

          <!--如果設(shè)為true那么在取得連接的同時(shí)將校驗(yàn)連接的有效性。Default: false -->
          <property name="testConnectionOnCheckin">true</property>

          <!--用戶名。Default: null-->
          <property name="user">root</property>

          <!--早期的c3p0版本對(duì)JDBC接口采用動(dòng)態(tài)反射代理。在早期版本用途廣泛的情況下這個(gè)參數(shù)
          允許用戶恢復(fù)到動(dòng)態(tài)反射代理以解決不穩(wěn)定的故障。最新的非反射代理更快并且已經(jīng)開始
          廣泛的被使用,所以這個(gè)參數(shù)未必有用。現(xiàn)在原先的動(dòng)態(tài)反射與新的非反射代理同時(shí)受到
          支持,但今后可能的版本可能不支持動(dòng)態(tài)反射代理。Default: false-->
          <property name="usesTraditionalReflectiveProxies">false</property>

          <property name="automaticTestTable">con_test</property>
          <property name="checkoutTimeout">30000</property>
          <property name="idleConnectionTestPeriod">30</property>
          <property name="initialPoolSize">10</property>
          <property name="maxIdleTime">30</property>
          <property name="maxPoolSize">25</property>
          <property name="minPoolSize">10</property>
          <property name="maxStatements">0</property>
          <user-overrides user="swaldman">
          </user-overrides>
          </default-config>
          <named-config name="dumbTestConfig">
          <property name="maxStatements">200</property>
          <user-overrides user="poop">
          <property name="maxStatements">300</property>
          </user-overrides>
          </named-config>
          </c3p0-config>

          posted @ 2008-01-18 11:58 菠蘿 閱讀(246) | 評(píng)論 (0)編輯 收藏

          主站蜘蛛池模板: 凤城市| 贵溪市| 运城市| 韶关市| 襄汾县| 渭源县| 中山市| 于田县| 东安县| 乌鲁木齐县| 黄大仙区| 宁南县| 遂宁市| 石嘴山市| 桑日县| 南华县| 昌平区| 微博| 镶黄旗| 锡林浩特市| 蒲江县| 宁远县| 抚州市| 繁昌县| 香河县| 门头沟区| 宁强县| 会泽县| 建平县| 屏东县| 颍上县| 鲜城| 西林县| 扎兰屯市| 马山县| 高清| 天津市| 濉溪县| 五莲县| 新郑市| 新津县|