作用
在運作期間,ice架構為了完全隔絕通信層對于客戶業務服務的影響,将通信層用到的所有資源都與客戶業務服務用到的資源完全隔離開來了。為了完成這個目标,寫代碼進行封裝的時候,我們一般封裝一個資源管理類來對通信層所用的資源進行管理,ice則用communicator來實作這個功能。
另一方面,架構為了完全獨立,一般都有個全局的入口點,類似于程式的入口main函數。ice架構則用Ice::Communicator 來代表運作期間架構的主進入點。
管理的資源
-
用戶端線程池
用戶端線程池會確定,在用戶端,至少有一個線程可用于接收對未完成請求的答複。這確定了不會發生死鎖。例如,如果伺服器在操作實作中回調客戶,即使客戶正在等待同一伺服器答複它的請求,用戶端接收者線程也能處理來自伺服器的請求。用戶端線程池還被用于異步方法調用(AMI),用以避免在回調中發生死鎖。
-
伺服器端線程池
這個線程池裡面的線程負責接受到來的連接配接,并處理來自客戶的請求。
-
配置屬性
Ice run time 的各個方面可以通過屬性進行配置。每個通信器都有自己的配置屬性集。
-
對象工廠
為了執行個體化從已知基類派生的類,通信器維護有一組對象工廠,能夠替Ice run time 對類進行執行個體化。
-
一個日志記錄器對象
日志記錄器對象實作了Ice::Logger 接口,并負責确定Ice run time産生的日志消息的處理方式。
-
一個統計對象
統計對象實作了Ice::Stats 接口,通信器會把通信流量(發送和接收位元組數)告知該對象。
-
一個預設路由器
路由器實作了Ice::Router 接口。Glacier 使用了路由器來實作Ice 的防火牆功能功能。
-
一個預設定位器
定位器是用于把對象辨別解析為代理的對象。定位器對象被用于建構定位服務,比如IcePack 。
-
一個插件管理器
插件是用于給通信器增加特性的對象。例如, IceSSL被實作成插件。每個通信器都有一個插件管理器,這個管理器實作Ice::PluginManager 接口,通過它,你可以通路通信器的插件集。
-
對象擴充卡
對象擴充卡負責分派到來的請求,并把每個請求傳給正确的servant。使用不同通信器的對象擴充卡和對象完全是互相獨立的。特别地:
- 每個通信器都使用自己的線程池。例如,這意味着,如果一個通信器耗盡了用于處理到來請求的線程,隻有使用該通信器的對象會受影響。使用其他通信器的對象有自己的線程池,因而不受影響。
-
跨越不同通信器的并置調用不會被優化,而使用同一通信器的并置調用則能避免産生大部分調用分派開銷。伺服器通常隻使用一個通信器,但有時多個通信器也會很有用。例如,加載的每個Ice 服務使用了單獨的通信器,以確定不同的服務不會互相幹擾。多個通信器器還能用于避免線程饑餓:如果一個
服務耗盡線程,其他的服務不會受影響。
通信器的接口
通信器的接口是用Slice 定義的。下面是其部分接口:
module Ice
{
local interface Communicator
{
string proxyToString(Object* obj);
Object* stringToProxy(string str);
ObjectAdapter createObjectAdapter(string name);
ObjectAdapter createObjectAdapterWithEndpoints(string name,string endpoints);
void shutdown();
void waitForShutdown();
void destroy();
// ...
};
// ...
};
通信器提供了一些操作:
proxyToString
stringToProxy
這兩個操作允許你把代理轉換成串化表示,或進行反向轉換。
createObjectAdapter
createObjectAdapterWithEndpoints
這兩個操作建立新的對象擴充卡。每個對象擴充卡都與一個或更多傳輸端點關聯在一起。一個對象擴充卡通常擁有一個傳輸端點。但是,一個對象擴充卡也可以提供多個傳輸端點。如果是這樣,這些端點可以通往同一組對象,但代表通路這些對象的不同手段。這很有用,例如,伺服器在防火牆後面,但必須讓内部和外部的客戶都能通路它;把擴充卡同時綁定到内部和外部接口,就可以其中任何一個接口通路在伺服器中實作的對象了。
createObjectAdapter 根據配置資訊來确定把自己綁定到哪個端點,而createObjectAdapterWithEndpoints 允許你為新擴充卡指定傳輸端點。你通常會優先于createObjectAdapterWithEndpoints使用createObjectAdapter。這樣,就能把與傳輸機制相關的資訊(比如主機名和端口号)放在 源碼外面,通過改變屬性,你可以對應用進行重配置(于是,在傳輸端點需要改變時,不用重新進行編譯)。
shutdown
這個操作關閉伺服器端的Ice run time:
- 在shutdown 被調用時,仍處在執行過程中的操作調用可以正常完成。shutdown 不會等待這些操作完成;在shutdown 傳回時,你所知道的是:不會再有新的請求被分派,但在你調用shutdown 時已經在執行之中的操作可能仍在運作。你可以調用waitForShutdown,等待仍在執行的操作完成。
- 在伺服器調用shutdown 之後到達的操作調用或者會失敗(抛出ConnectFailedException),或者會被透明地重定向到伺服器的某個新執行個體。
waitForShutdown
這個操作挂起發出調用的線程,直到通信器關閉為止(也就是說,直到在伺服器中不再有操作在執行為止)。這樣,你可以在銷毀通信器之前,等待伺服器空閑下來。
destroy
這個操作銷毀通信器及其相關資源,比如線程、通信端點,以及記憶體資源。一旦你銷毀了通信器(是以也就銷毀了該通信器的runtime),你不能再調用其他任何Ice 操作(除非建立另外的通信器)。
在離開程式的main 函數之前要調用destroy,不這樣做會導緻不确定的行為。
在離開main 之前調用destroy 是必需的,因為destroy 會在傳回之前等待所有運作中的線程終止。如果你沒有調用destroy 就離開main,你就會留下許多仍在運作的線程;許多線程包不允許你這樣做,你最終會使程式崩潰。
如果你沒有調用shutdown 就調用destroy,在這個調用傳回之前,它會等待所有執行中的操作調用完成(也就是說, destroy 的實作隐含地調用shutdown,然後調用waitForShutdown)。shutdown (是以,也包括destroy)會解除與通信器相關聯的所有對象擴充卡的激活狀态。Since destroy blocks until all operation invocations complete, a servant will deadlock if it invokes destroy on its own communicator while executing a dispatched operation.
在用戶端,如果你在操作執行過程中調用shutdown,這些操作會終止,抛出CommunicatorDestroyedException。