ï»??xml version="1.0" encoding="utf-8" standalone="yes"?>图片区小说区国产精品视频,头脑特工队2在线播放,91涩漫在线观看http://www.aygfsteel.com/boluobn/大江东去,‹¹ªæ·˜ž®?..zh-cnWed, 18 Jun 2025 17:58:44 GMTWed, 18 Jun 2025 17:58:44 GMT60用instsrv与srvany在windows 建立服务http://www.aygfsteel.com/boluobn/archive/2009/04/19/266420.html菠萝菠萝Sun, 19 Apr 2009 06:44:00 GMThttp://www.aygfsteel.com/boluobn/archive/2009/04/19/266420.htmlhttp://www.aygfsteel.com/boluobn/comments/266420.htmlhttp://www.aygfsteel.com/boluobn/archive/2009/04/19/266420.html#Feedback0http://www.aygfsteel.com/boluobn/comments/commentRss/266420.htmlhttp://www.aygfsteel.com/boluobn/services/trackbacks/266420.html用instsrv与srvany在windows 建立服务

instsrv.exe  srvany.exe

˜q™ä¸¤ä¸ªæ–‡ä»¶æ˜¯MS扚w‡ç”Ÿäñ”的,¾|‘上应该能烂下蝲ã€?/p>

首先ž®†è¿™ä¸¤ä¸ªæ–‡äšg攑ֈ°è‡ªå®šçš„èµ\径中。例如放在C:\根目录下

在CMD对话框中输入 c:\instsrv.exe  servername c:\ srvany.exe 回èžR

其中servername是你所需要的服务名�/p>

之后你需要进入注册表˜q›è¡Œç›¸åº”的设¾|®ï¼Œåœ¨æ³¨å†Œè¡¨çš„:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\servername

中简历Parameters子项åQŒç„¶åŽåœ¨å…¶ä¸­å»ºç«‹ä¸€ä¸ªå­—½W¦ä¸²ApplicationåQŒåŒå‡»è¯¥å­—符ä¸ÔŒ¼Œè¾“入如下格式的语句:

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

其中çš?56M与服务占用内存大ž®æœ‰å…»I¼Œ˜q™å°±è¦çœ‹æœºå™¨çš„配¾|®äº†ã€?/p>

修改¾l“束后推出,使用命ä×oservices.msc˜q›å…¥æœåŠ¡ç•Œé¢åQŒæ‰¾åˆîC½ åˆšåˆšå®šåˆ¶çš„æœåŠ¡ï¼ŒåŒå‡»˜q›å…¥åQŒä¹‹åŽé€‰æ‹©“登陆”åQŒå†é€‰ä¸­“本地登陆”òq¶ç¡®å®šã€‚之后手动启动服务即可ã€?br />
C:\service\instsrv.exe adslSrv "C:\service\srvany.exe"



菠萝 2009-04-19 14:44 发表评论
]]>
¾|‘上在线字典词典大全http://www.aygfsteel.com/boluobn/archive/2008/04/07/191226.html菠萝菠萝Mon, 07 Apr 2008 04:26:00 GMThttp://www.aygfsteel.com/boluobn/archive/2008/04/07/191226.htmlhttp://www.aygfsteel.com/boluobn/comments/191226.htmlhttp://www.aygfsteel.com/boluobn/archive/2008/04/07/191226.html#Feedback0http://www.aygfsteel.com/boluobn/comments/commentRss/191226.htmlhttp://www.aygfsteel.com/boluobn/services/trackbacks/191226.html¾˜»è¯‘¾cÕd­—典词å…?

]]>
XP/2003讉K—®XP的用户验证问é¢? http://www.aygfsteel.com/boluobn/archive/2008/03/07/184590.html菠萝菠萝Fri, 07 Mar 2008 12:43:00 GMThttp://www.aygfsteel.com/boluobn/archive/2008/03/07/184590.htmlhttp://www.aygfsteel.com/boluobn/comments/184590.htmlhttp://www.aygfsteel.com/boluobn/archive/2008/03/07/184590.html#Feedback0http://www.aygfsteel.com/boluobn/comments/commentRss/184590.htmlhttp://www.aygfsteel.com/boluobn/services/trackbacks/184590.html   首先关于启用Guestä¸ÞZ»€ä¹ˆä¸èƒ½è®¿é—®çš„问题åQ? 
   
  1、默认情况下åQŒXP   ¼›ç”¨Guest帐户  
  2、默认情况下åQŒXP的本地安全策略禁止Guest用户从网¾lœè®¿é—? 
  3、默认情况下åQŒXPçš?  本地安全½{–ç•¥   ->   安全选项   里,"帐户åQšä‹É用空密码用户只能˜q›è¡ŒæŽ§åˆ¶å°ç™»é™?是启用的åQŒä¹Ÿž®±æ˜¯è¯ß_¼Œ½Iºå¯†ç çš„ä»ÖM½•帐户都不能从¾|‘络讉K—®åªèƒ½æœ¬åœ°ç™»é™†åQŒGuest默认½Iºå¯†ç ?.....  
   
  所以,如果需要ä‹É用Guest用户讉K—®XP的话åQŒè¦˜q›è¡Œä¸Šé¢çš„三个设¾|®ï¼šå¯ç”¨Guest、修改安全策略允许Guest从网¾lœè®¿é—®ã€ç¦ç”?里面的安全策略或者给Guest加个密码ã€? 
   
  有时˜q˜ä¼šé‡åˆ°å¦å¤–一¿Uæƒ…况:讉K—®XP的时候,ç™Õd½•对话框中的用户名是灰çš?始终是Guest用户åQŒä¸èƒ½è¾“入别的用户帐受÷€? 
   
  原因是这个安全策略在作怪。默认情况下åQŒXP的访问方式是"仅来å®?的方式,那么你访问它åQŒå½“然就固定为Guest不能输入其他用户帐号了ã€? 
   
  所以,讉K—®XP最½Ž€å•çš„æ–ÒŽ³•ž®±æ˜¯åQšä¸ç”¨å¯ç”¨GueståQŒä»…ä¿®æ”¹ä¸Šé¢çš„å®‰å…¨ç­–ç•¥äØ“"¾lå…¸"ž®Þp¡Œäº†ã€‚别的系¾lŸè®¿é—®XPž®±å¯ä»¥è‡ªå·Þp¾“入帐户信息ã€? 
   
  至于讉K—®2003åQŒé»˜è®¤æƒ…况下2003¼›ç”¨GueståQŒä½†æ˜¯æ²¡æœ?  XP   那个讨厌的默认自相矛盄¡š„来宾方式å…׃ínåQŒæ‰€ä»¥å¯ä»¥ç›´æŽ¥è¾“入用户名密码讉K—®ã€?

]]>
RSS的格式及解释(�http://www.aygfsteel.com/boluobn/archive/2008/01/30/178454.html菠萝菠萝Wed, 30 Jan 2008 01:27:00 GMThttp://www.aygfsteel.com/boluobn/archive/2008/01/30/178454.htmlhttp://www.aygfsteel.com/boluobn/comments/178454.htmlhttp://www.aygfsteel.com/boluobn/archive/2008/01/30/178454.html#Feedback1http://www.aygfsteel.com/boluobn/comments/commentRss/178454.htmlhttp://www.aygfsteel.com/boluobn/services/trackbacks/178454.html阅读全文

]]>
AJAXè¯Õd–rss的代ç ?è½?http://www.aygfsteel.com/boluobn/archive/2008/01/29/178418.html菠萝菠萝Tue, 29 Jan 2008 14:49:00 GMThttp://www.aygfsteel.com/boluobn/archive/2008/01/29/178418.htmlhttp://www.aygfsteel.com/boluobn/comments/178418.htmlhttp://www.aygfsteel.com/boluobn/archive/2008/01/29/178418.html#Feedback0http://www.aygfsteel.com/boluobn/comments/commentRss/178418.htmlhttp://www.aygfsteel.com/boluobn/services/trackbacks/178418.html 
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½CÞZ¾‹</h1>
  <form >
      
  <a href="javascript:readRSS('http://www.aygfsteel.com/rss.aspx')">blogjava原创åŒ?nbsp;</a>&nbsp     
   <a href="javascript:readRSS('http://beginner.blogjava.net/rss.aspx')">blogjava新手åŒ?nbsp;</a> &nbsp 
    <a href="javascript:readRSS('http://life.blogjava.net/rss.aspx')">blogjava非技术区 </a> &nbsp 
     <a href="javascript:readRSS('http://general.blogjava.net/rss.aspx')">¾l¼åˆåŒ?nbsp;</a>
     <br>
     è¾“入一个RSS地址:<input type="text" value="
http://www.aygfsteel.com/wujun/rss.aspx" size=50 id="txturl">
     <input type="button" value="æŸ?nbsp;çœ? onclick="readrss1()">
     
  </form>
    <div id="result"></div>
</body>
</html>



]]>
Session机制http://www.aygfsteel.com/boluobn/archive/2008/01/26/177873.html菠萝菠萝Sat, 26 Jan 2008 01:53:00 GMThttp://www.aygfsteel.com/boluobn/archive/2008/01/26/177873.htmlhttp://www.aygfsteel.com/boluobn/comments/177873.htmlhttp://www.aygfsteel.com/boluobn/archive/2008/01/26/177873.html#Feedback0http://www.aygfsteel.com/boluobn/comments/commentRss/177873.htmlhttp://www.aygfsteel.com/boluobn/services/trackbacks/177873.html

摘要:

虽然session机制在web应用½E‹åºä¸­è¢«é‡‡ç”¨å·²ç»å¾ˆé•¿æ—‰™—´äº†ï¼Œä½†æ˜¯ä»ç„¶æœ‰å¾ˆå¤šäh不清楚session机制的本质,以至不能正确的应用这一技术。本文将详细讨论sessionçš„å·¥ä½œæœºåˆ¶åÆˆä¸”å¯¹åœ¨Java web application中应用session机制时常见的问题作出解答ã€?/div>
 
一、术语session
在我的经验里åQŒsession˜q™ä¸ªè¯è¢«æ»¥ç”¨çš„程度大概仅‹Æ¡äºŽtransactionåQŒæ›´åŠ æœ‰­‘£çš„æ˜¯transaction与session在某些语境下的含义是相同的ã€?br />
sessionåQŒä¸­æ–‡ç»å¸¸ç¿»è¯‘äØ“ä¼šè¯åQŒå…¶æœ¬æ¥çš„含义是指有始有¾lˆçš„一¾pÕdˆ—动作/消息åQŒæ¯”如打电话时从拿è“v电话拨号到挂断电话这中间的一¾pÕdˆ—˜q‡ç¨‹å¯ä»¥¿UîC¹‹ä¸ÞZ¸€ä¸?session。有时候我们可以看到这æ ïLš„è¯?#8220;在一个浏览器会话期间åQ?..”åQŒè¿™é‡Œçš„会话一词用的就是其本义åQŒæ˜¯æŒ‡ä»Žä¸€ä¸ªæµè§ˆå™¨½H—口打开到关闭这个期é—?â‘ ã€‚æœ€æ··äØ•çš„æ˜¯“用户åQˆå®¢æˆïL«¯åQ‰åœ¨ä¸€‹Æ¡ä¼šè¯æœŸé—?#8221;˜q™æ ·ä¸€å¥è¯åQŒå®ƒå¯èƒ½æŒ‡ç”¨æˆïLš„一¾pÕdˆ—动作åQˆä¸€èˆ¬æƒ…况下是同某个具体目的相关的一¾pÕdˆ—动作åQŒæ¯”如从ç™Õd½•åˆ°é€‰è´­å•†å“åˆ°ç»“è´¦ç™»å‡ø™¿™æ ·ä¸€ä¸ªç½‘上购物的˜q‡ç¨‹åQŒæœ‰æ—¶å€™ä¹Ÿè¢«ç§°ä¸ÞZ¸€ä¸ªtransactionåQ‰ï¼Œç„¶è€Œæœ‰æ—¶å€™ä¹Ÿå¯èƒ½ä»…仅是指一‹Æ¡è¿žæŽ¥ï¼Œä¹Ÿæœ‰å¯èƒ½æ˜¯æŒ‡å«ä¹‰â‘ ï¼Œå…¶ä¸­çš„差别只能靠上下文来推断②ã€?br />
然而当session一词与¾|‘络协议相关联时åQŒå®ƒåˆå¾€å¾€éšå«äº?#8220;面向˜qžæŽ¥”å’?æˆ?#8220;保持状æ€?#8221;˜q™æ ·ä¸¤ä¸ªå«ä¹‰åQ?“面向˜qžæŽ¥”指的是在通信双方在通信之前要先建立一个通信的渠道,比如打电话,直到å¯ÒŽ–¹æŽ¥äº†ç”µè¯é€šä¿¡æ‰èƒ½å¼€å§‹ï¼Œä¸Žæ­¤ç›¸å¯¹çš„æ˜¯å†™ä¿¡åQŒåœ¨ä½ æŠŠä¿¡å‘出去的时候你òq¶ä¸èƒ½ç¡®è®¤å¯¹æ–¹çš„地址是否正确åQŒé€šä¿¡æ¸ é“不一定能建立åQŒä½†å¯¹å‘ä¿¡äh来说åQŒé€šä¿¡å·²ç»å¼€å§‹äº†ã€?#8220;保持状æ€?#8221;则是指通信的一方能够把一¾pÕdˆ—的消息关联è“v来,使得消息之间可以互相依赖åQŒæ¯”如一个服务员能够认出再次光äÍçš„è€é¡¾å®¢åÆˆä¸”è®°å¾—ä¸Š‹Æ¡è¿™ä¸ªé¡¾å®¢è¿˜‹Æ åº—里一块钱。这一¾cȝš„例子æœ?#8220;一个TCP session”或è€?“一个POP3 session”â‘¢ã€?br />
而到了web服务器蓬勃发展的时代åQŒsession在web开发语境下的语义又有了新的扩展åQŒå®ƒçš„含义是指一¾cȝ”¨æ¥åœ¨å®¢æˆ·ç«¯ä¸ŽæœåŠ¡å™¨ä¹‹é—´ä¿æŒçŠ¶æ€çš„è§£å†³æ–ÒŽ¡ˆâ‘£ã€‚有时候session也用来指˜q™ç§è§£å†³æ–ÒŽ¡ˆçš„存储结构,å¦?#8220;把xxx保存在session é‡?#8221;⑤。由于各¿Uç”¨äºŽweb开发的语言在一定程度上都提供了对这¿Uè§£å†Ïx–¹æ¡ˆçš„æ”¯æŒåQŒæ‰€ä»¥åœ¨æŸç§ç‰¹å®šè¯­è¨€çš„语境下åQŒsession也被用来指代该语­a€çš„è§£å†Ïx–¹æ¡ˆï¼Œæ¯”如¾lå¸¸æŠŠJava里提供的javax.servlet.http.HttpSession½Ž€¿UîCØ“sessionâ‘¥ã€?br />
鉴于˜q™ç§æ··äؕ已不可改变,本文中session一词的˜qç”¨ä¹Ÿä¼šæ ÒŽ®ä¸Šä¸‹æ–‡æœ‰ä¸åŒçš„含义,请大家注意分辨ã€?br /> 在本文中åQŒä‹É用中æ–?#8220;‹¹è§ˆå™¨ä¼šè¯æœŸé—?#8221;来表辑֐«ä¹‰â‘ åQŒä‹Éç”?#8220;session机制”来表辑֐«ä¹‰â‘£åQŒä‹Éç”?#8220;session”表达含义⑤,使用具体çš?#8220;HttpSession”来表辑֐«ä¹‰â‘¥

