<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    菠蘿三國

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

    2008年1月14日

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

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

    instsrv.exe  srvany.exe

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

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

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

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

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

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\servername

    中簡歷Parameters子項,然后在其中建立一個字符串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)入,之后選擇“登陸”,再選中“本地登陸”并確定。之后手動啟動服務(wù)即可。

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

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

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

    翻譯類字典詞典

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

    XP/2003訪問XP的用戶驗證問題


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

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

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

         摘要:   閱讀全文

    posted @ 2008-01-30 09:27 菠蘿 閱讀(2153) | 評論 (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("請輸入RSS地址");
            }
        else
            {
                readRSS(url);
                }
        }

    </script>
    </head>

    <body">
      <h1>ajax讀rss示例</h1>
      <form >
          
      <a href="javascript:readRSS('http://m.tkk7.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>
         輸入一個RSS地址:<input type="text" value="
    http://m.tkk7.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 菠蘿 閱讀(354) | 評論 (0)編輯 收藏

    Session機(jī)制

    摘要:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    下面就是一個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這個HTTP Sniffer軟件來俘獲的HTTP通訊紀(jì)錄的一部分

    image
    瀏覽器在再次訪問goolge的資源時自動向外發(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)程序需要為某個客戶端的請求創(chuàng)建一個session的時候,服務(wù)器首先檢查這個客戶端的請求里是否已包含了一個session標(biāo)識 - 稱為 session id,如果已包含一個session id則說明以前已經(jīng)為此客戶端創(chuàng)建過session,服務(wù)器就按照session id把這個 session檢索出來使用(如果檢索不到,可能會新建一個),如果客戶端請求不包含session id,則為此客戶端創(chuàng)建一個session并且生成一個與此session相關(guān)聯(lián)的session id,session id的值應(yīng)該是一個既不會重復(fù),又不容易被找到規(guī)律以仿造的字符串,這個 session id將被在本次響應(yīng)中返回給客戶端保存。

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

    由于cookie可以被人為的禁止,必須有其他機(jī)制以便在cookie被禁止時仍然能夠把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
    這兩種方式對于用戶來說是沒有區(qū)別的,只是服務(wù)器在解析的時候處理的方式不同,采用第一種方式也有利于把session id的信息和正常程序參數(shù)區(qū)分開來。
    為了在整個交互過程中始終保持狀態(tài),就必須在每個客戶端可能請求的路徑后面都包含這個session id。

    另一種技術(shù)叫做表單隱藏字段。就是服務(wù)器會自動修改表單,添加一個隱藏字段,以便在表單提交時能夠把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ù)可以簡單的用對action應(yīng)用URL重寫來代替。

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

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

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

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

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

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

    cookie生存時間的設(shè)置則會影響瀏覽器生成的cookie是否是一個會話cookie。默認(rèn)是使用會話cookie。有興趣的可以用它來試驗我們在第四節(jié)里提到的那個誤解。

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

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

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

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

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

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

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

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

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

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

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

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

    9、為什么在Weblogic Server中改變session的值后要重新調(diào)用一次session.setValue
    做這個動作主要是為了在集群環(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處理上也有可能會出現(xiàn)問題。
    出現(xiàn)這一問題的大部分原因都是程序的錯誤,最常見的就是在一個應(yīng)用程序中去訪問另外一個應(yīng)用程序。我們在下一節(jié)討論這個問題。

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

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

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

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

    image
    image

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

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

    iPlanet中有一種很簡單的方法來實現(xiàn)共享一個session id,那就是把各個應(yīng)用程序的cookie路徑都設(shè)為/(實際上應(yīng)該是/NASApp,對于應(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。對于版本4以上的Tomcat,目前筆者尚未發(fā)現(xiàn)簡單的辦法。只能借助于第三方的力量,比如使用文件、數(shù)據(jù)庫、JMS或者客戶端cookie,URL參數(shù)或者隱藏字段等手段。

    我們再看一下Weblogic Server是如何處理session的。
    image
    image

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

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

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


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


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

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

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

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

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

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

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

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

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


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

    新建一工程,引入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方法,并打印到控制臺中。

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

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

     // 使用默認(rèn)的委托父 ClassLoader 為指定的 URL 構(gòu)造一個新 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時,將當(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時,是使用系統(tǒng)類加載器來加載class的,所以在web環(huán)境下,就會出錯。這是因為JVM中一個類用其全名和一個加載類ClassLoader的實例作為唯一標(biāo)識的。我們只要利用URLClassLoader的第二種構(gòu)造方法并傳入當(dāng)前線程類加載器即可解決。

    posted @ 2008-01-26 09:51 菠蘿 閱讀(457) | 評論 (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的變動
    5.源代碼
    ---------------------------------------------------------------------------

    第一章 介紹

    什么是 ClassLoader

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

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

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

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

    為什么編寫 ClassLoader?

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

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

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

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

    定制 ClassLoader 示例

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

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

    此項功能歸功于 Java 語言可以安裝定制 ClassLoader。Applet 查看器包含一個 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 是一個開放源碼包,它可以使您在單個虛擬機(jī)上運(yùn)行多個 Java 應(yīng)用程序。(請參閱進(jìn)一步了解和參考資料。)它使用定制的 ClassLoader,通過向每個應(yīng)用程序提供該類文件的自身副本,以防止應(yīng)用程序互相干擾。


    我們的 ClassLoader 示例

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

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

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

     


     

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

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



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

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

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

    在下一章中,您將會利用這些知識來使用我們的 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 時唯一需要覆蓋的方法。(Java 2 中 ClassLoader 的變動提供了關(guān)于 Java 1.2 中 findClass() 方法的信息。)


    方法 defineClass

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

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


    方法 findSystemClass

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

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

    其工作流程如下:

     

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

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


    方法 resolveClass

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

    方法 findLoadedClass

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

    組裝

     

     

     

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

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

     

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

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

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

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

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

    • 如果還沒有類,返回 ClassNotFoundException

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

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

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

    第三章:Compiling ClassLoader

    CCL 揭密

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

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

     

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

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

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

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

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

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

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

     

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

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

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

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

    使用 CompilationClassLoader

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

     

    % java Foo arg1 arg2

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

     

    % java CCLRun Foo arg1 arg2

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

    運(yùn)行示例

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

    每個類都聲明已被裝入并運(yùn)行。現(xiàn)在用源代碼來試一下。編譯 CCLRun 和 CompilingClassLoader。確保不要編譯其它類(FooBarBazBoo),否則將不會使用 CCL,因為這些類已經(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!

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

     

     

     

     

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

    第四章:java2 中ClassLoader的變動


    概述

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

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

    loadClass 的缺省實現(xiàn)

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

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

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

    新方法:findClass

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

    新方法:getSystemClassLoader

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

    新方法:getParent

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

    父代 ClassLoader 被定義成創(chuàng)建該 ClassLoader 所包含代碼的對象的 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 菠蘿 閱讀(325) | 評論 (0)編輯 收藏

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

    安裝WebLogic8.1
    安裝WebLogic比較容易,在這里就不再累述了,大家可以參閱相關(guān)文檔。現(xiàn)在著重講一下WebLogic的配置,因為后面在配置MyEclipse時將用到這里的有關(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,以下兩個Port均采用默認(rèn)值,下一步。
    (6)選擇Skip跳過Multiple Servers,Clusters,and Machines Options,下一步。
    (7)選擇Skip跳過JDBC連接池的配置(注:JDBC連接池的配置可以在啟動WebLogic后到控制臺上進(jìn)行,大家可以參閱相關(guān)文檔),下一步。
    (選擇Skip跳過JMS的配置(同樣留到控制臺上做),下一步。
    (9)繼續(xù)跳過,下一步。
    (10)選擇Yes,下一步。
    (11)在User頁點(diǎn)擊Add,隨意添加一個用戶user,密碼12345678,下一步。
    (12)將用戶user分配到Administrators組(還可以同時分配到其它組,方法是選中待加入的組,然后勾中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對話框。
    5.配置MyEclipse的WebLogic服務(wù)器
    MyEclipse默認(rèn)的應(yīng)用服務(wù)器為JBoss3,這里我們使用WebLogic8.1。啟動Eclipse,選擇“窗口\首選項”菜單,打開首選項對話框。展開MyEclipse下的Application Servers結(jié)點(diǎn),點(diǎn)擊JBoss 3,選中右面的Disable單選按鈕,停用JBoss 3。然后點(diǎn)擊WebLogic 8,選中右邊的Enable單選按鈕,啟用WebLogic服務(wù)器。同時下面的配置如下:
    (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對話框,在JRE名稱處隨便輸入一個名字,如jre1.4.1_02。然后在JRE主目錄處選擇WebLogic安裝文件夾中的JDK文件夾,如D:\BEA\jdk141_02,程序會自動填充Javadoc URL文本框和JRE系統(tǒng)庫列表框。單擊確定按鈕關(guān)閉對話框。這時候就可以在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ū)動類庫加進(jìn)來,這里我們用WebLogic自帶的SQL Server數(shù)據(jù)庫驅(qū)動庫D:\BEA\weblogic81\server\lib\mssqlserver4v65.jar。
    至此,MyEclipse中WebLogic8的配置工作就算完成了。下面可以看看在Eclipse中能否啟動WebLogic了?自從安裝了MyEclipse之后,Eclipse工具欄中就會有一個Run/Stop Servers下拉按鈕。點(diǎn)擊該按鈕的下拉部分,選擇“WebLogic 8\Start”菜單,即開始啟動WebLogic了。通過查看下面的控制臺消息,就可以知道啟動是否成功,或有什么異常發(fā)生。停止WebLogic可選擇“WebLogic\Stop”菜單。 

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

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

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

      概述

      J2EE開發(fā)人員經(jīng)常需要管理WebLogic Server并調(diào)試WebLogic Server上部署的應(yīng)用程序。 WebLogic Server管理控制臺雖然能夠啟動和停止WebLogic Server,卻不能設(shè)置JVM選項和服務(wù)器類路徑。必須使用startWebLogic腳本來設(shè)置JVM選項和服務(wù)器類路徑。而要調(diào)試WebLogic Server上部署的應(yīng)用程序,則需要帶遠(yuǎn)程調(diào)試器的IDE.有了WebLogic插件后,就可以通過Eclipse IDE管理WebLogic Server. 在文本中,我們將開發(fā)一個包括會話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工作臺完成插件安裝。現(xiàn)在WebLogic-Eclipse插件便安裝在 Eclipse IDE中了。Eclipse中新添了Run>Start WebLogic和Run>Stop WebLogic兩個功能。

      配置WebLogic-Eclipse插件

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

      為項目添加J2EE 1.4 j2ee.jar文件。1.4 j2ee.jar將在項目庫中列出。單擊Finish按鈕完成項目配置。這樣便將一個項目添加到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文件,請選擇WebLogic>Classpath節(jié)點(diǎn)。可以在添加WebLogic庫之前或之后添加JAR/Zip文件或目錄。選擇WebLogic>JavaVM Options節(jié)點(diǎn)指定JavaVM選項。例如,修改weblogic.ProductionModeEnabled屬性。將屬性值設(shè)置為false可使用開發(fā)模式啟動服務(wù)器。單擊Apply按鈕應(yīng)用JavaVM選項。

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

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

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

      配置了WebLogic插件后,將開發(fā)一個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項目EclipseWebLogic中,選擇File>Import導(dǎo)入J2EE應(yīng)用程序的src目錄。在Import窗體中,選擇File System節(jié)點(diǎn),然后單擊Next按鈕。在File system窗體中,選擇directories/files添加項目,然后單擊Finish按鈕(見圖1)。

    配置WebLogic-Eclipse插件 圖-1

      圖1

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

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

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

      替換為:

      String str=null;

      out.println(str.toString());

      選擇Run>Add Java Exception Breakpoint向servlet添加一個斷點(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)。因為servlet帶有異常,所以服務(wù)器被中斷,并且Debug perspective顯示NullPointerException.使用Run菜單項中的調(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 菠蘿 閱讀(451) | 評論 (0)編輯 收藏

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

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

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

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

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

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

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

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

    <!--通過實現(xiàn)ConnectionTester或QueryConnectionTester的類來測試連接。類名需制定全路徑。
    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)烈建議不使用的一個屬性-->
    <property name="forceIgnoreUnresolvedTransactions">false</property>

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

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

    <!--最大空閑時間,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
    屬于單個connection而不是整個連接池。所以設(shè)置這個參數(shù)需要考慮到多方面的因素。
    如果maxStatements與maxStatementsPerConnection均為0,則緩存被關(guān)閉。Default: 0-->
    <property name="maxStatements">100</property>

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

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

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

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

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

    <!--定義所有連接測試都執(zhí)行的測試語句。在使用連接測試的情況下這個一顯著提高測試速度。注意:
    測試的表必須在初始數(shù)據(jù)源的時候就存在。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>

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

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

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

    <!--早期的c3p0版本對JDBC接口采用動態(tài)反射代理。在早期版本用途廣泛的情況下這個參數(shù)
    允許用戶恢復(fù)到動態(tài)反射代理以解決不穩(wěn)定的故障。最新的非反射代理更快并且已經(jīng)開始
    廣泛的被使用,所以這個參數(shù)未必有用。現(xiàn)在原先的動態(tài)反射與新的非反射代理同時受到
    支持,但今后可能的版本可能不支持動態(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 菠蘿 閱讀(242) | 評論 (0)編輯 收藏

    修改jfreechart中的默認(rèn)字體

    生成圖表后自動生成chart表的問題:

    我測試生成圖表中的中文問題都解決了,但是每次生成chart圖時會報UTF編碼錯誤,從錯誤判斷應(yīng)該是某個文件的編碼錯誤,起初根據(jù)錯誤判斷是filter的問題,可是filter那點(diǎn)代碼中根本不涉及編碼的問題.我將很多配置文件的編碼都改了也不行.因為那個英文例子沒問題,我查看了JFreechart的一個servlet(org.jfree.chart.servlet.DisplayChart),因為jpviot就是調(diào)用這個servlet實現(xiàn)繪圖的,分析這個servlet我知道它會在一個臨時目錄生成png文件,然后交給servlet寫到瀏覽器的響應(yīng)中去,我找到那個臨時目錄(tomcattemp),發(fā)現(xiàn)里面已經(jīng)生成了正確的中文圖形.從而判斷圖形生成正確,但是寫到瀏覽器中時出了問題.最后我查看能生成英文圖表的那個例子,發(fā)覺不僅僅在html中生成圖形,而且生成map.而這個map的生成全是在程序中做的,程序生成一個xml文件,通過chart.xsl解析生成map的最終html代碼.但是在程序中生成時并沒有加入編碼設(shè)置,因此問題出在生成map這兒.

    最終修改代碼如下:

    com.tonbeller.jpivot.chart.ChartComponent:

    在render函數(shù)中修改如下:

    String desc="<?xml version="1.0" encoding="gb2312"?>";
    String xchart =desc+"n"+ "<xchart>" + writeImageMap(filename, info, false) + "</xchart>";
    這樣就為xchart設(shè)置了編碼.

    修改jfreechart中的默認(rèn)字體:

    com.tonbeller.jpivot.chart.ChartComponent中定義了幾種字體,但是這幾種字體都是英文字體,我將其修改為宋體:
    把所有的字體定義都改為"SimSun"
    注意到這兒并沒有玩,如果你僅僅修改程序,仍舊會出現(xiàn)問題,報錯說沒有適合"SimSun"的item
    同時要修改一個配置文件:WEB-INFjpivotchartchartpropertiesform.xml
    在這個配置文件中將SimSun加入其中,形式如下:

    <listBox1 type="string" modelReference="fontName" label="Title font">
    <listItem value="SansSerif" label="SansSerif"/>
    <listItem value="Serif" label="Serif"/>
    <listItem value="SimSun" label="SimSun"/>
    <listItem value="Monospaced" label="Monospaced"/>
    </listBox1>

    posted @ 2008-01-14 12:20 菠蘿 閱讀(1250) | 評論 (0)編輯 收藏

    jfreechart在aix unix上的中文顯示問題

     

     

    今天開始搭建新的平臺,要把原來windows的應(yīng)用遷移到Aix上,結(jié)果由于jfreechart的中文字體顯示耗了整個下午,好不郁悶,不過還好最后解決問題了:)
         
    主機(jī)環(huán)境:
     AIX Version 5.2 + Jboss4.03sp1 + J2RE 1.4.2 IBM AIX build ca142ifx-20050119
     使用jfreechart1.0rc

    添加啟動參數(shù) -Djava.awt.headless=true才能正常顯示jfreechart的圖.

    讓jre使用中文字體的過程如下:

    1.解包字體文件
    TrueType_zhCN_GBK.tar,列表如下:
    fangsongti.ttf
    heiti.ttf
    kaiti.ttf
    songti.ttf
    注:字體包是我以前在solaris上整出來的.

    2.copy字體到j(luò)re的字體目錄${JAVA_HOME}/jre/lib/fonts


    3.修改JRE的字體配置
    3.1 修改fonts.scale文件[${JAVA_HOME}/jre/lib/fonts/fonts.scale]
    把一行的數(shù)字加4
    在文件尾添加
    fangsongti.ttf -zhongyi-fangsong-medium-r-normal--0-0-0-0-m-0-gbk-0
    heiti.ttf -zhongyi-hei-medium-r-normal--0-0-0-0-m-0-gbk-0
    kaiti.ttf -zhongyi-kai-medium-r-normal--0-0-0-0-m-0-gbk-0
    songti.ttf -zhongyi-song-medium-r-normal--0-0-0-0-m-0-gbk-0
    3.2 修改fonts.dir文件[${JAVA_HOME}/jre/lib/fonts/fonts.dir]
    把一行的數(shù)字加4
    在文件尾添加
    fangsongti.ttf -zhongyi-fangsong-medium-r-normal--0-0-0-0-m-0-gbk-0
    heiti.ttf -zhongyi-hei-medium-r-normal--0-0-0-0-m-0-gbk-0
    kaiti.ttf -zhongyi-kai-medium-r-normal--0-0-0-0-m-0-gbk-0
    songti.ttf -zhongyi-song-medium-r-normal--0-0-0-0-m-0-gbk-0
    3.3 修改font.properties.zh文件[${JAVA_HOME}/jre/lib/font.properties.zh]
    把所有的serif.1的值 進(jìn)行如下替換
    -zhongyi-song-medium-r-normal--0-0-0-0-m-0-gbk-0


    4.重新啟動就可以了.

     

    其他的unix上我試了一下hp-unix,可以通過,其他的沒有試過,或許也可以吧:)

    posted @ 2008-01-14 12:18 菠蘿 閱讀(1119) | 評論 (9)編輯 收藏

    修改字體

    //X軸下標(biāo)字體大小及顏色
    Axis axis1 = plot.getDomainAxis();
    axis1.setLabelFont(new Font("sansserf",Font.PLAIN,30));//字體
    axis1.setLabelPaint(Color.white);//顏色
     
    //X軸的字體顏色
    Axis axis = plot.getDomainAxis();
    axis.setTickLabelFont(new Font("Serif", Font.PLAIN,25));//字體
    axis.setTickLabelPaint(Color.white);//顏色 
     
    //Y軸字下標(biāo)字體大小及顏色
    Axis axis2 = plot.getRangeAxis();
    axis2.setLabelFont(new Font("Serif", Font.PLAIN, 30));//字體  
    axis2.setLabelPaint(Color.white); //顏色
     
    //Y軸字體及顏色
    Axis axis3 = plot.getRangeAxis();
    axis3.setTickLabelFont(new Font("Serif", Font.PLAIN, 25));//字體  
    axis3.setTickLabelPaint(Color.white);//顏色
    

    posted @ 2008-01-14 12:10 菠蘿 閱讀(247) | 評論 (0)編輯 收藏

    主站蜘蛛池模板: 亚洲午夜在线一区| 亚洲AV无码久久精品蜜桃| 亚洲第一区精品观看| 2022中文字字幕久亚洲| 婷婷久久久亚洲欧洲日产国码AV | 日韩视频在线免费观看| 免费一看一级毛片| 亚洲精品乱码久久久久久自慰| 亚洲电影一区二区三区| 色在线亚洲视频www| 免费激情网站国产高清第一页 | 一级毛片aaaaaa免费看| 成人激情免费视频| 国产L精品国产亚洲区久久| 2022年亚洲午夜一区二区福利| 成人亚洲国产va天堂| 一个人免费播放在线视频看片| 91福利免费体验区观看区| 日本不卡高清中文字幕免费| 国产亚洲精久久久久久无码AV| 亚洲欧洲日产国码在线观看| 亚洲AV无码成人网站在线观看| 女同免费毛片在线播放| 成人免费视频77777| 国产精品亚洲视频| 亚洲免费在线视频观看| 成人免费观看男女羞羞视频| 18pao国产成视频永久免费| 全亚洲最新黄色特级网站| 男人j进入女人j内部免费网站 | 国国内清清草原免费视频99| 亚洲国产成人精品女人久久久| 亚洲综合一区二区精品导航| 欧美亚洲国产SUV| 免费人成在线观看网站品爱网| 国产成人免费片在线观看| 中文字幕亚洲综合久久| 日本高清不卡中文字幕免费| 日韩国产免费一区二区三区| 国产亚洲精品高清在线| 亚洲人成色在线观看|