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实现服务间调用_第1张图片

该架构图显示应用之间使用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 FruitPlatter;

sequence FruitBanquet; (集合的集合)

也可以在前面标识出该类型在java中所对应的类型,如:

["java:type:java.util.ArrayList"] sequence stringList;

dictionary

Map类型,类似于Java HashMap,如:

dictionary 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实现服务间调用_第2张图片

4.2、编写服务端

然后我们新开一个工程,并将上述生成的文件拷入新工程,同时引入开发ice所需要的jar包:

        
            com.zeroc
            ice
            3.7.2
        

新建一个服务实现类 HelloWorldHandler

public class HelloWorldHandler implements HelloWorldIDL {

    @Override
    public String sayHello(String username, Current current) {
        // 可以通过Current对象获取到客户端额外透传的参数
        Map 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 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精华,有时间且有兴趣需要学习。

你可能感兴趣的:(中间件,rpc,Ice)