目錄
1、Ice簡介
2、Ice下載下傳
3、Slice
3.1、基本資料類型
3.2、常量定義
3.3、複合資料結構定義
3.4、異常定義
3.5、Slice檔案複用
3.6、接口和方法定義
4、使用java實作一個執行個體
4.1、編寫腳本
4.2、編寫服務端
4.3、編寫用戶端
1、Ice簡介
Ice是ZeroC的開源通信産品,是一個面向對象的中間件,全程為:The Internet Communications Engine。其作為一款優秀的RPC工具,不僅性能強勁,而且支援多平台多語言開發,即服務端和用戶端使用到的開發語言可以是不同的。Ice讓我們能夠以最小的代價去建構分布式應用,隻需要專注業務邏輯即可,底層的通訊邏輯完全由ICE幫我們封裝實作。
另一方面,Ice也算是一款老牌RPC架構,其已經有十多年的沉澱,不僅支援伺服器端的RPC調用,也支援移動裝置,使得開發起來更為友善。其用戶端與服務端的架構如下:
該架構圖顯示應用之間使用Ice作為中間件平台,用戶端及服務的的應用都是由應用代碼即Ice的庫代碼混合組成的,且兩者使用的開發語言甚至都不同。上述代理是根據Slice定義的ice檔案實作,它提供了一個向下調用的接口,提供了資料的序列化與反序列化。Ice的核心部分提供了用戶端與服務端的網絡連接配接等核心通信功能,以及其他的網絡通信功能的實作及可能問題的處理。
2、Ice下載下傳
下載下傳Ice的話直接移步官網即可,本文處于mac的環境下,以最新版本3.7為例
https://zeroc.com/downloads/ice/3.7/java
下載下傳完成後使用 slice2java -v 可以檢視到目前Ice的版本号。
3、Slice
這是使用Ice所必須編寫的一個中間檔案,常用來生成代理對象,其全程為 Specification Language for Ice ,作為在服務端與用戶端之間調用所使用到的一門中間語言,其有自身的文法,與java其實還挺相似。
3.1、基本資料類型
類型 | 定義及範圍 | 長度 |
bool | true of false | ≥ 1bit |
byte | [-128, 127] or [0, 255] | ≥ 8bit |
short | [-2^15, 2^15-1] | ≥ 16bit |
int | [-2^31, 2^31-1] | ≥ 32bit |
long | [-2^63, 2^63-1] | ≥ 64bit |
float | ≥ 32bit | |
double | ≥ 64bit | |
string | variable-length |
3.2、常量定義
用 const 修飾,如:
const bool trueOrFalse = true;
const byte b = 0x0f;
const string msg = “hello”;
const short s = 56;
const double PI = 3.1416;
enum Fruit {Apple, Orange}; (enum類型其實等價于int)
const Fruit favoriteFruit = Orange;
3.3、複合資料結構定義
類型 | 含義說明 |
enum | 枚舉,如: enum Fruit {Apple, Orange} 或: enum Fruit {Apple = 5, Orange = 1} 實際上enum類型等價于int |
struct | 結構體,保護多個屬性資料,類似與JavaBean。 struct Student { int id; string name; } |
sequence | 複合類型,支援 基本類型的集合 或者 複合類型的集合,如: sequence<Fruit> FruitPlatter; sequence<FruitPlatter> FruitBanquet; (集合的集合) 也可以在前面辨別出該類型在java中所對應的類型,如: ["java:type:java.util.ArrayList<String>"] sequence<string> stringList; |
dictionary | Map類型,類似于Java HashMap,如: dictionary<long, Student> StudentMap |
3.4、異常定義
exception Error {}; // 可定義空異常
exception RangeError {
TimeOfDay errorTime;
TimeOfDay minTime;
TimeOfDay maxTime;
};
3.5、Slice檔案複用
使用#include關鍵字可引用其他slice檔案:
#include common.slice
3.6、接口和方法定義
使用interface來申明接口(文法上跟java定義接口文法類似,隻是沒有public關鍵字),如:
interface Clock {
TimeOfDay getTime();
void setTime(TimeOfDay time);
}
4、使用java實作一個執行個體
4.1、編寫腳本
首先需要編寫一個Slice檔案,檔案必須以.ice結尾,如下定義一個 HelloWorldIDL.ice 檔案:
[["java:package:myice.demo"]]
module test {
interface HelloWorldIDL {
string sayHello(string username);
};
};
第一行定義java的父包路徑,module定義子產品名,是以最後生成的檔案的包路徑為:myice.demo.test
需要注意的是,在.ice檔案 module 部分是不可或缺的,同時任何 } 後都需要跟 ;
然後我們需要使用該檔案來生成通用服務類,如下:
slice2java --output-dir ./generated ./slice/HelloWorldIDL.ice
此時在generated目錄下即有一大堆java服務類
4.2、編寫服務端
然後我們新開一個工程,并将上述生成的檔案拷入新工程,同時引入開發ice所需要的jar包:
<dependency>
<groupId>com.zeroc</groupId>
<artifactId>ice</artifactId>
<version>3.7.2</version>
</dependency>
建立一個服務實作類 HelloWorldHandler
public class HelloWorldHandler implements HelloWorldIDL {
@Override
public String sayHello(String username, Current current) {
// 可以通過Current對象擷取到用戶端額外透傳的參數
Map<String, String> extraParameters = current.ctx;
String extraStrings = null;
if (!CollectionUtils.isEmpty(extraParameters)) {
StringBuilder builder = new StringBuilder();
extraParameters.forEach((key, value) -> builder.append(key).append("-").append(value).append(";"));
extraStrings = builder.deleteCharAt(builder.length() - 1).toString();
}
return "Hello Zeroc ICE, " + username + ",extra param:" + extraStrings;
}
}
然後再建立一個服務端注冊并監聽請求的一個類 HelloWorldServer
public class HelloWorldServer {
public static void main(String[] args) {
Communicator communicator = null;
try {
// 初始化ICE Communicator對象,args可以傳一些初始化參數,如連接配接逾時、初始化用戶端連接配接池數量等
communicator = Util.initialize(args);
// 使用預設的通信協定(TCP/IP),用于監聽請求
ObjectAdapter adapter = communicator.createObjectAdapterWithEndpoints("helloWorldHandler", "default -p 7890");
// 建立服務端接口處理handler執行個體(ice裡稱為servant)
HelloWorldHandler helloWorldHandler = new HelloWorldHandler();
// 将建立的執行個體添加到adapter中
adapter.add(helloWorldHandler, Util.stringToIdentity("helloWorldHandler"));
// 激活adapter
adapter.activate();
// 在服務退出前,一直監聽請求
communicator.waitForShutdown();
} catch (Exception e) {
e.printStackTrace();
} finally {
// 關閉服務
if (null != communicator) {
communicator.destroy();
}
}
}
}
4.3、編寫用戶端
public class HelloWorldClient {
public static void main(String[] args) {
Communicator communicator = null;
try {
// 如服務端一樣初始化Communicator對象
communicator = Util.initialize(args);
// 傳入遠端服務接口的名稱、網絡協定、IP和端口,建立一個代理對象
ObjectPrx prx = communicator.stringToProxy("helloWorldHandler:default -p 7890");
// 通過slice腳本生成的類(以Prx結尾),向下轉型擷取到具體的用戶端代理類
HelloWorldIDLPrx helloWorldIDLPrx = HelloWorldIDLPrx.checkedCast(prx);
if (null != helloWorldIDLPrx) {
// 在調用方法時此處也可以額外傳參到服務端,服務端在Current對象的ctx屬性中可以取到
Map<String, String> params = new HashMap<>();
params.put("key", "value");
String result = helloWorldIDLPrx.sayHello("I'm client", params);
System.out.println(result);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (communicator != null) {
communicator.destroy();
}
}
}
}
然後分别啟動服務端與用戶端,可以看到控制台列印如下:
Hello Zeroc ICE, I'm client,extra param:key-value
寫在末尾,IceBox以及IceGrid是Ice的學習重點,也是Ice精華,有時間且有興趣需要學習。