二、HTTP协议与状态保�/strong>
HTTP 协议本èín是无状态的åQŒè¿™ä¸ŽHTTP协议本来的目的是相符的,客户端只需要简单的向服务器è¯äh±‚下蝲某些文äšgåQŒæ— è®ºæ˜¯å®¢æˆ·ç«¯è¿˜æ˜¯æœåŠ¡å™¨éƒ½æ²¡æœ‰å¿…è¦çºªå½•å½¼æ­¤è¿‡åŽÈš„è¡ŒäØ“åQŒæ¯ä¸€‹Æ¡è¯·æ±‚之间都是独立的åQŒå¥½æ¯”一个顾客和一个自动售货机或者一个普通的åQˆéžä¼šå‘˜åˆÓž¼‰å¤§å–åœÞZ¹‹é—´çš„关系一栗÷€?br />
然而聪明(或者贪心?åQ‰çš„äºÞZ»¬å¾ˆå¿«å‘现如果能够提供一些按需生成的动态信息会使web变得更加有用åQŒå°±åƒç»™æœ‰çº¿ç”µè§†åŠ ä¸Šç‚ÒŽ’­åŠŸèƒ½ä¸€æ —÷€‚è¿™¿Uéœ€æ±‚一斚w¢˜q«ä‹ÉHTML逐步æ·ÕdŠ äº†è¡¨å•ã€è„šæœ¬ã€DOM½{‰å®¢æˆïL«¯è¡ŒäØ“åQŒå¦ä¸€æ–šw¢åœ¨æœåŠ¡å™¨ç«¯åˆ™å‡ºçŽ°äº†CGI规范以响应客æˆïL«¯çš„åŠ¨æ€è¯·æ±‚ï¼Œä½œäØ“ä¼ è¾“è½½ä½“çš„HTTP协议也添加了文äšg上蝲ã€?cookie˜q™äº›ç‰ÒŽ€§ã€‚其中cookieçš„ä½œç”¨å°±æ˜¯äØ“äº†è§£å†³HTTP协议无状态的¾~ºé™·æ‰€ä½œå‡ºçš„努力。至于后来出现的session机制则是又一¿Uåœ¨å®¢æˆ·ç«¯ä¸ŽæœåŠ¡å™¨ä¹‹é—´ä¿æŒçŠ¶æ€çš„è§£å†³æ–ÒŽ¡ˆã€?br />
让我们用几个例子来描˜qîC¸€ä¸‹cookieå’Œsession机制之间的区别与联系。笔者曾¾lå¸¸åŽÈš„一家咖啡店有喝5杯咖啡免费赠一杯咖啡的优惠åQŒç„¶è€Œä¸€‹Æ¡æ€§æ¶ˆè´?杯咖啡的æœÞZ¼šå¾®ä¹Žå…¶å¾®åQŒè¿™æ—¶å°±éœ€è¦æŸ¿Uæ–¹å¼æ¥¾Uªå½•某位™å‘Ö®¢çš„æ¶ˆè´ÒŽ•°é‡ã€‚想象一下其实也无外乎下面的几种æ–ÒŽ¡ˆåQ?br /> 1、该店的店员很厉宻I¼Œèƒ½è®°ä½æ¯ä½é¡¾å®¢çš„æ¶ˆè´¹æ•°é‡åQŒåªè¦é¡¾å®¢ä¸€èµ°è¿›å’–啡店,店员ž®ÞqŸ¥é“该怎么对待了。这¿Uåšæ³•就是协议本íw«æ”¯æŒçŠ¶æ€ã€?br /> 2、发¾l™é¡¾å®¢ä¸€å¼ å¡ç‰‡ï¼Œä¸Šé¢è®°å½•着消费的数量,一般还有个有效期限。每‹Æ¡æ¶ˆè´ÒŽ—¶åQŒå¦‚果顾客出½Cø™¿™å¼ å¡ç‰‡ï¼Œåˆ™æ­¤‹Æ¡æ¶ˆè´¹å°±ä¼šä¸Žä»¥å‰æˆ–以后的消费相联¾p»è“v来。这¿Uåšæ³•就是在客户端保持状态ã€?br /> 3、发¾l™é¡¾å®¢ä¸€å¼ ä¼šå‘˜å¡åQŒé™¤äº†å¡å·ä¹‹å¤–什么信息也不纪录,每次消费æ—Óž¼Œå¦‚æžœ™å‘Ö®¢å‡ºç¤ºè¯¥å¡ç‰‡ï¼Œåˆ™åº—员在店里的纪录本上找到这个卡号对应的¾Uªå½•æ·ÕdŠ ä¸€äº›æ¶ˆè´¹ä¿¡æ¯ã€‚è¿™¿Uåšæ³•就是在服务器端保持状态ã€?br />
ç”׃ºŽHTTP协议是无状态的åQŒè€Œå‡ºäºŽç§¿Uè€ƒè™‘ä¹Ÿä¸å¸Œæœ›ä½¿ä¹‹æˆäØ“æœ‰çŠ¶æ€çš„åQŒå› æ­¤ï¼ŒåŽé¢ä¸¤ç§æ–ÒŽ¡ˆž®±æˆä¸ºçŽ°å®žçš„é€‰æ‹©ã€‚å…·ä½“æ¥è¯´cookie机制采用的是在客æˆïL«¯ä¿æŒçŠ¶æ€çš„æ–ÒŽ¡ˆåQŒè€Œsession机制采用的是在服务器端保持状态的æ–ÒŽ¡ˆã€‚同时我们也看到åQŒç”±äºŽé‡‡ç”¨æœåŠ¡å™¨ç«¯ä¿æŒçŠ¶æ€çš„æ–ÒŽ¡ˆåœ¨å®¢æˆïL«¯ä¹Ÿéœ€è¦ä¿å­˜ä¸€ä¸ªæ ‡è¯†ï¼Œæ‰€ä»¥session机制可能需要借助于cookie机制来达åˆîC¿å­˜æ ‡è¯†çš„目的åQŒä½†å®žé™…上它˜q˜æœ‰å…¶ä»–选择ã€?br />
三、理解cookie机制
cookie机制的基本原理就如上面的例子一æ ïL®€å•,但是˜q˜æœ‰å‡ ä¸ªé—®é¢˜éœ€è¦è§£å†»I¼š“会员å?#8221;如何分发åQ?#8220;会员å?#8221;的内容;以及客户如何使用“会员å?#8221;ã€?br />
正统的cookie分发是通过扩展HTTP协议来实现的åQŒæœåŠ¡å™¨é€šè¿‡åœ¨HTTP的响应头中加上一行特ŒDŠçš„æŒ‡ç¤ºä»¥æ½Cºæµè§ˆå™¨æŒ‰ç…§æŒ‡ç¤ºç”Ÿæˆç›¸åº”çš„cookie。然而纯¾_¹çš„客户端脚本如JavaScript或者VBScript也可以生成cookieã€?br />
而cookie çš„ä‹É用是由浏览器按照一定的原则在后台自动发送给服务器的。浏览器‹‚€æŸ¥æ‰€æœ‰å­˜å‚¨çš„cookieåQŒå¦‚果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置åQŒåˆ™æŠŠè¯¥cookie附在è¯äh±‚资源的HTTPè¯äh±‚头上发送给服务器。意思是麦当劳的会员卡只能在麦当劳的店里出示åQŒå¦‚果某家分店还发行了自å·Þqš„会员卡,那么˜q›è¿™å®¶åº—的时候除了要出示麦当劳的会员卡,˜q˜è¦å‡ºç¤º˜q™å®¶åº—的会员卡ã€?br />
cookie的内容主要包括:名字åQŒå€û|¼Œ˜q‡æœŸæ—‰™—´åQŒèµ\径和域ã€?br /> 其中域可以指定某一个域比如.google.comåQŒç›¸å½“于æ€Õdº—招牌åQŒæ¯”如宝‹zå…¬å¸ï¼Œä¹Ÿå¯ä»¥æŒ‡å®šä¸€ä¸ªåŸŸä¸‹çš„具体某台机器比如www.google.com或者froogle.google.comåQŒå¯ä»¥ç”¨é£˜æŸ”来做比ã€?br /> 路径ž®±æ˜¯è·Ÿåœ¨åŸŸååŽé¢çš„URL路径åQŒæ¯”å¦?或è€?foo½{‰ç­‰åQŒå¯ä»¥ç”¨æŸé£˜æŸ”专柜做比ã€?br /> 路径与域合在一起就构成了cookie的作用范围ã€?br /> 如果不设¾|®è¿‡æœŸæ—¶é—ß_¼Œåˆ™è¡¨½Cø™¿™ä¸ªcookie的生命期为浏览器会话期间åQŒåªè¦å…³é—­æµè§ˆå™¨½H—口åQŒcookiež®±æ¶ˆå¤×ƒº†ã€‚è¿™¿Uç”Ÿå‘½æœŸä¸ºæµè§ˆå™¨ä¼šè¯æœŸçš„ cookie被称ä¸ÞZ¼šè¯cookie。会话cookie一般不存储在硬盘上而是保存在内存里åQŒå½“ç„¶è¿™¿Uè¡Œä¸ºåƈ不是规范规定的。如果设¾|®äº†˜q‡æœŸæ—‰™—´åQŒæµè§ˆå™¨ž®×ƒ¼šæŠŠcookie保存到硬盘上åQŒå…³é—­åŽå†æ¬¡æ‰“å¼€‹¹è§ˆå™¨ï¼Œ˜q™äº›cookie仍然有效直到­‘…过讑֮šçš„过期时间ã€?br />
存储在硬盘上的cookie 可以在不同的‹¹è§ˆå™¨è¿›½E‹é—´å…׃ínåQŒæ¯”如两个IE½H—口。而对于保存在内存里的cookieåQŒä¸åŒçš„‹¹è§ˆå™¨æœ‰ä¸åŒçš„处理方式。对于IEåQŒåœ¨ä¸€ä¸ªæ‰“开的窗口上æŒ?Ctrl-NåQˆæˆ–者从文äšg菜单åQ‰æ‰“开的窗口可以与原窗口共享,而ä‹É用其他方式新开的IE˜q›ç¨‹åˆ™ä¸èƒ½å…±äº«å·²¾læ‰“开的窗口的内存cookieåQ›å¯¹äº?Mozilla Firefox0.8åQŒæ‰€æœ‰çš„˜q›ç¨‹å’Œæ ‡½{ùN¡µéƒ½å¯ä»¥å…±äº«åŒæ ïLš„cookie。一般来说是用javascriptçš„window.open打开的窗口会与原½H—口å…׃ín内存cookie。浏览器对于会话cookie的这¿Uåªè®¤cookie不认人的处理方式¾lå¸¸¾l™é‡‡ç”¨session机制的web应用½E‹åºå¼€å‘者造成很大的困扰ã€?br />
下面ž®±æ˜¯ä¸€ä¸ªgoolge讄¡½®cookie的响应头的例å­?br />
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
˜q™æ˜¯ä½¿ç”¨HTTPLook˜q™ä¸ªHTTP Sniffer软äšg来俘èŽïLš„HTTP通讯¾Uªå½•的一部分

image
‹¹è§ˆå™¨åœ¨å†æ¬¡è®‰K—®goolge的资源时自动向外发送cookie

image
用Firefox可以很容易的观察现有的cookie的�br /> 使用HTTPLook配合Firefox可以很容易的理解cookie的工作原理�br />
image
IE也可以设¾|®åœ¨æŽ¥å—cookie前询é—?br />
四、理解session机制

session机制是一¿UæœåŠ¡å™¨ç«¯çš„æœºåˆ¶åQŒæœåŠ¡å™¨ä½¿ç”¨ä¸€¿Uç±»ä¼égºŽæ•£åˆ—表的¾l“æž„åQˆä¹Ÿå¯èƒ½ž®±æ˜¯ä½¿ç”¨æ•£åˆ—表)来保存信息ã€?br />
å½“ç¨‹åºéœ€è¦äØ“æŸä¸ªå®¢æˆ·ç«¯çš„è¯äh±‚创徏一个session的时候,服务器首先检查这个客æˆïL«¯çš„请求里是否已包含了一个session标识 - ¿UîCØ“ session idåQŒå¦‚果已包含一个session id则说明以前已¾läؓ此客æˆïL«¯åˆ›å¾˜q‡sessionåQŒæœåС噍ž®±æŒ‰ç…§session id把这ä¸?session‹‚€ç´¢å‡ºæ¥ä‹É用(如果‹‚€ç´¢ä¸åˆŽÍ¼Œå¯èƒ½ä¼šæ–°å»ÞZ¸€ä¸ªï¼‰åQŒå¦‚果客æˆïL«¯è¯äh±‚不包含session idåQŒåˆ™ä¸ºæ­¤å®¢æˆ·ç«¯åˆ›å»ÞZ¸€ä¸ªsessionòq¶ä¸”生成一个与此session相关联的session idåQŒsession id的值应该是一个既不会重复åQŒåˆä¸å®¹æ˜“被扑ֈ°è§„律以仿造的字符ä¸ÔŒ¼Œ˜q™ä¸ª session idž®†è¢«åœ¨æœ¬‹Æ¡å“åº”中˜q”回¾l™å®¢æˆïL«¯ä¿å­˜ã€?br />
保存˜q™ä¸ªsession id的方式可以采用cookieåQŒè¿™æ ·åœ¨äº¤äº’˜q‡ç¨‹ä¸­æµè§ˆå™¨å¯ä»¥è‡ªåŠ¨çš„æŒ‰ç…§è§„åˆ™æŠŠ˜q™ä¸ªæ ‡è¯†å‘挥¾l™æœåŠ¡å™¨ã€‚ä¸€èˆ¬è¿™ä¸ªcookie的名字都是类ä¼égºŽSEEESIONIDåQŒè€Œã€‚比如weblogic对于web应用½E‹åºç”Ÿæˆçš„cookieåQŒJSESSIONID= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764åQŒå®ƒçš„名字就æ˜?JSESSIONIDã€?br />
ç”׃ºŽcookie可以被äh为的¼›æ­¢åQŒå¿…™åÀLœ‰å…¶ä»–机制以便在cookie被禁止时仍然能够把session id传递回服务器。经常被使用的一¿UæŠ€æœ¯å«åšURL重写åQŒå°±æ˜¯æŠŠsession id直接附加在URL路径的后面,附加方式也有两种åQŒä¸€¿Uæ˜¯ä½œäØ“URL路径的附加信息,表现形式为http://...../xxx;jsessionid= ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
另一¿Uæ˜¯ä½œäؓ查询字符串附加在URL后面åQŒè¡¨çްåÅžå¼äØ“http://...../xxx?jsessionid=ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764
˜q™ä¸¤¿Uæ–¹å¼å¯¹äºŽç”¨æˆäh¥è¯´æ˜¯æ²¡æœ‰åŒºåˆ«çš„,只是服务器在解析的时候处理的方式不同åQŒé‡‡ç”¨ç¬¬ä¸€¿Uæ–¹å¼ä¹Ÿæœ‰åˆ©äºŽæŠŠsession id的信息和正常½E‹åºå‚数区分开来ã€?br /> ä¸ÞZº†åœ¨æ•´ä¸ªäº¤äº’过½E‹ä¸­å§‹ç»ˆä¿æŒçŠ¶æ€ï¼Œž®±å¿…™åÕdœ¨æ¯ä¸ªå®¢æˆ·ç«¯å¯èƒ½è¯·æ±‚的路径后面都包含这个session idã€?br />
另一¿UæŠ€æœ¯å«åšè¡¨å•隐藏字ŒDüc€‚就是服务器会自动修改表单,æ·ÕdŠ ä¸€ä¸ªéšè—å­—ŒDµï¼Œä»¥ä¾¿åœ¨è¡¨å•提交时能够把session id传递回服务器。比如下面的表单
<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>


˜q™ç§æŠ€æœ¯çŽ°åœ¨å·²è¾ƒå°‘åº”ç”¨åQŒç¬”者接触过的很古老的iPlanet6(SunONE应用服务器的前èín)ž®×ƒ‹É用了˜q™ç§æŠ€æœ¯ã€?br /> 实际上这¿UæŠ€æœ¯å¯ä»¥ç®€å•的用对action应用URL重写来代æ›Ñ€?br />
在谈论session机制的时候,常常听到˜q™æ ·ä¸€¿Uè¯¯è§?#8220;只要关闭‹¹è§ˆå™¨ï¼Œsessionž®±æ¶ˆå¤×ƒº†”。其实可以想象一下会员卡的例子,除非™å‘Ö®¢ä¸ÕdŠ¨å¯¹åº—å®¶æå‡ºé”€å¡ï¼Œå¦åˆ™åº—å®¶¾lå¯¹ä¸ä¼šè½ÀL˜“删除™å‘Ö®¢çš„资料。对session来说也是一æ ïLš„åQŒé™¤éžç¨‹åºé€šçŸ¥æœåŠ¡å™¨åˆ é™¤ä¸€ä¸ªsessionåQŒå¦åˆ™æœåŠ¡å™¨ä¼šä¸€ç›´ä¿ç•™ï¼Œ½E‹åºä¸€èˆ¬éƒ½æ˜¯åœ¨ç”¨æˆ·åšlog off的时候发个指令去删除session。然而浏览器从来不会ä¸ÕdŠ¨åœ¨å…³é—­ä¹‹å‰é€šçŸ¥æœåŠ¡å™¨å®ƒž®†è¦å…³é—­åQŒå› æ­¤æœåС噍æ ÒŽœ¬ä¸ä¼šæœ‰æœºä¼šçŸ¥é“浏览器已经关闭åQŒä¹‹æ‰€ä»¥ä¼šæœ‰è¿™¿Ué”™è§‰ï¼Œæ˜¯å¤§éƒ¨åˆ†session机制都ä‹É用会话cookie来保存session idåQŒè€Œå…³é—­æµè§ˆå™¨åŽè¿™ä¸?session idž®±æ¶ˆå¤×ƒº†åQŒå†‹Æ¡è¿žæŽ¥æœåŠ¡å™¨æ—¶ä¹Ÿž®±æ— æ³•找到原来的session。如果服务器讄¡½®çš„cookie被保存到¼‹¬ç›˜ä¸Šï¼Œæˆ–者ä‹É用某¿Uæ‰‹ŒD‰|”¹å†™æµè§ˆå™¨å‘出的HTTPè¯äh±‚å¤ß_¼ŒæŠŠåŽŸæ¥çš„session id发送给服务器,则再‹Æ¡æ‰“å¼€‹¹è§ˆå™¨ä»ç„¶èƒ½å¤Ÿæ‰¾åˆ°åŽŸæ¥çš„sessionã€?br />
æ°æ°æ˜¯ç”±äºŽå…³é—­æµè§ˆå™¨ä¸ä¼šå¯ÆD‡´session被删除,˜q«ä‹ÉæœåŠ¡å™¨äØ“seesion讄¡½®äº†ä¸€ä¸ªå¤±æ•ˆæ—¶é—ß_¼Œå½“距¼›Õd®¢æˆïL«¯ä¸Šä¸€‹Æ¡ä‹É用session的时间超˜q‡è¿™ä¸ªå¤±æ•ˆæ—¶é—´æ—¶åQŒæœåС噍ž®±å¯ä»¥è®¤ä¸ºå®¢æˆïL«¯å·²ç»åœæ­¢äº†æ´»åŠ¨ï¼Œæ‰ä¼šæŠŠsession删除以节省存储空间ã€?br />
五、理解javax.servlet.http.HttpSession
HttpSession是Javaòq›_°å¯¹sessionæœºåˆ¶çš„å®žçŽ°è§„èŒƒï¼Œå› äØ“å®ƒä»…ä»…æ˜¯ä¸ªæŽ¥å£ï¼Œå…·ä½“åˆ°æ¯ä¸ªweb应用服务器的提供商,除了对规范支持之外,仍然会有一些规范里没有规定的细微差异。这里我们以BEAçš„Weblogic Server8.1ä½œäØ“ä¾‹å­æ¥æ¼”½Cºã€?br />
首先åQŒWeblogic Server提供了一¾pÕdˆ—的参数来控制它的HttpSession的实玎ͼŒåŒ…括使用cookie的开关选项åQŒä‹É用URL重写的开关选项åQŒsession持久化的讄¡½®åQŒsession失效旉™—´çš„设¾|®ï¼Œä»¥åŠé’ˆå¯¹cookie的各¿Uè®¾¾|®ï¼Œæ¯”如讄¡½®cookie的名字、èµ\径、域åQ?cookie的生存时间等ã€?br />
一般情况下åQŒsession都是存储在内存里åQŒå½“服务器进½E‹è¢«åœæ­¢æˆ–者重启的时候,内存里的session也会被清½Iºï¼Œå¦‚果讄¡½®äº†session的持久化ç‰ÒŽ€§ï¼ŒæœåŠ¡å™¨å°±ä¼šæŠŠsession保存到硬盘上åQŒå½“服务器进½E‹é‡æ–°å¯åŠ¨æˆ–˜q™äº›ä¿¡æ¯ž®†èƒ½å¤Ÿè¢«å†æ¬¡ä½¿ç”¨åQ?Weblogic Server支持的持久性方式包括文件、数据库、客æˆïL«¯cookie保存和复制ã€?br />
å¤åˆ¶ä¸¥æ ¼è¯´æ¥ä¸ç®—æŒä¹…åŒ–ä¿å­˜ï¼Œå› äØ“session实际上还是保存在内存里,不过同样的信息被复制到各个cluster内的服务器进½E‹ä¸­åQŒè¿™æ ·å³ä½¿æŸä¸ªæœåС噍˜q›ç¨‹åœæ­¢å·¥ä½œä¹Ÿä»ç„¶å¯ä»¥ä»Žå…¶ä»–˜q›ç¨‹ä¸­å–å¾—sessionã€?br />
cookie生存旉™—´çš„设¾|®åˆ™ä¼šåª„响浏览器生成的cookie是否是一个会话cookie。默认是使用会话cookie。有兴趣的可以用它来试验我们在第四节里提到的那个误解ã€?br />
cookieçš„èµ\径对于web应用½E‹åºæ¥è¯´æ˜¯ä¸€ä¸ªéžå¸”R‡è¦çš„选项åQŒWeblogic Server对这个选项的默认处理方式ä‹É得它与其他服务器有明昄¡š„区别。后面我们会专题讨论ã€?br />
关于session的设¾|®å‚考[5] http://e-docs.bea.com/wls/docs70/webapp/weblogic_xml.html#1036869

六、HttpSession常见问题
åQˆåœ¨æœ¬å°èЂ䏭sessionçš„å«ä¹‰äØ“â‘¤å’Œâ‘¥çš„æ··åˆåQ?br />
1、session在何时被创徏
一个常见的误解是以为session在有客户端访问时ž®Þp¢«åˆ›å¾åQŒç„¶è€Œäº‹å®žæ˜¯ç›´åˆ°æŸserver端程序调ç”?HttpServletRequest.getSession(true)˜q™æ ·çš„语句时才被创徏åQŒæ³¨æ„å¦‚æžœJSP没有昄¡¤ºçš„ä‹Éç”?<% @page session="false"%> 关闭sessionåQŒåˆ™JSPæ–‡äšg在编译成Servlet时将会自动加上这样一条语å?HttpSession session = HttpServletRequest.getSession(true);˜q™ä¹Ÿæ˜¯JSP中隐含的 session对象的来历ã€?br />
ç”׃ºŽsession会消耗内存资源,因此åQŒå¦‚果不打算使用sessionåQŒåº”该在所有的JSP中关闭它ã€?br />
2、session何时被删é™?br /> ¾l¼åˆå‰é¢çš„讨论,session在下列情况下被删除a.½E‹åºè°ƒç”¨HttpSession.invalidate();或b.距离上一‹Æ¡æ”¶åˆ°å®¢æˆïL«¯å‘送的session idæ—‰™—´é—´éš”­‘…过了session的超时设¾|?或c.服务器进½E‹è¢«åœæ­¢åQˆéžæŒä¹…sessionåQ?br />
3、如何做到在‹¹è§ˆå™¨å…³é—­æ—¶åˆ é™¤session
严格的讲åQŒåšä¸åˆ°˜q™ä¸€ç‚V€‚可以做一点努力的办法是在所有的客户端页面里使用javascript代码window.oncolose来监视浏览器的关闭动作,然后向服务器发送一个请求来删除session。但是对于浏览器崩溃或者强行杀死进½E‹è¿™äº›éžå¸¸è§„手段仍然无能为力ã€?br />
4、有个HttpSessionListener是怎么回事
ä½ å¯ä»¥åˆ›å»ø™¿™æ ïLš„listeneråŽÈ›‘控session的创建和销毁事ä»Óž¼Œä½¿å¾—在发生这æ ïLš„事äšg时你可以做一些相应的工作。注意是session的创建和销毁动作触发listeneråQŒè€Œä¸æ˜¯ç›¸åã€‚类似的与HttpSession有关的listener˜q˜æœ‰ HttpSessionBindingListeneråQŒHttpSessionActivationListenerå’?HttpSessionAttributeListenerã€?br />
5、存攑֜¨session中的对象必须是可序列化的å?br /> ä¸æ˜¯å¿…éœ€çš„ã€‚è¦æ±‚å¯¹è±¡å¯åºåˆ—åŒ–åªæ˜¯äØ“äº†session能够在集¾Ÿ¤ä¸­è¢«å¤åˆ¶æˆ–者能够持久保存或者在必要时server能够暂时把session交换出内存。在 Weblogic Serverçš„session中放¾|®ä¸€ä¸ªä¸å¯åºåˆ—化的对象在控制åîC¸Šä¼šæ”¶åˆîC¸€ä¸ªè­¦å‘Šã€‚我所用过的某个iPlanet版本如果 session中有不可序列化的对象åQŒåœ¨session销毁时会有一个ExceptionåQŒå¾ˆå¥‡æ€ªã€?br />
6、如何才能正¼‹®çš„应付客户端禁止cookie的可能æ€?br /> å¯Òމ€æœ‰çš„URL使用URL重写åQŒåŒ…括超链接åQŒformçš„actionåQŒå’Œé‡å®šå‘çš„URLåQŒå…·ä½“做法参见[6]
http://e-docs.bea.com/wls/docs70/webapp/sessions.html#100770

7、开两个‹¹è§ˆå™¨çª—口访问应用程序会使用同一个session˜q˜æ˜¯ä¸åŒçš„session
参见½W¬ä¸‰ž®èЂ坹cookie的讨论,对session来说是只认id不认人,因此不同的浏览器åQŒä¸åŒçš„½H—口打开方式以及不同的cookie存储方式都会对这个问题的½{”案有媄响ã€?br />
8、如何防止用æˆäh‰“开两个‹¹è§ˆå™¨çª—口操作导致的sessionæ··äØ•
˜q™ä¸ªé—®é¢˜ä¸Žé˜²æ­¢è¡¨å•多‹Æ¡æäº¤æ˜¯¾cÖM¼¼çš„,可以通过讄¡½®å®¢æˆ·ç«¯çš„令牌来解冟뀂就是在服务器每‹Æ¡ç”Ÿæˆä¸€ä¸ªä¸åŒçš„id˜q”回¾l™å®¢æˆïL«¯åQŒåŒæ—¶ä¿å­˜åœ¨session里,客户端提交表单时必须把这个id也返回服务器åQŒç¨‹åºé¦–先比较返回的id与保存在session里的值是否一è‡ß_¼Œå¦‚果不一致则说明本次操作已经被提交过了。可以参看《J2EE核心模式》关于表½Cºå±‚模式的部分。需要注意的是对于ä‹É用javascript window.open打开的窗口,一般不讄¡½®˜q™ä¸ªidåQŒæˆ–者ä‹É用单独的idåQŒä»¥é˜²ä¸»½H—口无法操作åQŒå¾è®®ä¸è¦å†window.open打开的窗口里做修æ”ÒŽ“ä½œï¼Œ˜q™æ ·ž®±å¯ä»¥ä¸ç”¨è®¾¾|®ã€?br />
9ã€äØ“ä»€ä¹ˆåœ¨Weblogic Server中改变session的值后要重新调用一‹Æ¡session.setValue
做这个动作主要是ä¸ÞZº†åœ¨é›†¾Ÿ¤çŽ¯å¢ƒä¸­æç¤ºWeblogic Server session中的值发生了改变åQŒéœ€è¦å‘其他服务器进½E‹å¤åˆ¶æ–°çš„session倹{€?br />
10ã€äØ“ä»€ä¹ˆsession不见äº?br /> 排除session正常失效的因素之外,服务器本íw«çš„可能性应该是微乎其微的,虽然½W”者在iPlanet6SP1加若òq²è¡¥ä¸çš„Solaris版本上倒也遇到˜q‡ï¼›‹¹è§ˆå™¨æ’件的可能性次之,½W”者也遇到˜q?721插äšg造成的问题;理论上防火墙或者代理服务器在cookie处理上也有可能会出现问题ã€?br /> 出现˜q™ä¸€é—®é¢˜çš„大部分原因都是½E‹åºçš„é”™è¯¯ï¼Œæœ€å¸¸è§çš„å°±æ˜¯åœ¨ä¸€ä¸ªåº”ç”¨ç¨‹åºä¸­åŽ»è®¿é—®å¦å¤–ä¸€ä¸ªåº”ç”¨ç¨‹åºã€‚æˆ‘ä»¬åœ¨ä¸‹ä¸€èŠ‚è®¨è®ø™¿™ä¸ªé—®é¢˜ã€?br />
七、跨应用½E‹åºçš„sessionå…׃ín

常常有这æ ïLš„æƒ…况åQŒä¸€ä¸ªå¤§™å¹ç›®è¢«åˆ†å‰²æˆè‹¥å¹²ž®é¡¹ç›®å¼€å‘,ä¸ÞZº†èƒ½å¤Ÿäº’不òq²æ‰°åQŒè¦æ±‚每个小™å¹ç›®ä½œäؓ一个单独的web应用½E‹åºå¼€å‘,可是åˆîCº†æœ€åŽçªç„¶å‘现某几个ž®é¡¹ç›®ä¹‹é—´éœ€è¦å…±äº«ä¸€äº›ä¿¡æ¯ï¼Œæˆ–者想使用session来实现SSO(single sign on)åQŒåœ¨session中保存login的用户信息,最自然的要求是应用½E‹åºé—´èƒ½å¤Ÿè®¿é—®å½¼æ­¤çš„sessionã€?br />
然而按照Servlet规范åQŒsession的作用范围应该仅仅限于当前应用程序下åQŒä¸åŒçš„应用½E‹åºä¹‹é—´æ˜¯ä¸èƒ½å¤Ÿäº’相讉K—®å¯ÒŽ–¹çš„session的。各个应用服务器从实际效果上都遵守了˜q™ä¸€è§„范åQŒä½†æ˜¯å®žçŽ°çš„¾l†èŠ‚å´å¯èƒ½å„æœ‰ä¸åŒï¼Œå› æ­¤è§£å†³è·¨åº”ç”¨ç¨‹åºsessionå…׃ín的方法也各不相同ã€?br />
首先来看一下Tomcat是如何实现web应用½E‹åºä¹‹é—´session的隔¼›Èš„åQŒä»Ž Tomcat讄¡½®çš„cookie路径来看åQŒå®ƒå¯¹ä¸åŒçš„应用½E‹åºè®„¡½®çš„cookie路径是不同的åQŒè¿™æ ·ä¸åŒçš„应用½E‹åºæ‰€ç”¨çš„session id是不同的åQŒå› æ­¤å³ä½¿åœ¨åŒä¸€ä¸ªæµè§ˆå™¨½H—口里访问不同的应用½E‹åºåQŒå‘送给服务器的session id也可以是不同的ã€?br />
image
image

æ ÒŽ®˜q™ä¸ªç‰ÒŽ€§ï¼Œæˆ‘们可以推测Tomcat中session的内存结构大致如下ã€?br /> image

½W”者以前用˜q‡çš„iPlanet也采用的是同æ ïLš„æ–¹å¼åQŒä¼°è®¡SunONE与iPlanet之间不会有太大的差别。对于这¿Uæ–¹å¼çš„æœåŠ¡å™¨ï¼Œè§£å†³çš„æ€èµ\很简单,实际实行èµäh¥ä¹Ÿä¸éš¾ã€‚要么让所有的应用½E‹åºå…׃ín一个session idåQŒè¦ä¹ˆè®©åº”用½E‹åºèƒ½å¤ŸèŽ·å¾—å…¶ä»–åº”ç”¨½E‹åºçš„session idã€?br />
iPlanet中有一¿Uå¾ˆ½Ž€å•çš„æ–ÒŽ³•来实现共享一个session idåQŒé‚£ž®±æ˜¯æŠŠå„个应用程序的cookie路径都设ä¸?åQˆå®žé™…上应该æ˜?NASAppåQŒå¯¹äºŽåº”用程序来讲它的作用相当于根)ã€?br />
<session-info>
<path>/NASApp</path>
</session-info>


需要注意的是,操作å…׃ínçš„session应该遵åó@一些编½E‹çº¦å®šï¼Œæ¯”如在session attribute名字的前面加上应用程序的前缀åQŒä‹Éå¾?setAttribute("name", "neo")变成setAttribute("app1.name", "neo")åQŒä»¥é˜²æ­¢å‘½å½Iºé—´å†²çªåQŒå¯¼è‡´äº’相覆盖ã€?br />
在Tomcat中则没有˜q™ä¹ˆæ–¹ä¾¿çš„选择。在Tomcat版本3上,我们˜q˜å¯ä»¥æœ‰ä¸€äº›æ‰‹ŒD‰|¥å…׃ínsession。对于版æœ?以上的TomcatåQŒç›®å‰ç¬”者尚未发现简单的办法。只能借助于第三方的力量,比如使用文äšg、数据库、JMS或者客æˆïL«¯cookieåQŒURL参数或者隐藏字ŒD늭‰æ‰‹æ®µã€?br />
我们再看一下Weblogic Server是如何处理session的�br /> image
image

从截屏画面上可以看到Weblogic Serverå¯Òމ€æœ‰çš„应用½E‹åºè®„¡½®çš„cookieçš„èµ\径都æ˜?åQŒè¿™æ˜¯ä¸æ˜¯æ„å‘³ç€åœ¨Weblogic Server中默认的ž®±å¯ä»¥å…±äº«session了呢åQŸç„¶è€Œä¸€ä¸ªå°å®žéªŒå›_¯è¯æ˜Žå³ä‹É不同的应用程序ä‹É用的是同一个sessionåQŒå„个应用程序仍然只能访问自己所讄¡½®çš„那些属性。这说明Weblogic Server中的session的内存结构可能如ä¸?br /> image

对于˜q™æ ·ä¸€¿Uç»“构,åœ?session机制本èín上来解决sessionå…׃ín的问题应该是不可能的了。除了借助于第三方的力量,比如使用文äšg、数据库、JMS或者客æˆïL«¯ cookieåQŒURL参数或者隐藏字ŒD늭‰æ‰‹æ®µåQŒè¿˜æœ‰ä¸€¿Uè¾ƒä¸ºæ–¹ä¾¿çš„做法åQŒå°±æ˜¯æŠŠä¸€ä¸ªåº”用程序的session攑ֈ°ServletContext中,˜q™æ ·å¦å¤–一个应用程序就可以从ServletContext中取得前一个应用程序的引用。示例代码如下,

应用½E‹åºA
context.setAttribute("appA", session);


应用½E‹åºB
contextA = context.getContext("/appA");
HttpSession sessionA = (HttpSession)contextA.getAttribute("appA");


值得注意的是˜q™ç§ç”¨æ³•不可¿UÀL¤åQŒå› ä¸ºæ ¹æ®ServletContextçš„JavaDocåQŒåº”用服务器可以处于安全的原因对于context.getContext("/appA");˜q”回½Iºå€û|¼Œä»¥ä¸Šåšæ³•在Weblogic Server 8.1中通过ã€?br />
那么Weblogic Serverä¸ÞZ»€ä¹ˆè¦æŠŠæ‰€æœ‰çš„应用½E‹åºçš„cookie路径都设ä¸?å‘¢ï¼ŸåŽŸæ¥æ˜¯äØ“äº†SSOåQŒå‡¡æ˜¯å…±äº«è¿™ä¸ªsession的应用程序都可以å…׃ín认证的信息。一个简单的实验ž®±å¯ä»¥è¯æ˜Žè¿™ä¸€ç‚¹ï¼Œä¿®æ”¹é¦–å…ˆç™Õd½•的那个应用程序的描述½W¦weblogic.xmlåQŒæŠŠcookie路径修改ä¸?appA 讉K—®å¦å¤–一个应用程序会重新要求ç™Õd½•åQŒå³ä½¿æ˜¯åè¿‡æ¥ï¼Œå…ˆè®¿é—®cookie路径ä¸?的应用程序,再访问修改过路径的这个,虽然不再提示ç™Õd½•åQŒä½†æ˜¯ç™»å½•的用户信息也会丢失。注意做˜q™ä¸ªå®žéªŒæ—¶è®¤è¯æ–¹å¼åº”该ä‹É用FORMåQŒå› ä¸ºæµè§ˆå™¨å’Œweb服务器对basic认证方式有其他的处理方式åQŒç¬¬äºŒæ¬¡è¯äh±‚的认证不是通过 session来实现的。具体请参看[7] secion 14.8 AuthorizationåQŒä½ å¯ä»¥ä¿®æ”¹æ‰€é™„çš„½CÞZ¾‹½E‹åºæ¥åš˜q™äº›è¯•验ã€?br />
八、æ€È»“
session机制本èínòq¶ä¸å¤æ‚åQŒç„¶è€Œå…¶å®žçŽ°å’Œé…¾|®ä¸Šçš„灵‹zÀL€§å´ä½¿å¾—具体情况复杂多变。这也要求我们不能把仅仅某一‹Æ¡çš„¾léªŒæˆ–者某一个浏览器åQŒæœåŠ¡å™¨çš„ç»éªŒå½“ä½œæ™®éé€‚ç”¨çš„ç»éªŒï¼Œè€Œæ˜¯å§‹ç»ˆéœ€è¦å…·ä½“æƒ…å†µå…·ä½“åˆ†æžã€?br /> 摘要åQšè™½ç„¶session机制在web应用½E‹åºä¸­è¢«é‡‡ç”¨å·²ç»å¾ˆé•¿æ—‰™—´äº†ï¼Œä½†æ˜¯ä»ç„¶æœ‰å¾ˆå¤šäh不清楚session机制的本质,以至不能正确的应用这一技术。本文将详细讨论sessionçš„å·¥ä½œæœºåˆ¶åÆˆä¸”å¯¹åœ¨Java web application中应用session机制时常见的问题作出解答ã€?/div>

]]>URLClassLoader加蝲class到当前线½E‹ç±»åŠ è²å™¨ï¼ˆè½¬ï¼‰http://www.aygfsteel.com/boluobn/archive/2008/01/26/177872.html菠萝菠萝Sat, 26 Jan 2008 01:51:00 GMThttp://www.aygfsteel.com/boluobn/archive/2008/01/26/177872.htmlhttp://www.aygfsteel.com/boluobn/comments/177872.htmlhttp://www.aygfsteel.com/boluobn/archive/2008/01/26/177872.html#Feedback0http://www.aygfsteel.com/boluobn/comments/commentRss/177872.htmlhttp://www.aygfsteel.com/boluobn/services/trackbacks/177872.html 下面来看一个例子,在该例子中,我们要完成的工作是利用URLClassLoader加蝲jaròq¶è¿è¡Œå…¶ä¸­çš„¾cÈš„æŸä¸ªæ–ÒŽ³•ã€?

首先我们定义一个接口,使所有ç‘ô承它的类都必™åÕd®žçްactionæ–ÒŽ³•åQŒå¦‚下:

  public   interface  ActionInterface  {
     public  String action();
}
å®ŒæˆåŽå°†å…¶æ‰“åŒ…äØ“testInterface.jaræ–‡äšgã€?/p>

接下来新å»ÞZ¸€å·¥ç¨‹åQŒäؓ了编译通过åQŒå¼•入之前打好的testInterface.jaråŒ…ã€‚åÆˆåˆ›å¾TestAction¾c»ï¼Œä½¿å®ƒå®žçްActionInterface接口。如下:


  public   class  TestAction  implements  ActionInterface  {
     public  String action()  {
         return   " com.mxjava.TestAction.action " ;
    }
}
 
å®ŒæˆåŽå°†å…¶æ‰“åŒ…äØ“test.jaråQŒæ”¾åœ¨c盘根目录下。下面要做的ž®±æ˜¯åˆ©ç”¨URLClassLoader加蝲òq¶è¿è¡ŒTestActionçš„actionæ–ÒŽ³•åQŒåƈž®†è¿”回的值打印在控制åîC¸Šã€?/p>

新徏一工程åQŒå¼•å…¥testInterface.jaråŒ…ã€‚åÆˆåˆ›å¾ä¸€å¯æ‰§è¡Œç±»åQˆmainæ–ÒŽ³•åQ‰ï¼Œåœ¨å…¶ä¸­åŠ å…¥å¦‚ä¸‹ä»£ç ï¼š

 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¾c»è²å…¥å†…存,ž®†å…¶å¼ºåˆ¶è½¬åž‹ä¸ºtestInterface包中的ActionInterface¾cÕdž‹åQŒæœ€åŽè°ƒç”¨å…¶actionæ–ÒŽ³•åQŒåƈ打印到控制台中ã€?/p>

  执行½E‹åºåŽï¼Œåœ¨æŽ§åˆ¶å°ä¸Šå¦‚期打印出我们惌™¦çš„内宏V€‚但是,事情òq¶æ²¡æœ‰é‚£ä¹ˆç®€å•,当我们将该代码移动web应用中时åQŒå°±ä¼šæŠ›å‡ºå¼‚常。原来,Java为我们提供了三种可选择的ClassLoaderåQ?br /> 1. ¾pȝ»Ÿ¾cÕdŠ è½½å™¨æˆ–å«ä½œåº”ç”¨ç±»åŠ è²å™?(system classloader or application classloader)
2. 当前¾cÕdŠ è½½å™¨
3. 当前¾U¿ç¨‹¾cÕdŠ è½½å™¨

  在上例中我们使用javac命ä×o来运行该½E‹åºåQŒè¿™æ—¶å€™ä‹É用的是系¾lŸç±»åŠ è²å™?(system classloader)。这个类加蝲器处ç?-classpath下的¾cÕdŠ è½½å·¥ä½œï¼Œå¯ä»¥é€šè¿‡ClassLoader.getSystemClassLoader()æ–ÒŽ³•调用ã€?ClassLoader 下所有的 getSystemXXX()的静态方法都是通过˜q™ä¸ªæ–ÒŽ³•定义的。在代码中,应该ž®½é‡ž®‘地调用˜q™ä¸ªæ–ÒŽ³•åQŒä»¥å…¶å®ƒçš„类加蝲器作ä¸ÞZ»£ç†ã€‚否则代码将只能工作在简单的命ä×o行应用中。当在web应用中时åQŒæœåŠ¡å™¨ä¹Ÿæ˜¯åˆ©ç”¨ClassLoader来加载class的,ç”׃ºŽClassLoader的不同,所以在强制转型时JVM认定不是同一¾cÕdž‹ã€‚(在JAVA中,一个类用其完全匚w…¾cÕd(fully qualified class name)ä½œäØ“æ ‡è¯†åQŒè¿™é‡ŒæŒ‡çš„完全匹配类名包括包名和¾cÕdã€‚但在JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识。因此,如果一个名为Pg的包中,有一个名为Cl的类åQŒè¢«¾cÕdŠ è½½å™¨KlassLoader的一个实例kl1加蝲åQŒCl的实例,即C1.class在JVM中表½CÞZØ“(Cl, Pg, kl1)。这意味着两个¾cÕdŠ è½½å™¨çš„å®žä¾?Cl, Pg, kl1) å’?(Cl, Pg, kl2)是不同的åQŒè¢«å®ƒä»¬æ‰€åŠ è²çš„ç±»ä¹Ÿå› æ­¤å®Œå…¨ä¸åŒï¼Œäº’ä¸å…¼å®¹çš„ã€‚ï¼‰ä¸ÞZº†èƒ½å¤Ÿä½¿ç¨‹åºæ­£¼‹®è¿è¡Œï¼Œæˆ‘们首要解决的问题就是,如何ž®†URLClassLoader加蝲的类åQŒåŒå½“前ClassLoader保持在同一¾cÕdŠ è½½å™¨ä¸­ã€‚è§£å†Ïx–¹æ³•很½Ž€å•,利用java提供的第三种ClassLoader—当前线½E‹ç±»åŠ è²å™¨å³å¯ã€‚jdk api文档ž®×ƒ¼šå‘现åQŒURLClassLoader提供了三¿Uæž„造方式:

 // 使用默认的委托父 ClassLoader 为指定的 URL 构造一个新 URLClassLoaderã€?nbsp;
 URLClassLoader(URL[] urls)
// 为给定的 URL 构造新 URLClassLoader�nbsp;
URLClassLoader(URL[] urls, ClassLoader parent)
// 为指定的 URL、父¾cÕdŠ è½½å™¨å’?URLStreamHandlerFactory 创徏æ–?URLClassLoaderã€?
 URLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) 
接下来要做的ž®±æ˜¯åQŒåœ¨æž„造URLClassLoaderæ—Óž¼Œž®†å½“前线½E‹ç±»åŠ è²å™¨ç½®å…¥å³å¯ã€‚å¦‚ä¸‹ï¼š

URLClassLoader myClassLoader  =   new  URLClassLoader( new  URL[]  { url } , Thread.currentThread().getContextClassLoader());
æ€È»“åQ?br />   Java是利用ClassLoader来加载类到内存的åQŒClassLoader本èín是用java语言写的åQŒæ‰€ä»¥æˆ‘们可以扩展自å·Þqš„ClassLoader。利用URLClassLoader可以加蝲指定jar包中的类到内存。在命行上利用URLClassLoader加蝲jaræ—Óž¼Œæ˜¯ä‹É用系¾lŸç±»åŠ è²å™¨æ¥åŠ è²class的,所以在web环境下,ž®×ƒ¼šå‡ºé”™ã€‚这是因为JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识的。我们只要利用URLClassLoaderçš„ç¬¬äºŒç§æž„é€ æ–¹æ³•åÆˆä¼ å…¥å½“å‰¾U¿ç¨‹¾cÕdŠ è½½å™¨å›_¯è§£å†³ã€?/p>

]]>
了解Java ClassLoaderhttp://www.aygfsteel.com/boluobn/archive/2008/01/25/177748.html菠萝菠萝Fri, 25 Jan 2008 05:52:00 GMThttp://www.aygfsteel.com/boluobn/archive/2008/01/25/177748.htmlhttp://www.aygfsteel.com/boluobn/comments/177748.htmlhttp://www.aygfsteel.com/boluobn/archive/2008/01/25/177748.html#Feedback0http://www.aygfsteel.com/boluobn/comments/commentRss/177748.htmlhttp://www.aygfsteel.com/boluobn/services/trackbacks/177748.html 
【原文地址åQšhttps://www6.software.ibm.com/developerworks/cn/education/java/j-classloader/tutorial/ã€?br /> 1.介绍
2.ClassLoader的结�br /> 3.Compiling ClassLoader
4.java2 中ClassLoader的变�br /> 5.源代�br /> ---------------------------------------------------------------------------

