直播中
5.1 腳本對(duì)象的定義
前面章節(jié)研究了ASP對(duì)象模型。
對(duì)象模型是用來(lái)理解系統(tǒng)的各個(gè)部分相互關(guān)系的一種基本手段。
ASP對(duì)象模型提供了一種結(jié)構(gòu),用來(lái)作為一個(gè)整體操縱HTTP請(qǐng)求、響應(yīng)及ASP環(huán)境中的不同元素。例如,我們已經(jīng)看到,如何通過(guò)查看ASP請(qǐng)求對(duì)象的cookie集合,得到來(lái)自瀏覽器的任何cookie值。
我們使用的腳本語(yǔ)言也有對(duì)象模型。然而,腳本語(yǔ)言提供的這一對(duì)象模型,不同于由ASP DLL直接提供的對(duì)象模型,腳本對(duì)象是由Microsoft腳本運(yùn)行期庫(kù)(scrrun.dll)提供的,安裝缺省的Active Scripting腳本引擎時(shí),也安裝了Microsoft腳本運(yùn)行期庫(kù)。
5.1.1 不同類型的對(duì)象和組件
不要對(duì)“對(duì)象”和“組件”這兩個(gè)名詞感到困惑,在一定范圍內(nèi)它們都可以作為ASP的一部分,同樣可以通過(guò)COM對(duì)其進(jìn)行訪問(wèn)。從概念上可以將它們分為四類:
· ASP內(nèi)置對(duì)象,如ObjectContext、Request、Response、Application、Session、Server和ASPError。本書(shū)的第2章到第4章已經(jīng)研究了這些內(nèi)容。
· 腳本對(duì)象。通過(guò)腳本運(yùn)行期庫(kù)使用,如Dictionary、FileSystem和TextStream。這是本章要討論的對(duì)象。
· 可安裝的組件。由Microsoft在IIS 5.0和ASP 3.0標(biāo)準(zhǔn)安裝時(shí)提供。這將在下一章討論。
· 其他組件。從其他獨(dú)立廠商購(gòu)買的、在網(wǎng)站上發(fā)現(xiàn)的或者自己創(chuàng)建的組件。還有一些其他的由Windows服務(wù)或產(chǎn)品提供的組件,如Windows Scripting Host。在本書(shū)的附錄中提供了相應(yīng)的列表,本書(shū)專門有一部分章節(jié)講述如何構(gòu)建自己的組件。
5.1.2 VBScript和Jscript腳本對(duì)象
作為腳本運(yùn)行期庫(kù)的一部分,Microsoft提供三個(gè)主要的對(duì)象:
· Dictionary對(duì)象提供一個(gè)極為有用的存儲(chǔ)對(duì)象,它用來(lái)存儲(chǔ)值,通過(guò)對(duì)象的名字而不是其索引進(jìn)行訪問(wèn)和引用。例如,對(duì)于存儲(chǔ)從ASP Request對(duì)象中檢索到的名稱/值對(duì),這是非常合適的。
· FileSystemObject對(duì)象提供了對(duì)服務(wù)器底層文件系統(tǒng)的訪問(wèn)(在客戶端上使用IE 5.0,與名為“Hypertext Application(HTA)”的特殊類型的頁(yè)面協(xié)同使用)??捎肍ileSystemObject對(duì)象遍歷計(jì)算機(jī)的本地及網(wǎng)絡(luò)的驅(qū)動(dòng)器、文件夾和文件。
· TextStream對(duì)象提供對(duì)存儲(chǔ)在磁盤上文件的訪問(wèn),用于同F(xiàn)ileSystemObject對(duì)象協(xié)同使用。TextStream對(duì)象能夠讀出或?qū)懭胛谋荆樞虻模┪募?,并僅能通過(guò)FileSystemObject對(duì)象進(jìn)行實(shí)例化,所以人們常常認(rèn)為TextStream對(duì)象是FileSystemObject對(duì)象的子對(duì)象。
FileSystemObject對(duì)象是其他一系列用來(lái)與文件系統(tǒng)交互的對(duì)象和集合的“父代”。該對(duì)象提供了對(duì)象的三個(gè)集合:Drives、Folders和Files集合,每個(gè)集合分別是相應(yīng)的Drive、Folder和File對(duì)象的集合。它們用來(lái)進(jìn)行磁盤上的驅(qū)動(dòng)器、文件夾(目錄)和文件的遍歷和定位。對(duì)象間的關(guān)系如圖5-1所示:
圖5-1 腳本運(yùn)行期庫(kù)中對(duì)象間的關(guān)系
下面,將依次介紹這些對(duì)象和集合,以及如何使用它們。然而,首先要理解對(duì)象實(shí)例與組件的創(chuàng)建或?qū)嵗绞街g的差異。這是下一節(jié)的主要內(nèi)容。
5.2 創(chuàng)建對(duì)象生組件實(shí)例
創(chuàng)建腳本運(yùn)行期庫(kù)對(duì)象的實(shí)例與創(chuàng)建任何其他對(duì)象和組件的實(shí)例化方式完全相同??墒褂肁SP Server對(duì)象提供的CreateObject方法(確保對(duì)象創(chuàng)建在當(dāng)前頁(yè)面的環(huán)境內(nèi)),或者使用一個(gè)<OBJECT>元素。我們將研究這兩種方法,究竟采用那種方法依賴于頁(yè)面的需要。
5.2.1 使用Server.CreateObject方法
正如在研究Server對(duì)象的時(shí)候看到的,組件或其他對(duì)象實(shí)例可根據(jù)它們的ProgID來(lái)創(chuàng)建:
<%
Dim objThis
Set objThis = Server.CreateObject(“ADODB.Connection”)
%>
ProgID字符串“正式的”格式是“供應(yīng)商.組件.版本”,供應(yīng)商的名字和版本是可選的。通常ProgID只包含前兩部分(如上例)。少數(shù)供應(yīng)商在ProgID中設(shè)置版本編號(hào),這將避免向后兼容的新版本使用同樣的ProgID,這要求改變ASP頁(yè)面才能使用新版本。
5.2.2 使用<OBJECT>元素
可以使用標(biāo)準(zhǔn)的HTML<OBJECT>元素通過(guò)增加RUNAT參數(shù)并指定其值為“SERVER”來(lái)在服務(wù)器上創(chuàng)建一個(gè)組件實(shí)例。另外,通常是提供對(duì)象的ProgID字符串而不是數(shù)字的ClassID:
<OBJECT ID=”objThis” RUNAT=”SERVER” PROGID=”This.Object”>
<PARAM NAME=”param1” VALUE=”value1”>
<PARAM NAME=”param2” VALUE=”value2”>
</OBJECT>
如果上面腳本的對(duì)象有相應(yīng)的屬性可在腳本中使用,在<OBJECT>元素內(nèi)可通過(guò)<PARAM>元素進(jìn)行設(shè)置,就像通常在HTML頁(yè)面中所做的一樣。在ASP中使用<OBJECT>元素時(shí)不要求CODEBASE屬性,當(dāng)其不可用時(shí),服務(wù)器不會(huì)試圖下載以及安裝對(duì)象或組件。
1. 指定一個(gè)ClassID
另外,可以指定想要?jiǎng)?chuàng)建的對(duì)象或組件的ClassID。在不知道目標(biāo)機(jī)安裝了什么其他組件的情況下,這是非常有用的。例如在客戶端上的瀏覽器的頁(yè)面上實(shí)例化組件時(shí)。
在理論上,組件的ProgID(文本“供應(yīng)商.組件”)不應(yīng)該相互沖突,應(yīng)該是唯一的。然而,這不是無(wú)懈可擊的。有可能美國(guó)北方的一個(gè)供應(yīng)商與希臘小島上的一個(gè)供應(yīng)商同名。但是,使用ClassID識(shí)別訪問(wèn)時(shí),因?yàn)镃lassID是唯一的,同名情況就不會(huì)發(fā)生。
如果決定使用對(duì)象或組件的ClassID,應(yīng)將其放入CLASSID屬性中,而不是PROGID屬性。如:
<OBJECT ID=”objThis” RUNAT=”SERVER”
CLASSID=”clsid:892D6DA7-E0F9-11D2-B2E9-00105A42AF30”>
<PARAM NAME=”param1” VALUE=”value1”>
<PARAM NAME=”param2” VALUE=”value2”>
</OBJECT>
但在自己的服務(wù)器上實(shí)例化對(duì)象時(shí),應(yīng)該知道對(duì)象和組件的安裝方式。這樣在ASP代碼中創(chuàng)建對(duì)象實(shí)例時(shí),可以安全地使用ProgID。這就是ClassID很少在ASP頁(yè)面內(nèi)使用的原因。然而,因?yàn)镻rogID用于查找ClassID,如果愿意也可以用組件或?qū)ο蟮腃lassID代替ProgID。
2. 設(shè)置對(duì)象實(shí)例的作用域
缺省情況下,所有ASP頁(yè)面中創(chuàng)建的對(duì)象與組件實(shí)例(無(wú)論用Server.CreateObject方法或<OBJECT>元素)都有頁(yè)面內(nèi)的作用域(page scope)。這意味著,對(duì)象與組件只有該頁(yè)在ASP上運(yùn)行時(shí)才存在,當(dāng)頁(yè)面完成并且把結(jié)果發(fā)送到客戶端以后就自動(dòng)地取消了。
然而,如果在global.asa文件(它存在于站點(diǎn)或虛擬應(yīng)用程序的根目錄)中放置<OBJECT>聲明,可以將對(duì)象或組件的作用域指定為應(yīng)用程序或會(huì)話作用域。
(1) 在應(yīng)用程序?qū)幼饔糜騽?chuàng)建對(duì)象
通過(guò)設(shè)置SCOPE屬性為“APPLICATION”,創(chuàng)建應(yīng)用程序?qū)幼饔糜驅(qū)ο螅?BR><OBJECT ID=”objThis” RUNAT=”SERVER” PROGID=”This.Object”
SCOPE=”APPLICATION”>
</OBJECT>
應(yīng)用程序開(kāi)始時(shí)創(chuàng)建了對(duì)象實(shí)例,即一旦用戶從虛擬應(yīng)用程序的目錄請(qǐng)求一個(gè)頁(yè)面,就創(chuàng)建對(duì)象實(shí)例。對(duì)于缺省Web站點(diǎn),這可以是站點(diǎn)上的任一目錄。直到應(yīng)用程序結(jié)束(最后的用戶會(huì)話結(jié)束)前,對(duì)象實(shí)例一直存在,并且可以被虛擬應(yīng)用程序或站點(diǎn)目錄內(nèi)任一頁(yè)面內(nèi)的任意用戶引用和使用。
(2) 在會(huì)話層作用域創(chuàng)建對(duì)象
如果想創(chuàng)建由單個(gè)用戶使用的對(duì)象實(shí)例,其作用域?yàn)樗L問(wèn)的所有頁(yè)面,可創(chuàng)建會(huì)話層作用域?qū)ο?。這通過(guò)將SCOPE屬性設(shè)置為“SESSION”來(lái)實(shí)現(xiàn):
<OBJECT ID=”objThis” RUNAT=”SERVER” PROGID=”This.Object”
SCOPE=SESSION”>
</OBJECT>
對(duì)象一旦被引用就被創(chuàng)建,引用是由用戶從虛擬應(yīng)用程序或站點(diǎn)載入的頁(yè)面內(nèi)的程序代碼完成的(在global.asa文件中有<OBJECT>聲明)。當(dāng)用戶會(huì)話生命周期結(jié)束并被取消時(shí),它引用的對(duì)象實(shí)例也就取消了。
(3) 關(guān)于作用域和狀態(tài)
使對(duì)象實(shí)例的作用域?yàn)槿值幕蛘邽橛脩魰?huì)話全局環(huán)境看起來(lái)是一個(gè)好主意,但在實(shí)際使用時(shí)有些問(wèn)題需要考慮,其中之一是在用戶的許多請(qǐng)求之間能夠有效地保護(hù)對(duì)象的狀態(tài)。換句話說(shuō),可以設(shè)定對(duì)象的一些屬性,它們對(duì)使用的所有頁(yè)面是共用的。因?yàn)椴槐孛看味紕?chuàng)建新的實(shí)例并設(shè)置其屬性,所以這看起來(lái)是個(gè)較好的辦法。
事實(shí)上,微軟建議一般情況下不要這樣做,這一思想是傳統(tǒng)程序設(shè)計(jì)思想的殘余。在Web上,要面對(duì)的最大問(wèn)題是服務(wù)器以及Web應(yīng)用程序及所提供的動(dòng)態(tài)網(wǎng)頁(yè)如何應(yīng)付數(shù)以百萬(wàn)計(jì)的網(wǎng)站訪問(wèn)者。將組件實(shí)例駐留在內(nèi)存中等待一個(gè)特定用戶的頁(yè)面請(qǐng)求,對(duì)可能有幾百個(gè)用戶同時(shí)瀏覽的網(wǎng)站來(lái)說(shuō),這樣做不能有效地使用資源。
Windows 2000提供新的COM+運(yùn)行期特性,它能夠處理組件的創(chuàng)建、緩存和使用,采用一種吞吐量最大化但所占服務(wù)器資源最小化的方式。對(duì)象實(shí)例存儲(chǔ)在哪里和存儲(chǔ)多久的問(wèn)題,最好由操作系統(tǒng)自己完成,而不是由程序員決定。
也就是說(shuō),在頁(yè)面內(nèi)需要的地方創(chuàng)建對(duì)象實(shí)例,當(dāng)頁(yè)面終止時(shí)讓其消失。COM+整理這些碎片,自動(dòng)處理后臺(tái)的一些復(fù)雜工作。如果要了解有關(guān)這方面的內(nèi)容,第14章比較詳細(xì)地研究了組件的創(chuàng)建。
當(dāng)然,在某種情況下,我們可能要求一個(gè)對(duì)象具有應(yīng)用程序?qū)雍蜁?huì)話層的作用域,尤其是在頁(yè)面請(qǐng)求間保存狀態(tài)時(shí)。在后面討論Dictionary對(duì)象時(shí),將有一個(gè)這方面的實(shí)例。
5.2.3 Server.CreateObject與<OBJECT>的區(qū)別
Server.CreateObject方法立即創(chuàng)建一個(gè)對(duì)象實(shí)例。在大多數(shù)情況下這也是我們所希望的。而<OBJECT>元素只有首次引用一個(gè)對(duì)象時(shí)才創(chuàng)建指定的對(duì)象實(shí)例。因此如果在代碼中停止使用該對(duì)象,則不創(chuàng)建該對(duì)象實(shí)例。
如果代碼只在某種情況下使用這個(gè)對(duì)象(可能依賴于請(qǐng)求參數(shù)的值),這也許是有用的。因?yàn)槿绻恍枰@個(gè)對(duì)象,則可以節(jié)省服務(wù)器的資源。
然而,如果肯定需要?jiǎng)?chuàng)建某一對(duì)象,可使用Server.CreateObject方法完成。用<OBJECT>元素創(chuàng)建對(duì)象有助于防止在代碼中取消對(duì)對(duì)象的調(diào)用時(shí),忘記取消程序中的Server.CreateObject行,當(dāng)然這是一個(gè)粗心的程序設(shè)計(jì)。
最后需要記住的是,如果對(duì)象是使用Server.CreateObject方法創(chuàng)建的,就可以從會(huì)話或應(yīng)用程序中去掉對(duì)象,但使用<OBJECT>元素創(chuàng)建的,則不行。
5.2.4 組件線程模型
在頁(yè)面內(nèi)使用對(duì)象或組件時(shí),應(yīng)該考慮的另一個(gè)問(wèn)題是該對(duì)象涉及到的響應(yīng)多個(gè)請(qǐng)求的行為方式。事實(shí)上在ASP里,這是所需要理解的最復(fù)雜的題目之一。一個(gè)組件的線程模型,結(jié)合其作用域,影響該組件和應(yīng)用程序的性能和效率,也影響將它實(shí)例化的ASP頁(yè)面。
線程就是由處理器執(zhí)行的系統(tǒng)對(duì)象,用于完成由組件代碼定義的任務(wù)。每一個(gè)線程都可以被認(rèn)為是單個(gè)二進(jìn)制指令集。在像Windows這樣的多線程環(huán)境中,多個(gè)線程可同時(shí)運(yùn)行。
實(shí)際上有五個(gè)線程模型(包括在Windows 2000里引入的Neutral-threading模型):
· Single-threaded(單線程):某一時(shí)刻只能有一個(gè)進(jìn)程使用某組件。
· Apartment-threaded(單元線程):若干進(jìn)程都可以使用某組件,但只有一個(gè)在指定的線程上。
· Neutral-threaded(中立線程):若干進(jìn)程都能使用某組件,并且可以使用指定的一組線程中的任何一個(gè)。
· Multiple-threaded或Free-threaded(多線程或自由線程):若干進(jìn)程都能使用某組件,并且這些進(jìn)程可以運(yùn)行在不同的線程上。
· Both-threaded(雙線程):對(duì)象既可以是單元線程的又可以作為自由線程的。
在這里不解釋線程模型的技術(shù)細(xì)節(jié),本書(shū)后面有相應(yīng)的內(nèi)容。
單元線程的組件(例如使用Visual Basic創(chuàng)建的或作為XML腳本的組件)可在頁(yè)面層作用域內(nèi)很好地運(yùn)行,在會(huì)話層作用域內(nèi)也是可以接受的。事實(shí)上,在頁(yè)面層,由于較低的數(shù)據(jù)處理開(kāi)銷,也能很好地運(yùn)行雙線程的組件。
Winodws 2000中的中立線程的模型甚至提供了更好的性能,盡管到目前為止只有很少的這樣的組件和與之相適應(yīng)的開(kāi)發(fā)工具。
如果需要會(huì)話層組件,使用可用的雙線程的組件。并且如果需要應(yīng)用程序?qū)幼饔糜?,可一直使用雙線程的組件。
然而,微軟建議避免使用會(huì)話層作用域的組件,甚至不使用應(yīng)用程序?qū)幼饔糜虻慕M件,除非這些組件是絕對(duì)需要的。使組件的活動(dòng)時(shí)間超過(guò)作用域?yàn)轫?yè)面級(jí)的組件所要求的時(shí)間,對(duì)于由COM+提供代理特性的對(duì)象是沒(méi)有益處的。