引言:java
最近比較搓,忙得沒空寫寫博客,回想一下又好像沒忙什麼事。得檢討一下了,固然此是後話。app
本文就Zeroc Ice方法返回複雜類的對象(return by-value, not by-reff),作以簡單說明。之因此有這篇文章,只因筆者發現網上流傳的中文文章中有這麼個空白,英文的也沒個直接的說明。ide
此文用BBCode編寫。svn
內容:測試
1、ICE方法返回對象的實現
2、機制的簡要說明
3、一個Exception的解決
4、資源信息this
正文:google
1、ICE方法返回對象的實現。設計
1,模型設計。代理
如上圖「class_diagram.JPG」所示,Bond(債券)爲JavaBean,MainOperator(主操做者)有一個方法「Bond getBean(String beanUID)」返回一個JavaBean。指針
2,具體實現。(各代碼所在文件名,請參看首註釋中的「file」註釋)
A)slice定義
/* * file: BondDef.ice * by: zhaoningbo * date: 2011-07-25 15:51 */ #ifndef BEAN_BOND_DEF #define BEAN_BOND_DEF module com{ module number{ module bean{ // 債券Bean class Bond{ // Files string bName; string bCode; // Methods string getbName(); void setbName(string bName); string getbCode(); void setbCode(string bCode); }; }; }; }; #endif Java代碼 /* * file: MainOperatorDef.ice * by: zhaoningbo * date: 2011-07-25 16:02 */ #ifndef OPERATOR_MAINOPERATOR_DEF #define OPERATOR_MAINOPERATOR_DEF module com{ module number{ // 預約義 module bean{ class Bond; }; module operator{ // 總執行者 interface MainOperator{ // 獲取Bond對象 idempotent com::number::bean::Bond getBean(string beanUID); }; }; }; }; #endif B)slice2java生成ice的java接口類集 C)編寫服務方 (i)實現Bond。由於Bond是個抽象類,須要給定一個實現BondI。 Java代碼 /* * file: BondI.java */ package com.number.bond; import java.io.Serializable; import Ice.Current; import com.number.bean.Bond; /** * 自定義債券Bean * 注:實現Bond時,直接實現Override便可,無需添加其餘的類元素。 * @author zhnb * */ public class BondI extends Bond implements Serializable { private static final long serialVersionUID = 8758902536680272427L; @Override public String getbCode(Current current) { return this.bCode; } @Override public String getbName(Current current) { return this.bName; } @Override public void setbCode(String bCode, Current current) { this.bCode = bCode; } @Override public void setbName(String bName, Current current) { this.bName = bName; } } (ii)加個dao層數據提供者(僅圖好看) Java代碼 /* * file: BondLCData.java */ package com.number.dao; import java.io.Serializable; import com.number.bond.BondI; /** * 數據提供類 * @author zhnb * */ public class BondLCData implements Serializable { private static final long serialVersionUID = -5413237344986060553L; // 單值 public static BondI BONDLC_DATA_SINGLE = null; static{ BondI bondI= new BondI(); bondI.setbCode("600006"); bondI.setbName("青島啤酒"); BONDLC_DATA_SINGLE = bondI; } } (iii)實現操做者業務類 Java代碼 /* * file: MainOperatorI.java */ package com.number.operator; import java.io.Serializable; import Ice.Current; import com.number.bean.Bond; import com.number.dao.BondLCData; /** * 主操做業務類 * @author zhnb * */ public class MainOperatorI extends _MainOperatorDisp implements Serializable { private static final long serialVersionUID = 1017768576442347413L; @Override public Bond getBean(String beanUID, Current current) { // 獲取一個BondLC對象 Bond bond = BondLCData.BONDLC_DATA_SINGLE; return bond; } } (ix)發佈業務類,註冊到服務 Java代碼 /* * file: MainOperatorServer.java */ package com.number.operator; import java.io.Serializable; import Ice.ObjectAdapter; /** * 主操做服務發佈者 * @author zhnb * */ public class MainOperatorServer implements Serializable { private static final long serialVersionUID = -691557224337330222L; public static void main(String[] args) { // 0, 聲明執行狀態 int status = 0; Ice.Communicator ic = null; try { // 1, 初始化環境 // 加載屬性文件 ic = Ice.Util.initialize(); // 2, 初始化Adapter String name = "MainOperatorServer"; String endpoints = "default -h 127.0.0.1 -p 9999"; ObjectAdapter objAdapter = ic.createObjectAdapterWithEndpoints( name, endpoints); // 3, 建立伺服者 Ice.Object servant = new MainOperatorI(); // 4, 添加伺服者至適配器 objAdapter.add(servant, Ice.Util.stringToIdentity("MainOperatorUID")); // 5, 激活 objAdapter.activate(); System.out.println("<<MainOperatorUID started>>"); // 6, 等待關閉 ic.waitForShutdown(); } catch (Exception e) { e.printStackTrace(); status = 1; } finally { if (ic != null) { ic.destroy(); } System.exit(status); } } 以上類中MainOperatorI主是個普通接口的實現方式,很簡單。BondI是個類的實現方式,須要留意。 D)編寫客戶方 (i)編寫請求者 Java代碼 /* * file: MainOperatorClient.java */ package com.number.operator; import java.io.Serializable; import Ice.ObjectPrx; import com.number.bean.Bond; import com.number.bond.ObjectFactory4Bond; import com.number.except.UGenericException; /** * 請求數據者(通用接口方式) * @author zhnb * */ public class MainOperatorClient implements Serializable { private static final long serialVersionUID = -3207025201067021445L; /** * 獲取債券對象 * @param bondUID 債券標誌 * @return */ public Bond getBean(String bondUID){ Bond bond = null; try { // 獲取代理 MainOperatorPrx mainOperatorPrx = this.getOwnPrx(); /* // 添加自定義類 Ice.ObjectFactory factory = new ObjectFactory4Bond(); this.ic.addObjectFactory(factory, com.number.bond.BondI.ice_staticId()); */ bond = mainOperatorPrx.getBean("anyThingAsArg"); } catch (UGenericException e) { e.printStackTrace(); } return bond; } // =========以<下>爲私有方法,提供ICE支撐。========= // 獲取服務端提供的代理 private MainOperatorPrx mainOperatorPrx = null; // Ice通信員(爲回收資源時,方便自動回收) private Ice.Communicator ic = null; // GC回收時,自動銷燬Ice.Communicator。 @Override protected void finalize() throws Throwable { if (this.ic != null) { ic.destroy(); } super.finalize(); } /** * 獲取代理 * * @return 本類的代理 */ private MainOperatorPrx getOwnPrx() throws UGenericException { // 代理爲空時,自動獲取代理。 if (this.mainOperatorPrx == null) { // 環境爲空時,初始化環境 if (this.ic == null) { // 1, 初始化環境 ic = Ice.Util.initialize(); } // 2, 建立代理基類對象 String str = "MainOperatorUID:default -h 127.0.0.1 -p 9999"; ObjectPrx objPrx = this.ic.stringToProxy(str); // 3, 獲取代理 this.mainOperatorPrx = MainOperatorPrxHelper.checkedCast(objPrx); // 4, 測試是否可用,不可用時拋出異常。 if (this.mainOperatorPrx == null) { throw new UGenericException(str + ", request proxy faild."); } } return this.mainOperatorPrx; } // =========以<上>爲私有方法,提供ICE支撐。========= } (ii)爲客戶端寫個手工測試類 Java代碼 /* * file: StartAllClient.java */ package com.number.start; import java.io.Serializable; import com.number.bean.Bond; import com.number.operator.MainOperatorClient; /** * 啓動使用者 * @author zhnb * */ public class StartAllClient implements Serializable { private static final long serialVersionUID = -6282697303788648813L; public static void main(String[] args) { MainOperatorClient moc = new MainOperatorClient(); Bond bond = moc.getBean("something"); StringBuffer info = new StringBuffer(); if (bond == null) { info.append("null"); } else { info.append("Bond@" + bond.hashCode() + ":"); info.append("bName=" + bond.bName); info.append(",bCode=" + bond.bCode); info.append(":"); info.append("bName=" + bond.getbName()); info.append(",bCode=" + bond.getbCode()); } System.out.println(info.toString()); System.exit(0); } }OK,看樣子寫完了,能夠跑了吧。試個……(提交一下,我去瞅個行號~。=)
唸叨着,「先啓服務run 'MainOperatorServer'……再啓客戶run 'StartAllClient'」……
哦~&*……*出錯了!
Java代碼
Exception in thread "main" Ice.NoObjectFactoryException
reason = ""
type = "::com::number::bean::Bond"
at IceInternal.BasicStream.readObject(BasicStream.java:1444)
Why? ?? !? 不是一直這麼個寫法嘛?!
——若是是這麼個寫法,我也就不花功夫寫這篇文章了。
2、機制的簡要說明
返回值有兩種方式,一種是Ice最喜歡(也是最推薦的)「引用」方式,另外一種是「傳值」方式。在ICE中的含意以下:
「引用」,即客戶端不會拿到類型實體的副本,只拿到一個代理,能夠抽象成一個遠程指針(C系)或者一個對象引用(J系)。
「傳值」,跟「引用」相對,即拿到類型實體的副本。
(此處略去兩者特色,即便用範圍,約一千字。)
所以傳接口的時候,就相似於「遠程過程調用」的感受,屬於「行爲」性。可抽象成一系列的接口,實現C-S間的規範協議。而傳值時,有「序列反序列」的味道,屬於「實體」性。須要傳方有個打包成序列的模板,收方有個解包成對象的模板。回觀上文報錯,釋然了。
3、一個Exception的解決
一個Exception指的是「NoObjectFactoryException」,無對象工廠異常。當客戶方拿到一箱Bond的零件後,他找不到工廠給的對象裝配圖。傻眼了的意思。
人工建圖。沒有拿到模型,可是知道有個「Bond.java」抽象的不能使,那就直接實現一個最基礎的吧。造個BondI當臨時模板使着吧,先!
/* * file: BondI.java */ package com.number.bond; import java.io.Serializable; import Ice.Current; import com.number.bean.Bond; /** * 自定義債券Bean(LC, 本地類) * @author zhnb * */ public class BondI extends Bond implements Serializable { private static final long serialVersionUID = 8758902536680272427L; // Methods @Override public String getbCode(Current current) { return this.bCode; } @Override public String getbName(Current current) { return this.bName; } @Override public void setbCode(String bCode, Current current) { this.bCode = bCode; } @Override public void setbName(String bName, Current current) { this.bName = bName; } } 建好了,怎麼告訴裝配工呢。ICE的裝配工,會看已有的圖紙,也會手機上網去ObjectFactory試着查還沒裝到本身包裏的圖紙。那咱們就把裝配圖傳到ObjectFactory上去吧! (i)建立一個ObjectFactory規範下的裝配圖 Java代碼 /* * file: ObjectFactory4Bond.java */ package com.number.bond; import Ice.Object; import Ice.ObjectFactory; /** * 傳值方式,必須實現一個自定義類工廠。 * @author zhnb * */ public class ObjectFactory4Bond implements ObjectFactory { @Override public Object create(String type) { System.out.println("!!>type=" + type); if (type.equals(com.number.bond.BondI.ice_staticId())) { return new BondI(); } return null; } @Override public void destroy() { // TODO Auto-generated method stub } }(ii)拿到這箱Bond前,把裝配圖傳到ObjectFactory上去。
定位: 正文 | 1、ICE方法返回對象的實現 | 2,具體實現。| D)編寫客戶方
找到:「MainOperatorClient.java」第34~38行,把註釋部分放出來。
註釋掉的這兩行代碼,將裝配圖「BondI」放到ObjectFactory上去。以備裝配工查看。
(iii)再次運行,經過。顯示以下
Java代碼
!!>type=::com::number::bean::Bond
Bond@12830537:bName=青島啤酒,bCode=600006:bName=青島啤酒,bCode=600006
4、資源信息
你能夠在code google上下載到此demo的源代碼,只需熱身一下你的SVN。
Java代碼
svn checkout http://number-icedemo-base.googlecode.com/svn/trunk/ number-icedemo-base-read-only
補充:
有未說明清楚的問題,歡迎尾隨追貼。~,=