ASP系列講座(九)設定對像作用域
作者:Eve Cole
更新時間:2009-05-30 19:59:07
物件的作用域決定哪些腳本可以使用該物件。預設情況下,當您建立物件實例時,該物件具有頁面作用域。同一ASP 頁中的任何腳本指令都能使用該頁作用域的物件;當ASP 頁送回客戶端時,該物件即被釋放。對大多數物件來說,建議的作用域是頁作用域。您可以改變一個物件的作用域,使其可被其他頁的腳本使用。本主題將說明如何使用頁作用域的物件以及如何改變物件的作用域。
使用頁作用域物件在ASP 頁上用Server.CreateObject 建立的物件在該頁的生存期內一直存在。該物件對該頁的任何腳本命令都是可存取的,當ASP 處理完該頁時,該物件即被釋放。因此,物件具有該頁的作用域或生命週期。
在使用Visual Basic 或VBScript 程式設計時,請注意在ASP 處理完該頁之前不要釋放物件。例如,以下語句經常用於透過將物件變數賦以Nothing 值來釋放物件:
Set myObj = Nothing
如果您在ASP 頁中包含了該語句,那麼任何使用myObj 的企圖都會傳回一個預期的錯誤代碼。但在內部,即使在物件釋放以後,ASP 仍保留對它的引用。當您在腳本中無法使用物件時,物件的資源直到ASP 處理完頁之後才釋放。同樣,如果您透過建立另一個物件實例並將其賦給已使用過的物件變數來釋放該物件時,ASP 將保留對原始物件實例的參考。對大多數腳本來說,建立多個物件可能不會產生問題,但如果物件使用共享資源,例如資料庫連接,就有可能出現問題。
由於物件有頁作用域,所以不要依靠手工釋放的物件。例如,以下的循環會建立1001 個Connection 對象,它將能開啟大多數的連線甚至於一個大型的SQL server:
<%
For I = 0 to 1000
Set Conn = Server.CreateObject("ADODB.Connection")
Conn.Open "connection string"
Next
%>
總的來說,應該盡量避免在一個循環內部建立物件。如果無法避免,您應該手動釋放被物件使用過的資源。如果Connection 物件只被建立一次,且資料資源的實體連線在每個循環中被開啟然後關閉,那麼上例將會正常運作:
<%
Set Conn = Server.CreateObject("ADODB.Connection")
For I = 0 to 1000
Conn.Open "connection string"
Conn.Close
Next
%>
為物件賦予會話作用域在應用程式中,對於每個新會話,都會建立session-scope 對象,並且在會話結束後會將其釋放。因此,每個活動的會話都有一個物件。會話作用域用於從多個腳本中呼叫的對象,但只影響一個使用者會話。您可以只在需要時才為物件賦予會話作用域。如果確實需要使用會話作用域,那麼就必須了解提供物件的元件的執行緒模型,因為它會影響效能和物件的安全環境。詳細信息,請參閱本主題的“高級信息:性能問題” 。
若要為物件賦予會話作用域,請將物件儲存在ASP Session 內建物件中,您既可以在Global.asa 檔案中使用<OBJECT> 標記,也可以在ASP 頁上使用Server.CreateObject 方法建立具有會話作用域的物件實例。
在Global.asa 檔案中,您可用擴充了RUNAT 屬性(必須設定為Sever)和SCOPE 屬性(必須設定為Session)的;OBJECT> 標記。以下範例建立一個Ad Rotator 物件的會話作用域實例:
<OBJECT RUNAT=Server SCOPE=Session ID=MyAd PROGID="MSWC.Adrotator">
</OBJECT>
一旦您在Session 對像中儲存了對象,您就可以從應用程式的任何頁面存取該對象。下面的語句使用上例中由<OBJECT> 標記所建立的物件實例:
<%= MyAd.GetAdvertisement("addata.txt") %>
在ASP 頁上,您也可以使用Server.CreateObject 方法將物件儲存在Session 內建物件中。以下範例在Session 物件中儲存Ad Rotator 物件的一個實例。
<% Set Session("MyAd") = Server.CreateObject("MSWC.Adrotator") %>
要顯示廣告,您首先應該取得儲存在Session 物件中的Ad Rotator 物件的實例,然後才能呼叫方法來顯示物件:
<% Set MyAd = Session("MyAd") %>
<%= MyAd.GetAdvertisement("addata.txt") %>
在用<OBJECT> 標記聲明的物件被某個.asp 檔案中的腳本指令引用之前,ASP 並不會建立其實例。 Server.CreateObject 方法則立即建立該物件實例。因此,對於會話作用域物件來說,使用<OBJECT> 標記要比Server.CreateObject 屬性更好。
為物件賦予應用程式作用域
application-scope 物件是在應用程式啟動時就建立的物件的單一實例。該物件由所有客戶端請求共用。只有在極少數情況下,您才需要為物件賦予應用程式作用域。一些實用程式對象,例如計數器等,可能需要應用程式作用域。但一般來說,您可用在下一節中建議的替代方案。另外,線程模型會影響效能和物件安全環境(請參閱本主題的「進階資訊:效能問題」)。
若要為物件賦予應用程式作用域並將其儲存在ASP Application 內建物件中,既可以使用Global.asa 檔案中的<OBJECT> 標記,也可以使用ASP 頁上的Server.CreateObject 方法建立應用程式作用域的物件實例。
在Global.asa 檔案中,您可用擴充了RUNAT 屬性(必須設定為Sever)和SCOPE 屬性(必須設定為Session)的;OBJECT> 標記。在ASP 頁中,您可以使用Server.CreateObject 將物件實例儲存在Application 內建物件中。關於使用<OBJECT> 標記和Server.CreateObject 的範例,請參閱上一節「為物件賦予會話作用域」。
會話和應用程式作用域的替代方案僅當需要時,才能為物件賦予會話或應用程式作用域。因為在會話或應用程式結束運行之前,這些物件會一直保留。它們會佔用記憶體或資料庫連接等資源,這些資源可能在其他方面更有用。另外,元件的執行緒模型會影響您從中所建立的物件的效能,尤其是那些具有會話或應用程式作用域的物件。
在許多情況下,比創建應用程式或會話作用域物件更好的方法就是利用會話或應用程式作用域變量,將資訊傳遞給在網頁層級創建的物件。例如,不要為ADO Connection 物件賦予會話或應用程式作用域,因為它建立的連線會在相當長的一段時間保持開啟而此時腳本已不再使用ODBC 連線共用。但您可以將ODBC 連線字串儲存在Session 或Application 內建物件中,並在網頁上從已建立的Connection 物件實例中取得該字串。透過這種方式,您可以儲存在會話或應用程式名稱空間中頻繁使用的信息,但只有在需要時才建立使用該資訊的物件。
使用者自訂的JScript 物件您可以透過定義一個建立和初始化新物件的屬性和方法的建構子來建立自己的JScript 物件。當腳本用new 操作符來呼叫建構函式時,就會建立該物件的實例。 ASP 腳本支援使用者自訂的對象,當具有頁作用域時,後者正常運作。但如果為使用者自訂的JScript 物件賦予應用程式或會話作用域,將可能影響該物件的功能。特別是,若一個物件具有會話或應用程式作用域,則其他頁的腳本可以取得該物件的屬性,但是卻不能呼叫其方法。
進階資訊:效能問題元件的執行緒模型可能會影響Web 網站的效能,一般來說,帶有Both 標記的物件是建議在所有的ASP 腳本中使用的對象,尤其是在Session 和Application 物件中。不建議使用單線程物件。
因為您可能不會始終控制所用物件的線程模型,所以,以下的指導可幫助您獲得最佳效能:
頁作用域物件。帶有Both 或Apartment 標記的物件將給您最佳的效能。
應用程式作用域物件。一般來說,應避免在Application 物件中放置物件。如果您確實需要使用應用程式作用域對象,您會從結合了FreeThreadedMarshaler 的帶有Both 標記的物件中獲得最佳效能。您可以用<OBJECT> 標記也可以用Server.CreateObject 方法在Application 物件中儲存帶有Single、Free 或Both 標記的物件。您必須用單元線程物件來使用<OBJECT> 標記。
會話作用域物件。帶有Both 標記的物件將為您提供最佳性能。用單線程或單元線程物件會導致Web 伺服器將會話鎖定在一個線程上。自由線程物件不會鎖定會話,但運行速度不高。在Session 物件中,您可以用<OBJECT> 標記或Server.CreateObject 方法儲存物件。
如果您已安裝了SDK 文檔,您將會獲得有關線程模型及其隱含的元件效能的詳細資訊。 (在Windows 95 及其後續版本中SDK 文件不可用。)