½W¬ä¸€ç«?介绍

什么是 ClassLoader

在流行的商业化编½E‹è¯­­a€ä¸­ï¼ŒJava 语言ç”׃ºŽåœ?Java 虚拟æœ?(JVM) 上运行而显得与众不同。这意味着已编译的½E‹åºæ˜¯ä¸€¿Uç‰¹ŒDŠçš„、独立于òq›_°çš„æ ¼å¼ï¼Œòq‰™žä¾èµ–于它们所˜qè¡Œçš„æœºå™¨ã€‚在很大½E‹åº¦ä¸Šï¼Œ˜q™ç§æ ¼å¼ä¸åŒäºŽä¼ ¾lŸçš„可执行程序格式ã€?

ä¸?C æˆ?C++ ¾~–写的程序不同,Java ½E‹åºòq¶ä¸æ˜¯ä¸€ä¸ªå¯æ‰§è¡Œæ–‡äšgåQŒè€Œæ˜¯ç”Þp®¸å¤šç‹¬ç«‹çš„¾cÀL–‡ä»¶ç»„成,每一个文件对应于一ä¸?Java ¾c…R€?

此外åQŒè¿™äº›ç±»æ–‡äšgòq‰™žç«‹å³å…¨éƒ¨éƒ½è£…入内存,而是æ ÒŽ®½E‹åºéœ€è¦è£…入内存。ClassLoader æ˜?JVM 中将¾c»è£…入内存的那部分ã€?

