天天看點

ZeroC Ice-java簡單案例

目錄

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調用,也支援移動裝置,使得開發起來更為友善。其用戶端與服務端的架構如下:

ZeroC Ice-java簡單案例

該架構圖顯示應用之間使用Ice作為中間件平台,用戶端及服務的的應用都是由應用代碼即Ice的庫代碼混合組成的,且兩者使用的開發語言甚至都不同。上述代理是根據Slice定義的ice檔案實作,它提供了一個向下調用的接口,提供了資料的序列化與反序列化。Ice的核心部分提供了用戶端與服務端的網絡連接配接等核心通信功能,以及其他的網絡通信功能的實作及可能問題的處理。

2、Ice下載下傳

下載下傳Ice的話直接移步官網即可,本文處于mac的環境下,以最新版本3.7為例

https://zeroc.com/downloads/ice/3.7/java

下載下傳完成後使用 slice2java -v 可以檢視到目前Ice的版本号。

ZeroC Ice-java簡單案例

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服務類

ZeroC Ice-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精華,有時間且有興趣需要學習。