1、需要了解ICE運作環境對用戶端請求的調用分派語義,即當一個請求到來時,如何查找到對應到servant服務對象進行消息處理
A、在ASM 中查找該辨別。如果ASM 有這樣一個條目,就把請求分派到對應的servant。
B、如果到來的對象辨別的範疇不是空的,就查找針對該範疇注冊的servant定位器。如果有這樣的servant 定位器,就調用這個定位器的locate,
如果locate 傳回一個servant,就把請求分派到該servant,然後調用finished ;而如果locate 調用傳回null,就在用戶端引發
ObjectNotExistException。
C、如果到來的對象辨別的範疇是空的,或者在找不到針對該範疇的servant 定位器,就去查找預設的servant 定位器(也就是,針對空範疇
注冊的servant 定位器)。如果有預設的servant 定位器,就像上一步那樣分派請求。
D、如果上述操作均找不到對應的servant,則在用戶端ObjectNotExistException。
2、通過如下的方法在一個Objectadapter中操作servant的定位器:
virtual void addServantLocator(const ServantLocatorPtr&, const std::string&); // 指定範疇注冊定位器,如果範疇為空,則是預設定位器
virtual ServantLocatorPtr removeServantLocator(const std::string&); // 移除定位器,該定位器上不會再有新請求,老請求繼續
virtual ServantLocatorPtr findServantLocator(const std::string&) const; // 指定範疇查找定位器
3、Servant定位器的實作樣例:
class OCCIServantLocator : public Ice::ServantLocator
{
public:
virtual Ice::ObjectPtr locate(const Ice::Current&, Ice::LocalObjectPtr&);
virtual void finished(const Ice::Current&, const Ice::ObjectPtr&, const Ice::LocalObjectPtr&);
virtual void deactivate(const std::string&);
};
注意:
A、ICE調用定位器的locate和finished方法是在同一個線程中進行的。(AMD方法除外)
B、如果locate傳回了一個servant,那麼在servant的操作請求完成時,一定會調用finished方法以友善資源回收
C、可以再locate方法中傳回一個cookie對象,那麼在finished方法調用時,該cookie會發送給finished方法
D、隻有當communicator或者objectadapter對象關閉時,才會調用定位器的deactivate方法
E、如果在定位器對象中存在一些臨界資源修改,需要對這些臨界資源進行同步互斥保護
F、可以再locate和finished方法中抛出異常,這些異常會抛送給用戶端
4、為每個服務操作申明執行個體化一個服務處理對象時最容易了解的普通做法,但是在一個受限資源系統上是不可接受的。為了解決系統啟動時就建立多個
servant執行個體所帶來的缺陷(可能有些servant壓根就不會使用、啟動過程中執行個體化可能導緻比較慢的啟動),可以通過servant定位器來實作延遲執行個體化
和按需執行個體化。
Ice::ObjectPtr MyServantLocator::locate(const Ice::Current & c, Ice::LocalObjectPtr &)
{
IceUtil::Mutex::Lock lock(_m);
// Check if we have instantiated a servant already.
Ice::ObjectPtr servant = c.adapter.identityToServant(c.id);
if(!servant) { // We don't have a servant already
// Instantiate a servant.
servant = new ServantI(c.id.name);
// Add the servant to the ASM.
c.adapter->add(servant, c.id);
}
return servant;
}
4、預設服務處理對象。預設服務處理對象存在的理由時,要為每類請求建立一個對應的servant執行個體在受限資源系統上是不可接受的。
那麼使用預設的服務處理對象,讓所有請求都用一個執行個體化對象來處理時一種不錯的選擇,通過如下的方法設定預設服務處理對象:
virtual void addDefaultServant(const ObjectPtr&, const std::string&);
在objectadapter上指定特屬範疇的預設服務處理對象。
那麼為了能夠區分每個服務調用請求,一種常用的做法是:在服務處理函數中通過current.id.name來區分
每個servant需要有一個ice_Ping方法來判斷servant是否還存活,由于預設處理對象合并了多數servant的服務調用,是以需要顯示
的實作ice_Ping方法來判斷current.id.name是否還存活。
5、采用servant定位器來實作servant的按需執行個體化是一種不錯的改進,但是這樣還是存在一個問題,就是龐大的servant執行個體往往在資源受限系統上
得不到滿足,為此,ICE提供了一種改進的servant定位器"逐出器(evictor)"
逐出器是一種特殊的servant定位器,除了實作servant定位器的虛拟接口locate和finished之外,還實作了在内部管理了一個所謂的ASM,
而不是用Objectadapter上的預設ASM來存儲ASM,同時在内部的ASM上實作了LRU的淘汰算法。
實作一個逐出器的方法如下:
class MyEvictor : public Ice::EvictorBase
{
public:
virtual Ice::ObjectPtr add(const Ice::Current&, Ice::LocalObjectPtr&);
virtual void evict(const Ice::ObjectPtr&, const Ice::LocalObjectPtr&);
};
注意:
A、EvictorBase的回調方法add、evict和ServantLocator的回調方法locate、finished功能類似
B、注意不要試圖在add方法中做類似locate方法中添加servant到ASM中
C、add和evict方法都支援cookie參數的傳遞,可以傳遞使用者指定的上下文資訊
D、在類似如資料庫代理的服務系統中,要為每條記錄建立一個servant對象不太現實,使用預設對象又不太高效,使用Evictor是一個不錯的選擇