而且åQŒJava ClassLoader ž®±æ˜¯ç”?Java 语言¾~–写的。这意味着创徏您自å·Þqš„ ClassLoader 非常å®ÒŽ˜“åQŒä¸å¿…了è§?JVM 的微ž®ç»†èŠ‚ã€?

ä¸ÞZ»€ä¹ˆç¼–å†?ClassLoader?

如果 JVM 已经有一ä¸?ClassLoaderåQŒé‚£ä¹ˆäؓ什么还要编写另一个呢åQŸé—®å¾—好。缺省的 ClassLoader 只知道如何从本地文äšg¾pȝ»Ÿè£…å…¥¾cÀL–‡ä»¶ã€‚不˜q‡è¿™åªé€‚合于常规情况,卛_·²å…¨éƒ¨¾~–译å®?Java ½E‹åºåQŒåƈ且计½Ž—机处于½{‰å¾…状态ã€?

ä½?Java 语言最å…äh–°æ„çš„事就æ˜?JVM 可以非常å®ÒŽ˜“åœîC»Žé‚£äº›éžæœ¬åœ°ç¡¬ç›˜æˆ–从网¾lœä¸ŠèŽ·å–¾c…R€‚例如,‹¹è§ˆè€…可以ä‹É用定制的 ClassLoader ä»?Web 站点装入可执行内宏V€?

有许多其它方式可以获取类文äšg。除了简单地从本地或¾|‘络装入文äšg以外åQŒå¯ä»¥ä‹É用定制的 ClassLoader 完成以下ä»ÕdŠ¡åQ?

  • 在执行非¾|®ä¿¡ä»£ç ä¹‹å‰åQŒè‡ªåŠ¨éªŒè¯æ•°å­—ç­¾å?
  • 使用用户提供的密码透明地解密代ç ?
  • 动态地创徏½W¦åˆç”¨æˆ·ç‰¹å®šéœ€è¦çš„定制化构建类
ä»ÖM½•您认为可以生æˆ?Java 字节码的内容都可以集成到应用½E‹åºä¸­ã€?/font>

定制 ClassLoader ½CÞZ¾‹

如果使用˜q?JDK 或ä“Q何基äº?Java ‹¹è§ˆå™¨ä¸­çš?Applet 查看器,那么您差不多肯定使用˜q‡å®šåˆ¶çš„ ClassLoaderã€?

Sun 最初发å¸?Java 语言æ—Óž¼Œå…¶ä¸­æœ€ä»¤äh兴奋的一件事是观看这™åÒŽ–°æŠ€æœ¯æ˜¯å¦‚何执行在运行时从远½E‹çš„ Web 服务器装入的代码。(此外åQŒè¿˜æœ‰æ›´ä»¤äh兴奋的事 -- Java 技术提供了一¿Uä¾¿äºŽç¼–写代码的强大语言。)更一些ä×o人激动的是它可以执行从远½E?Web 服务器通过 HTTP ˜qžæŽ¥å‘送过来的字节码ã€?

此项功能归功äº?Java 语言可以安装定制 ClassLoader。Applet 查看器包含一ä¸?ClassLoaderåQŒå®ƒä¸åœ¨æœ¬åœ°æ–‡äšg¾pȝ»Ÿä¸­å¯»æ‰„¡±»åQŒè€Œæ˜¯è®‰K—®˜qœç¨‹æœåŠ¡å™¨ä¸Šçš?Web 站点åQŒç»˜q?HTTP 装入原始的字节码文äšgåQŒåƈ把它们è{换成 JVM 内的¾c…R€?

‹¹è§ˆå™¨å’Œ Applet 查看器中çš?ClassLoaders ˜q˜å¯ä»¥åšå…¶å®ƒäº‹æƒ…åQšå®ƒä»¬æ”¯æŒå®‰å…¨æ€§ä»¥åŠä‹É不同çš?Applet 在不同的™åµé¢ä¸Šè¿è¡Œè€Œäº’不干扰ã€?

Luke Gorrie ¾~–写çš?Echidna 是一个开放源码包åQŒå®ƒå¯ä»¥ä½¿æ‚¨åœ¨å•个虚拟机上运行多ä¸?Java 应用½E‹åºã€‚(请参é˜?a >˜q›ä¸€æ­¥äº†è§£å’Œå‚考资æ–?/a>。)它ä‹É用定制的 ClassLoaderåQŒé€šè¿‡å‘每个应用程序提供该¾cÀL–‡ä»¶çš„自èín副本åQŒä»¥é˜²æ­¢åº”用½E‹åºäº’相òq²æ‰°ã€?


我们çš?ClassLoader ½CÞZ¾‹

了解äº?ClassLoader 如何工作以及如何¾~–写 ClassLoader 之后åQŒæˆ‘们将创徏¿UîC½œ CompilingClassLoader (CCL) çš?Classloader。CCL 为我们编è¯?Java 代码åQŒè€Œæ— éœ€è¦æˆ‘们干涉这个过½E‹ã€‚它基本上就¾cÖM¼¼äºŽç›´æŽ¥æž„建到˜qè¡Œæ—¶ç³»¾lŸä¸­çš?"make" ½E‹åºã€?

注:˜q›ä¸€æ­¥äº†è§£ä¹‹å‰ï¼Œåº”注意在 JDK 版本 1.2 中已改进äº?ClassLoader ¾pȝ»Ÿçš„æŸäº›æ–¹é¢ï¼ˆå?Java 2 òq›_°åQ‰ã€‚本教程是按 JDK 版本 1.0 å’?1.1 写的åQŒä½†ä¹Ÿå¯ä»¥åœ¨ä»¥åŽçš„版本中˜qè¡Œã€?/p>

Java 2 ä¸?ClassLoader 的变åŠ?/a>描述äº?Java 版本 1.2 中的变动åQŒåƈ提供了一些详¾l†ä¿¡æ¯ï¼Œä»¥ä¾¿ä¿®æ”¹ ClassLoader 来利用这些变动ã€?

 


 

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

½W¬äºŒç«?ClassLoader的结æž?/strong>



ClassLoader 的基本目标是对类的请求提供服务。当 JVM 需要ä‹É用类æ—Óž¼Œå®ƒæ ¹æ®å¿U°å‘ ClassLoader è¯äh±‚˜q™ä¸ª¾c»ï¼Œç„¶åŽ ClassLoader 试图˜q”回一个表½Cø™¿™ä¸ªç±»çš?Class 对象ã€?

通过覆盖对应于这个过½E‹ä¸åŒé˜¶ŒD늚„æ–ÒŽ³•åQŒå¯ä»¥åˆ›å»ºå®šåˆ¶çš„ ClassLoaderã€?

在本章的其余部分åQŒæ‚¨ä¼šå­¦ä¹?Java ClassLoader 的关键方法。您ž®†äº†è§£æ¯ä¸€ä¸ªæ–¹æ³•的作用以及它是如何适合装入¾cÀL–‡ä»¶è¿™ä¸ªè¿‡½E‹çš„。您也会知道åQŒåˆ›å»ø™‡ªå·Þqš„ ClassLoader æ—Óž¼Œéœ€è¦ç¼–写什么代码ã€?

在下一章中åQŒæ‚¨ž®†ä¼šåˆ©ç”¨˜q™äº›çŸ¥è¯†æ¥ä‹É用我们的 ClassLoader ½CÞZ¾‹ -- CompilingClassLoaderã€?


æ–ÒŽ³• loadClass


ClassLoader.loadClass() æ˜?ClassLoader 的入口点。其特征如下åQ?

 

Class loadClass( String name, boolean resolve );

name 参数指定äº?JVM 需要的¾cȝš„名称åQŒè¯¥åç§°ä»¥åŒ…表示法表½Cºï¼Œå¦?Foo æˆ?java.lang.Objectã€?

resolve 参数告诉æ–ÒŽ³•是否需要解析类。在准备执行¾cÖM¹‹å‰ï¼Œåº”考虑¾c»è§£æžã€‚åÆˆä¸æ€ÀL˜¯éœ€è¦è§£æžã€‚如æž?JVM 只需要知道该¾cÀL˜¯å¦å­˜åœ¨æˆ–扑ևºè¯¥ç±»çš„è¶…¾c»ï¼Œé‚£ä¹ˆž®×ƒ¸éœ€è¦è§£æžã€?

åœ?Java 版本 1.1 和以前的版本中,loadClass æ–ÒŽ³•是创建定制的 ClassLoader 时唯一需要覆盖的æ–ÒŽ³•。(Java 2 ä¸?ClassLoader 的变åŠ?/a>提供了关äº?Java 1.2 ä¸?findClass() æ–ÒŽ³•的信息。)


æ–ÒŽ³• defineClass

defineClass æ–ÒŽ³•æ˜?ClassLoader 的主要诀½Hã€‚该æ–ÒŽ³•接受由原始字节组成的数组òq¶æŠŠå®ƒè{换成 Class 对象。原始数¾l„包含如从文件系¾lŸæˆ–¾|‘络装入的数据ã€?

defineClass ½Ž¡ç† JVM 的许多复杂、神¿U˜å’Œå€šèµ–于实现的斚w¢ -- 它把字节码分析成˜qè¡Œæ—¶æ•°æ®ç»“构、校验有效性等½{‰ã€‚不必担心,您无需亲自¾~–写它。事实上åQŒå³ä½¿æ‚¨æƒŒ™¦˜q™ä¹ˆåšä¹Ÿä¸èƒ½è¦†ç›–å®ƒï¼Œå› äØ“å®ƒå·²è¢«æ ‡è®°æˆæœ€¾lˆçš„ã€?


æ–ÒŽ³• findSystemClass

findSystemClass æ–ÒŽ³•从本地文件系¾lŸè£…入文件。它在本地文件系¾lŸä¸­å¯ÀL‰¾¾cÀL–‡ä»Óž¼Œå¦‚果存在åQŒå°±ä½¿ç”¨ defineClass ž®†åŽŸå§‹å­—èŠ‚è{换成 Class 对象åQŒä»¥ž®†è¯¥æ–‡äšg转换成类。当˜qè¡Œ Java 应用½E‹åºæ—Óž¼Œ˜q™æ˜¯ JVM 正常装入¾cȝš„¾~ºçœæœºåˆ¶ã€‚(Java 2 ä¸?ClassLoader 的变åŠ?/a>提供了关äº?Java 版本 1.2 ˜q™ä¸ª˜q‡ç¨‹å˜åŠ¨çš„è¯¦¾l†ä¿¡æ¯ã€‚)

对于定制çš?ClassLoaderåQŒåªæœ‰åœ¨ž®è¯•其它æ–ÒŽ³•装入¾cÖM¹‹åŽï¼Œå†ä‹Éç”?findSystemClass。原因很½Ž€å•:ClassLoader 是负责执行装入类的特ŒDŠæ­¥éª¤ï¼Œä¸æ˜¯è´Ÿè´£æ‰€æœ?/em>¾c…R€‚例如,即ä‹É ClassLoader 从远½E‹çš„ Web 站点装入了某些类åQŒä»ç„‰™œ€è¦åœ¨æœ¬åœ°æœºå™¨ä¸Šè£…入大量的基本 Java 库。而这些类不是我们所兛_¿ƒçš„,所以要 JVM 以缺省方式装入它们:从本地文件系¾lŸã€‚è¿™ž®±æ˜¯ findSystemClass 的用途ã€?

其工作流½E‹å¦‚下:

 

  • è¯äh±‚定制çš?ClassLoader 装入¾c…R€?
  • ‹‚€æŸ¥è¿œ½E?Web 站点åQŒæŸ¥çœ‹æ˜¯å¦æœ‰æ‰€éœ€è¦çš„¾c…R€?
  • 如果有,那么好;抓取˜q™ä¸ª¾c»ï¼Œå®Œæˆä»ÕdŠ¡ã€?
  • 如果没有åQŒå‡å®šè¿™ä¸ªç±»æ˜¯åœ¨åŸºæœ¬ Java 库中åQŒé‚£ä¹ˆè°ƒç”?findSystemClassåQŒä‹É它从文äšg¾pȝ»Ÿè£…入该类ã€?

在大多数定制 ClassLoaders 中,首先调用 findSystemClass 以节省在本地ž®±å¯ä»¥è£…入的许多 Java 库类而要在远½E?Web 站点上查找所èŠÞqš„æ—‰™—´ã€‚然而,正如åQŒåœ¨ä¸‹ä¸€ç« èŠ‚æ‰€çœ‹åˆ°çš„ï¼Œç›´åˆ°¼‹®ä¿¡èƒ½è‡ªåŠ¨ç¼–è¯‘æˆ‘ä»¬çš„åº”ç”¨½E‹åºä»£ç æ—Óž¼Œæ‰è®© JVM 从本地文件系¾lŸè£…入类ã€?


æ–ÒŽ³• resolveClass

正如前面所提到的,可以不完全地åQˆä¸å¸¦è§£æžï¼‰è£…å…¥¾c»ï¼Œä¹Ÿå¯ä»¥å®Œå…¨åœ°åQˆå¸¦è§£æžåQ‰è£…入类。当¾~–写我们自己çš?loadClass æ—Óž¼Œå¯ä»¥è°ƒç”¨ resolveClassåQŒè¿™å–决äº?loadClass çš?resolve 参数的倹{€?/font>

æ–ÒŽ³• findLoadedClass

findLoadedClass 充当一个缓存:当请æ±?loadClass 装入¾cÀL—¶åQŒå®ƒè°ƒç”¨è¯¥æ–¹æ³•来查看 ClassLoader 是否已装入这个类åQŒè¿™æ ·å¯ä»¥é¿å…é‡æ–°è£…入已存在¾cÀL‰€é€ æˆçš„麻烦。应首先调用该方法ã€?/font>

¾l„装

 

 

 

让我们看一下如何组装所有方法�

我们çš?loadClass 实现½CÞZ¾‹æ‰§è¡Œä»¥ä¸‹æ­¥éª¤ã€‚(˜q™é‡ŒåQŒæˆ‘们没有指定生成类文äšg是采用了哪种技æœ?-- 它可以是ä»?Net 上装入、或者从归档文äšg中提取、或者实时编译。无论是哪一¿Uï¼Œé‚£æ˜¯¿Uç‰¹ŒDŠçš„¼œžå¥‡æ–¹å¼åQŒä‹É我们获得了原始类文äšg字节。)

 

  • 调用 findLoadedClass 来查看是否存在已装入的类ã€?br x="7" />
  • 如果没有åQŒé‚£ä¹ˆé‡‡ç”¨é‚£¿Uç‰¹ŒDŠçš„¼œžå¥‡æ–¹å¼æ¥èŽ·å–åŽŸå§‹å­—èŠ‚ã€?br x="7" />
  • 如果已有原始字节åQŒè°ƒç”?defineClass ž®†å®ƒä»¬è{换成 Class 对象ã€?br x="7" />
  • 如果没有原始字节åQŒç„¶åŽè°ƒç”?findSystemClass 查看是否从本地文件系¾lŸèŽ·å–ç±»ã€?br x="7" />
  • 如果 resolve 参数æ˜?trueåQŒé‚£ä¹ˆè°ƒç”?resolveClass 解析 Class 对象ã€?br x="7" />
  • 如果˜q˜æ²¡æœ‰ç±»åQŒè¿”å›?ClassNotFoundExceptionã€?br x="7" />
  • 否则åQŒå°†¾c»è¿”回给调用½E‹åºã€?
推想

现在您已¾läº†è§£äº† ClassLoader 的工作原理,现在该构å»ÞZ¸€ä¸ªäº†ã€‚在下一章中åQŒæˆ‘们将讨论 CCLã€?br />
---------------------------------------------------------------------------------------------

½W¬ä¸‰ç« ï¼šCompiling ClassLoader

CCL 揭密

我们çš?ClassLoader (CCL) çš„ä“Q务是¼‹®ä¿ä»£ç è¢«ç¼–译和更新ã€?

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

 

  • 当请求一个类æ—Óž¼Œå…ˆæŸ¥çœ‹å®ƒæ˜¯å¦åœ¨ç£ç›˜çš„当前目录或相应的子目录ã€?br x="7" />
  • 如果该类不存在,但源码中有,那么调用 Java ¾~–译器来生成¾cÀL–‡ä»¶ã€?br x="7" />
  • 如果该类已存在,‹‚€æŸ¥å®ƒæ˜¯å¦æ¯”源码旧。如果是åQŒè°ƒç”?Java ¾~–译器来重新生成¾cÀL–‡ä»¶ã€?br x="7" />
  • 如果¾~–译å¤ÞpÓ|åQŒæˆ–者由于其它原因不能从现有的源码中生成¾cÀL–‡ä»Óž¼Œ˜q”回 ClassNotFoundExceptionã€?br x="7" />
  • 如果仍然没有该类åQŒä¹Ÿè®¸å®ƒåœ¨å…¶å®ƒåº“中,所以调ç”?findSystemClass 来寻找该¾c…R€?br x="7" />
  • 如果˜q˜æ˜¯æ²¡æœ‰åQŒåˆ™˜q”回 ClassNotFoundExceptionã€?br x="7" />
  • 否则åQŒè¿”回该¾c…R€?
Java ¾~–译的工作方å¼?/strong>

 

在深入讨è®ÞZ¹‹å‰ï¼Œåº”该先退一步,讨论 Java ¾~–译。通常åQŒJava ¾~–译器不只是¾~–译您要求它¾~–译的类。它˜q˜ä¼š¾~–译其它¾c»ï¼Œå¦‚æžœ˜q™äº›¾cÀL˜¯æ‚¨è¦æ±‚编译的¾cÀL‰€éœ€è¦çš„¾c…R€?

CCL 逐个¾~–译应用½E‹åºä¸­çš„需要编译的每一个类。但一般来è¯ß_¼Œåœ¨ç¼–译器¾~–译完第一个类后,CCL 会查找所有需要编译的¾c»ï¼Œç„¶åŽ¾~–è¯‘å®ƒã€‚äØ“ä»€ä¹ˆï¼ŸJava ¾~–译器类ä¼égºŽæˆ‘们正在使用的规则:如果¾cÖM¸å­˜åœ¨åQŒæˆ–者与它的源码相比åQŒå®ƒæ¯”较旧,那么它需要编译。其实,Java ¾~–译器在 CCL 之前的一个步骤,它会做大部分的工作ã€?

å½?CCL ¾~–译它们æ—Óž¼Œä¼šæŠ¥å‘Šå®ƒæ­£åœ¨¾~–译哪个应用½E‹åºä¸Šçš„¾c…R€‚在大多数的情况下,CCL 会在½E‹åºä¸­çš„ä¸È±»ä¸Šè°ƒç”¨ç¼–译器åQŒå®ƒä¼šåšå®Œæ‰€æœ‰è¦åšçš„ -- ¾~–译器的单一调用已èƒö够了ã€?

然而,有一¿Uæƒ…形,在第一步时不会¾~–译某些¾c…R€‚如果ä‹Éç”?Class.forName æ–ÒŽ³•åQŒé€šè¿‡åç§°æ¥è£…入类åQŒJava ¾~–译器会不知道这个类时所需要的。在˜q™ç§æƒ…况下,您会看到 CCL 再次˜qè¡Œ Java ¾~–译器来¾~–译˜q™ä¸ª¾c…R€‚在源代ç ?/a>中演½CÞZº†˜q™ä¸ª˜q‡ç¨‹ã€?

使用 CompilationClassLoader

要ä‹Éç”?CCLåQŒå¿…™åÖM»¥ç‰Òޮп–¹å¼è°ƒç”¨½E‹åºã€‚不能直接运行该½E‹åºåQŒå¦‚åQ?

 

% java Foo arg1 arg2

应以下列方式˜qè¡Œå®ƒï¼š

 

% java CCLRun Foo arg1 arg2

CCLRun 是一个特ŒDŠçš„存根½E‹åºåQŒå®ƒåˆ›å¾ CompilingClassLoader òq¶ç”¨å®ƒæ¥è£…å…¥½E‹åºçš„主¾c»ï¼Œä»¥ç¡®ä¿é€šè¿‡ CompilingClassLoader 来装入整个程序。CCLRun 使用 Java Reflection API 来调用特定类的主æ–ÒŽ³•òq¶æŠŠå‚数传递给它。有兌™¯¦¾l†ä¿¡æ¯ï¼Œè¯·å‚é˜?a >源代ç ?/a>ã€?

˜qè¡Œ½CÞZ¾‹

源码包括了一¾l„小¾c»ï¼Œå®ƒä»¬æ¼”示了工作方式。主½E‹åºæ˜?Foo ¾c»ï¼Œå®ƒåˆ›å»ºç±» Bar 的实例。类 Bar 创徏另一个类 Baz 的实例,它在 baz 包内åQŒè¿™æ˜¯äؓ了展½C?CCL 是如何处理子包里的代码ã€?code style="font-size: 12px; font-family: Courier New,Courier,monospace">Bar 也是通过名称装入的,其名¿UîCØ“ BooåQŒè¿™ç”¨æ¥å±•示它也能与 CCL 工作ã€?

每个¾c»éƒ½å£°æ˜Žå·²è¢«è£…å…¥òq¶è¿è¡Œã€‚现在用源代ç ?/a>来试一下。编è¯?CCLRun å’?CompilingClassLoader。确保不要编译其它类åQ?code style="font-size: 12px; font-family: Courier New,Courier,monospace">Fooã€?code style="font-size: 12px; font-family: Courier New,Courier,monospace">Barã€?code style="font-size: 12px; font-family: Courier New,Courier,monospace">Baz å’?BooåQ‰ï¼Œå¦åˆ™ž®†ä¸ä¼šä‹Éç”?CCLåQŒå› ä¸ø™¿™äº›ç±»å·²ç»¾~–译˜q‡äº†ã€?

 


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

è¯äh³¨æ„ï¼Œé¦–先调用¾~–译器,Foo.java ½Ž¡ç† Bar å’?baz.Baz。直åˆ?Bar 通过名称来装å…?Boo æ—Óž¼Œè¢«è°ƒç”¨å®ƒåQŒè¿™æ—?CCL 会再‹Æ¡è°ƒç”¨ç¼–译器来编译它ã€?

 

 

 

 

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

½W¬å››ç« ï¼šjava2 中ClassLoader的变åŠ?/strong>


概述

åœ?Java 版本 1.2 和以后的版本中,å¯?ClassLoader 做了一些改˜q›ã€‚ä“Qä½•äØ“è€ç³»¾lŸç¼–写的代码可以在新版本中运行,但新¾pȝ»Ÿä¸ºæ‚¨æä¾›äº†ä¸€äº›ä¾¿åˆ©ã€?

新模型是委托模型åQŒè¿™æ„å‘³ç€å¦‚æžœ ClassLoader 不能扑ֈ°¾c»ï¼Œå®ƒä¼šè¯äh±‚父代 ClassLoader 来执行此™å¹ä“Q务。所æœ?ClassLoaders 的根是系¾l?ClassLoaderåQŒå®ƒä¼šä»¥¾~ºçœæ–¹å¼è£…å…¥¾c?-- 卻I¼Œä»Žæœ¬åœ°æ–‡ä»¶ç³»¾lŸã€?

loadClass 的缺省实�/strong>

定制¾~–写çš?loadClass æ–ÒŽ³•一般尝试几¿Uæ–¹å¼æ¥è£…入所è¯äh±‚的类åQŒå¦‚果您¾~–写许多¾c»ï¼Œä¼šå‘çŽîC¸€‹Æ¡æ¬¡åœ°åœ¨ç›¸åŒçš„、很复杂的方法上¾~–写变量ã€?

åœ?Java 1.2 ä¸?loadClass 的实现嵌入了大多数查扄¡±»çš„一般方法,òq¶ä‹É您通过覆盖 findClass æ–ÒŽ³•来定制它åQŒåœ¨é€‚当的时å€?findClass 会调ç”?loadClassã€?

˜q™ç§æ–¹å¼çš„好处是您可能不一定要覆盖 loadClassåQ›åªè¦è¦†ç›?findClass ž®Þp¡Œäº†ï¼Œ˜q™å‡ž®‘了工作量ã€?

新方法:findClass

loadClass 的缺省实现调用这个新æ–ÒŽ³•ã€?code style="font-size: 12px; font-family: Courier New,Courier,monospace">findClass 的用途包含您çš?ClassLoader 的所有特ŒDŠä»£ç ï¼Œè€Œæ— éœ€è¦å¤åˆ¶å…¶å®ƒä»£ç ï¼ˆä¾‹å¦‚åQŒå½“专门的方法失败时åQŒè°ƒç”¨ç³»¾l?ClassLoaderåQ‰ã€?/font>

新方法:getSystemClassLoader

如果覆盖 findClass æˆ?loadClassåQ?code style="font-size: 12px; font-family: Courier New,Courier,monospace">getSystemClassLoader 使您能以实际 ClassLoader 对象来访问系¾l?ClassLoaderåQˆè€Œä¸æ˜¯å›ºå®šçš„ä»?findSystemClass 调用它)ã€?/font>

新方法:getParent

ä¸ÞZº†ž®†ç±»è¯äh±‚委托¾l™çˆ¶ä»?ClassLoaderåQŒè¿™ä¸ªæ–°æ–ÒŽ³•允许 ClassLoader 获取它的父代 ClassLoader。当使用ç‰Òޮп–ÒŽ³•åQŒå®šåˆ¶çš„ ClassLoader 不能扑ֈ°¾cÀL—¶åQŒå¯ä»¥ä‹É用这¿Uæ–¹æ³•ã€?

父代 ClassLoader 被定义成创徏�ClassLoader 所包含代码的对象的 ClassLoader�

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

 

 

 

½W¬äº”ç«?源代ç ?/strong>

 

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!" );
}
}



]]>eclipse配置weblogic(�http://www.aygfsteel.com/boluobn/archive/2008/01/24/177510.html菠萝菠萝Thu, 24 Jan 2008 07:33:00 GMThttp://www.aygfsteel.com/boluobn/archive/2008/01/24/177510.htmlhttp://www.aygfsteel.com/boluobn/comments/177510.htmlhttp://www.aygfsteel.com/boluobn/archive/2008/01/24/177510.html#Feedback0http://www.aygfsteel.com/boluobn/comments/commentRss/177510.htmlhttp://www.aygfsteel.com/boluobn/services/trackbacks/177510.html安装WebLogic8.1
安装WebLogic比较å®ÒŽ˜“åQŒåœ¨˜q™é‡Œž®×ƒ¸å†ç¯˜qîCº†åQŒå¤§å®¶å¯ä»¥å‚阅相å…Ïx–‡æ¡£ã€‚现在着重讲一下WebLogic的配¾|®ï¼Œå› äؓ后面在配¾|®MyEclipse时将用到˜q™é‡Œçš„æœ‰å…³ä¿¡æ¯ã€?
(1)˜qè¡Œå¼€å§‹\½E‹åº\BEA WebLogic PlatFORM 8.1\Configuration Wizardã€?
(2)选择Create a new WebLogic configurationåQŒä¸‹ä¸€æ­¥ã€?
(3)选择Basic WebLogic Server DomainåQŒä¸‹ä¸€æ­¥ã€?
(4)选择CustomåQŒä¸‹ä¸€æ­¥ã€?
(5)在Name处输入adminåQŒListen Address处选择localhoståQŒä»¥ä¸‹ä¸¤ä¸ªPort均采用默认å€û|¼Œä¸‹ä¸€æ­¥ã€?
(6)选择Skipè·Œ™¿‡Multiple ServersåQŒClustersåQŒand Machines OptionsåQŒä¸‹ä¸€æ­¥ã€?
(7)选择Skipè·Œ™¿‡JDBC˜qžæŽ¥æ± çš„配置åQˆæ³¨åQšJDBC˜qžæŽ¥æ± çš„配置可以在启动WebLogic后到控制åîC¸Š˜q›è¡ŒåQŒå¤§å®¶å¯ä»¥å‚阅相å…Ïx–‡æ¡£ï¼‰åQŒä¸‹ä¸€æ­¥ã€?
(选择Skipè·Œ™¿‡JMS的配¾|®ï¼ˆåŒæ ·ç•™åˆ°æŽ§åˆ¶åîC¸Šåšï¼‰åQŒä¸‹ä¸€æ­¥ã€?
(9)¾l§ç®‹è·Œ™¿‡åQŒä¸‹ä¸€æ­¥ã€?
(10)选择YesåQŒä¸‹ä¸€æ­¥ã€?
(11)在User™å늂¹å‡»AddåQŒéšæ„æ·»åŠ ä¸€ä¸ªç”¨æˆ·useråQŒå¯†ç ?2345678åQŒä¸‹ä¸€æ­¥ã€?
(12)ž®†ç”¨æˆ·user分配到Administrators¾l„(˜q˜å¯ä»¥åŒæ—¶åˆ†é…åˆ°å…¶å®ƒ¾l„,æ–ÒŽ³•是选中待加入的¾l„,然后勾中user前的复选框卛_¯åQ‰ï¼Œä¸‹ä¸€æ­¥ã€?
(13)直接点击下一步蟩˜q‡ã€?
(14)讄¡½®ç”¨æˆ·user的权限,选中AdminåQŒå‹¾ä¸­user前的复选框åQˆè¦æŒ‡å®šå…¶å®ƒæƒé™ä¾æ¬¡¾cÀLލåQ‰ï¼Œä¸‹ä¸€æ­¥ã€?
(15)采用默认讄¡½®åQŒç›´æŽ¥ç‚¹å‡ÖM¸‹ä¸€æ­¥èŸ©˜q‡ã€?
(16)同样采用默认讄¡½®åQŒç›´æŽ¥ç‚¹å‡ÖM¸‹ä¸€æ­¥èŸ©˜q‡ã€?
(17)配置JDKåQŒé‡‡ç”¨WebLogic的默认å€û|¼Œç›´æŽ¥ç‚¹å‡»ä¸‹ä¸€æ­¥èŸ©˜q‡ã€?
(1最后在Configuration Name处输入devåQŒç„¶åŽç‚¹å‡»Create生成配置åQŒå®Œæ¯•点击Done关闭Configuration Wizard对话框ã€?
5.配置MyEclipse的WebLogic服务�
MyEclipse默认的应用服务器为JBoss3åQŒè¿™é‡Œæˆ‘们ä‹É用WebLogic8.1。启动EclipseåQŒé€‰æ‹©“½H—口\首选项”菜单åQŒæ‰“开首选项对话框。展开MyEclipse下的Application Servers¾l“点åQŒç‚¹å‡»JBoss 3åQŒé€‰ä¸­å³é¢çš„Disable单选按钮,停用JBoss 3。然后点击WebLogic 8åQŒé€‰ä¸­åŒ™¾¹çš„Enable单选按钮,启用WebLogic服务器。同时下面的配置如下åQ?
(1)BEA home directoryåQšD:\BEA。假定WebLogic安装在D:\BEAæ–‡äšg夹中ã€?
(2)WebLogic installation directoryåQšD:\BEA\weblogic81ã€?
(3)Admin usernameåQšuserã€?
(4)Admin passwordåQ?2345678ã€?
(5)Execution domain rootåQšD:\BEA\user_projects\devã€?
(6)Execution domain nameåQšdevã€?
(7)Execution server nameåQšadminã€?
(8)Hostname:PortNumberåQšlocalhost:7001ã€?
(9)Security policy fileåQšD:\BEA\weblogic81\server\lib\weblogic.policyã€?
(10)JAAS login configuration fileåQšçœç•¥ã€?
接着展开WebLogic 8¾l“点åQŒç‚¹å‡»JDKåQŒåœ¨åŒ™¾¹çš„WLS JDK name处选择WebLogic 8的默认JDKã€‚è¿™é‡Œç»„åˆæ¡†ä¸­ç¼ºçœäØ“j2re1.4.2_03åQŒå³ä¹‹å‰å•独安装的jre。单击Add按钮åQŒå¼¹å‡ºWebLogic > Add JVM对话框,在JRE名称处随便输入一个名字,如jre1.4.1_02。然后在JREä¸È›®å½•处选择WebLogic安装文äšg夹中的JDKæ–‡äšg夹,如D:\BEA\jdk141_02åQŒç¨‹åºä¼šè‡ªåЍ填充Javadoc URL文本框和JRE¾pȝ»Ÿåº“列表框。单å‡È¡®å®šæŒ‰é’®å…³é—­å¯¹è¯æ¡†ã€‚这时候就可以在WLS JDK name¾l„合框中选择jre1.4.1_02了。之后还要在下面的Optional Java VM argumentsåQŒå¦‚-ms64m -mx64m -Djava.library.path="D:/BEA/weblogic81/server/bin" -Dweblogic.management.discover=false -Dweblogic.ProductionModeEnabled=false
最后点击PathsåQŒåœ¨åŒ™¾¹çš„Prepend to classpath列表框中åQŒé€šè¿‡Add JAR/ZIP按钮åQŒåŠ å…¥D:\BEA\weblogic81\server\lib\weblogic.jar、D:\BEA\weblogic81\server\lib\webservices.jar。如果用到数据库åQŒè¿˜éœ€æŠŠæ•°æ®åº“的驱动类库加˜q›æ¥åQŒè¿™é‡Œæˆ‘们用WebLogic自带的SQL Server数据库驱动库D:\BEA\weblogic81\server\lib\mssqlserver4v65.jarã€?
è‡Ïx­¤åQŒMyEclipse中WebLogic8的配¾|®å·¥ä½œå°±½Ž—完成了。下面可以看看在Eclipse中能否启动WebLogic了?自从安装了MyEclipse之后åQŒEclipse工具栏中ž®×ƒ¼šæœ‰ä¸€ä¸ªRun/Stop Servers下拉按钮。点击该按钮的下拉部分,选择“WebLogic 8\Start”菜单åQŒå³å¼€å§‹å¯åЍWebLogic了。通过查看下面的控制台消息åQŒå°±å¯ä»¥çŸ¥é“启动是否成功åQŒæˆ–有什么异常发生。停止WebLogic可选择“WebLogic\Stop”菜单ã€?nbsp;



]]>J2EE配置WebLogic-Eclipse插äšg(è½?http://www.aygfsteel.com/boluobn/archive/2008/01/24/177508.html菠萝菠萝Thu, 24 Jan 2008 07:32:00 GMThttp://www.aygfsteel.com/boluobn/archive/2008/01/24/177508.htmlhttp://www.aygfsteel.com/boluobn/comments/177508.htmlhttp://www.aygfsteel.com/boluobn/archive/2008/01/24/177508.html#Feedback0http://www.aygfsteel.com/boluobn/comments/commentRss/177508.htmlhttp://www.aygfsteel.com/boluobn/services/trackbacks/177508.html服务å™?/a>¾c»èµ\径和JVM选项后,卛_¯é€šè¿‡Eclipse IDE配置和管理WebLogic Server.

  概述

  J2EE开发äh员经帔Rœ€è¦ç®¡ç†WebLogic Serveròq¶è°ƒè¯•WebLogic Server上部¾|²çš„应用½E‹åºã€?WebLogic Server½Ž¡ç†æŽ§åˆ¶å°è™½ç„¶èƒ½å¤Ÿå¯åŠ¨å’Œåœæ­¢WebLogic ServeråQŒå´ä¸èƒ½è®„¡½®JVM选项å’?a class="channel_keylink" target="_blank">服务å™?/a>¾c»èµ\径。必™åÖM‹É用startWebLogic脚本来设¾|®JVM选项和服务器¾c»èµ\径。而要调试WebLogic Server上部¾|²çš„应用½E‹åºåQŒåˆ™éœ€è¦å¸¦˜qœç¨‹è°ƒè¯•器的IDE.有了WebLogic插äšg后,ž®±å¯ä»¥é€šè¿‡Eclipse IDE½Ž¡ç†WebLogic Server. 在文本中åQŒæˆ‘们将开发一个包括会话EJBå’Œservletçš„J2EE应用½E‹åºã€é€šè¿‡Eclipse IDE在WebLogic Server中部¾|²åº”用程序、在Eclipse中调试应用程序ã€?/p>

  安装准备

  下蝲òq¶å®‰è£…Eclipse 3.0 IDEåQ?a >www.eclipse.org

  下蝲òq¶å®‰è£…WebLogic Server 8.1åQ?/p>

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

  安装WebLogic-Eclipse插äšg

  现在安装WebLogic-Eclipse IDE.在Eclipse IDE上,选择Help>Software Updates>Find and InstallåQŒå°†æ˜„¡¤ºInstall/Update½H—体。选择Search for new features to installåQŒç„¶åŽå•击Next按钮。在昄¡¤ºçš„Install½H—体中,单击New Remote Site按钮指定要从其安装插件的更新Web站点。在New Update Site½H—体中,指定名称和安装WebLogic-Eclipse插äšgçš„URL.WebLogic-Eclipse插äšgçš„URLæ˜?

  选择许可条款òq¶å•击Next按钮。在Install location½H—体中指定将安装WebLogic-Eclipse插äšg的目录。单击Finish按钮完成WebLogic插äšg的配¾|®ã€‚在昄¡¤ºçš„JAR Verification½H—体中,单击Install按钮安装WebLogic-Eclipse插äšg。重启Eclipse工作台完成插件安装。现在WebLogic-Eclipse插äšg便安装在 Eclipse IDE中了。Eclipse中新æ·ÖMº†Run>Start WebLogicå’ŒRun>Stop WebLogic两个功能ã€?/p>

  配置WebLogic-Eclipse插äšg

  安装了WebLogic-Eclipse插äšg后,我们ž®†åœ¨Eclipse IDE中配¾|®è¯¥æ’äšg。首先,创徏一个用于配¾|®WebLogic插äšg的项目。选择File>New>Project.在New Project½H—体中选择Java>Java ProjectåQŒç„¶åŽå•击Next按钮。在Create a Java project½H—体中指定项目名¿UŽÍ¼Œç„¶åŽå•击Next按钮。在Java Settings½H—体䏭䨓™å¹ç›®æ·ÕdŠ æºæ–‡ä»¶å¤¹ã€‚å•å‡»Add Folder按钮。在New Source Folder½H—体中指定文件夹名称。出çŽîC¸€ä¸ªæ¶ˆæ¯çª—体提½Cø™®¾¾|®binæ–‡äšgå¤¹ä½œä¸ºæž„å»ø™¾“出文件夹。接下来åQŒæ·»åŠ é¡¹ç›®æ‰€éœ€çš„åº“ã€‚ç¤ºä¾‹åº”ç”¨ç¨‹åºéœ€è¦åœ¨¾c»èµ\径中æ·ÕdŠ J2EE JAR.选择Libraries选项卡,然后单击Add External JARs按钮ã€?/p>

  为项目添加J2EE 1.4 j2ee.jaræ–‡äšgã€?.4 j2ee.jarž®†åœ¨™å¹ç›®åº“中列出。单击Finish按钮完成™å¹ç›®é…ç½®ã€‚这样便ž®†ä¸€ä¸ªé¡¹ç›®æ·»åŠ åˆ°Eclipse IDE Package Explorer视图中ã€?/p>

  接下来指定WebLogic Server配置。选择Window>Preferences.在出现的Preferences½H—体中,选择WebLogic节点。在WebLogic preference™åµé¢åQŒé€‰æ‹©è¦é…¾|®çš„WebLogic Server版本。指定不同的字段å€û|¼Œå¦?è¡? 所½Cºã€‚由于安装服务器和配¾|®åŸŸçš„目录不同,å€ég¹Ÿæœ‰æ‰€ä¸åŒã€‚单击Apply按钮应用指定的倹{€?/p>

  字段描述�/strong>

  è¡? WebLogic-Eclipse插äšg

  如果必须向服务器¾c»èµ\径添加JARæ–‡äšgåQŒè¯·é€‰æ‹©WebLogic>Classpath节点。可以在æ·ÕdŠ WebLogic库之前或之后æ·ÕdŠ JAR/Zipæ–‡äšg或目录。选择WebLogic>JavaVM Options节点指定JavaVM选项。例如,修改weblogic.ProductionModeEnabledå±žæ€§ã€‚å°†å±žæ€§å€ÆD®¾¾|®äØ“false可ä‹É用开发模式启动服务器。单击Apply按钮应用JavaVM选项ã€?/p>

  接下来,指定要ä‹É用WebLogic Server配置˜q›è¡Œè°ƒè¯•的项目。单击Add按钮åQŒé€‰æ‹©è¦æ·»åŠ åˆ°æ’äšg配置的项目。若要调试某个项目,该项目必™åÖM½äºŽæ’仉™…¾|®ä¸­ã€‚单击OK按钮ã€?/p>

  ˜q™æ ·ä¾¿å°†é€‰æ‹©çš„项目添加到™å¹ç›®åˆ—表中了。单击Apply按钮åQŒç„¶åŽå•击OK按钮åQŒä‹É用项目和WebLogic Server完成WebLogic插äšg的配¾|®ã€?/p>

  开发和调试WebLogic应用½E‹åº

  配置了WebLogic插äšg后,ž®†å¼€å‘一个J2EE应用½E‹åºåœ¨WebLogic Server中进行部¾|²å’Œè°ƒè¯•。示例J2EE应用½E‹åºç”±Session EJB和客æˆïL«¯servlet¾l„成。可从资源zipæ–‡äšg中获取该 J2EE应用½E‹åºåQˆå…³äºŽæœ¬æ–‡çš„æºä»£ç ï¼Œå¯åœ¨¾U¿æŸ¥çœ‹WLDJ归档文äšg中的文章 http://wldj.sys-con.com/read/issue/archives/åQŒVol. 5åQŒiss. 2åQ‰ã€‚将资源zipæ–‡äšg提取到目录。在上文中配¾|®çš„Eclipse™å¹ç›®EclipseWebLogic中,选择File>Import导入J2EE应用½E‹åºçš„src目录。在Import½H—体中,选择File System节点åQŒç„¶åŽå•击Next按钮。在File system½H—体中,选择directories/filesæ·ÕdŠ ™å¹ç›®åQŒç„¶åŽå•击Finish按钮åQˆè§å›?åQ‰ã€?/p>

配置WebLogic-Eclipse插äšg å›?1

  �

  ˜q™æ ·ä¾¿å°†½CÞZ¾‹J2EE应用½E‹åºæ–‡äšgæ·ÕdŠ åˆ°é¡¹ç›®ä¸­ã€‚ä‹É用Ant build.xmlæ–‡äšg构徏™å¹ç›®ã€‚右键单击build.xmlåQŒé€‰æ‹©Run>Ant Build卛_¯æž„徏J2EE应用½E‹åºòq¶å°†å…‰™ƒ¨¾|²åœ¨WebLogic Server应用½E‹åºç›®å½•中。接下来åQŒé€‰æ‹©Run>Start WebLogic在Eclipse IDE中启动WebLogic Server.˜q™æ ·ä¾¿å°†Session EJB/Servlet应用½E‹åºéƒ¨çÖvåœ?WebLogic Server中,如应用程序节ç‚ÒŽ‰€½Cºã€?/p>

  在浏览器中输入URL http://localhoståQ?001/weblogic/webLogicPlug-in˜qè¡ŒWebLogicServlet. servlet的输出将在浏览器中显½Cºã€‚接下来向客æˆïL«¯servletæ·ÕdŠ ä¸€ä¸ªå¼‚å¸¸ï¼ˆNullPointerExceptionåQ‰ï¼Œä»¥éªŒè¯WebLogic插äšg的调试功能。在WebLogicServlet servlet中将åQ?/p>

  out.printlnåQˆsessionEJB.getEclipsePlug-inåQˆï¼‰åQ‰ï¼›

  替换为:

  String str=nullåQ?/p>

  out.printlnåQˆstr.toStringåQˆï¼‰åQ‰ï¼›

  选择Run>Add Java Exception Breakpoint向servletæ·ÕdŠ ä¸€ä¸ªæ–­ç‚V€‚在Add Java Exception Breakpoint½H—体中,选择NullPointerException.åˆ é™¤ä¹‹å‰æž„å¾çš„ç›®å½•åÆˆä½¿ç”¨build.xml构徏应用½E‹åºã€‚选择Debug perspective.在Debug perspective可以看到WebLogic Server正运行在localhostä¸ÀLœºä¸­ã€?/p>

  在浏览器中运行示例servletåQˆå¸¦NullPointerExceptionåQ‰ã€‚因为servlet带有异常åQŒæ‰€ä»¥æœåŠ¡å™¨è¢«ä¸­æ–­ï¼Œòq¶ä¸”Debug perspective昄¡¤ºNullPointerException.使用Run菜单™å¹ä¸­çš„调试功能可以调试应用程序ã€?/p>

  ¾l“束è¯?/p>

  ¾lég¸Šæ‰€˜qŽÍ¼Œä½¿ç”¨WebLogic插äšg可以通过Eclipse IDE½Ž¡ç†WebLogic ServeråQŒè¿˜å¯é€šè¿‡Eclipse IDE调试服务器中部çÖv的应用程序。WebLogic插äšg的局限性在于不支持JSP调试。该插äšgçš?.0版本ž®†æœ‰æ›´å¤šåŠŸèƒ½ã€?/p> J2EE配置WebLogic-Eclipse插äšg

]]>
Ö÷Õ¾Ö©Öë³ØÄ£°å£º ÁÙò£ÏØ| Öн­ÏØ| ÀäË®½­ÊÐ| Á¬½­ÏØ| ²¼¶û½òÏØ| ÓÀ¼ÃÊÐ| ÀÖ°²ÏØ| Ëɽ­Çø| ¶«À¼ÏØ| ÕýÀ¶Æì| ÎÞÎªÏØ| Ó¢É½ÏØ| ËÞÖÝÊÐ| Ëç½­ÏØ| ºÍÁúÊÐ| ±£Í¤| Âå´¨ÏØ| ·îÐÂÏØ| ²¼ÍÏÏØ| ãþÑôÏØ| ÁêË®| ÆîÑôÏØ| ͨ³ÇÏØ| Ã×Ò×ÏØ| Ïç³ÇÏØ| ÄϳÇÏØ| ÕżҸÛÊÐ| ¡»¯ÏØ| ɯ³µÏØ| ¶¨½áÏØ| Ǭ°²ÏØ| ÈêÄÏÏØ| ¾«ºÓÏØ| ÍпËÍÐÏØ| ½­±±Çø| ½ðƽ| ƽºÍÏØ| ×Ó³¤ÏØ| μÄÏÊÐ| ÌìµÈÏØ| ÁúÄÏÏØ|