IceBox是什么
一种易于使用的 Ice 应用服务框架
Service Configurator 模式
- 这种技术可用于配置服务、并把对它们的管理集中在一起。
- 用实践中的术语说,这意味着服务被开发成可动态加载的组件,并且可以按照需要,以任何一种组合方式配置进一个通用的 “超级服务器”中。
- IceBox 是 Service Configurator 模式的一种用于 Ice 服务的实现。
IceBox优点
1.优化:你可以对同一个IceBox服务器加载的多个服务进行配置,利用Ice的并置优化。
例如:如果一个服务是另一个服务的客户,而这两个服务驻留在同一个 IceBox 服务器中,那么在它们之间进行的调用就可以优化。
2.解耦:要把多个服务组合成一个应用,可以通过配置、而不是编译和链接来完成。
这解除了服务和服务器的耦合,允许你按照需要组合服务或分离服务。
3.节省资源:在 Java Virtual Machine (JVM) 的单个实例中,可以有多个活动的 Java 服务。
与在多个 JVM 中分别运行一个整体式的服务器相比,上面的这种做法能够节省操作系统资源。
4.集中式管理:各个服务要实现 IceBox 服务接口,为开发者提供了一个公共框架,以及一个集中式的管理设施。
5.支持:在服务器激活和部署服务 IcePack 中集成了 IceBox 支持。
服务管理器
IceBox::ServiceManager
这个对象负责加载和初始化服务,并执行客户所要求的管理动作。
ServiceManager 接口只支持 shutdown,用于终止服务、关闭 IceBox 服务器。
端点配置
IceBox.ServiceManager.Endpoints=tcp -p 10000
客户配置
ServiceManager.Proxy=ServiceManager:tcp -p 10000
管理实用程序
Usage: iceboxadmin [options] [command...]
Options:
-h, --help
-v, --version
Commands:
shutdown
Show this message.
Display the Ice version.
Shutdown the server.
开发服务
要编写 IceBox 服务,需要实现某个 IceBox 服务接口。
module IceBox {
local interface ServiceBase {
void stop();
};
local interface Service extends ServiceBase {
void start(string name,
Ice::Communicator communicator,
Ice::StringSeq args)throws FailureException;
};
};
你可以看到,服务只需实现两个操作:start 和 stop。这些操作由服务管理器调用;
start 在服务加载后被调用。
stop 在服务关闭时被调用。
配置服务器
1.要把服务配置进 IceBox 服务器中,只需使用一个属性。这个属性的用途有好几个:
定义服务的名字
向服务管理器提供服务进入点
定义用于服务的属性和参数
2.下面是这个属性的格式:
IceBox.Service.name=entry_point [args]
* name 是服务名。这个名字会传给服务的start操作,在配置进同一个 IceBox 服务器的所有服务中必须是唯一的。
用不同的名字加载同一个服务的两个或多个实例是可能的,尽管你很少需要这么做。
* 属性值的第一个参数用于指定进入点。对于 C++ 服务,其形式必须是 library:symbol
- library 是服务共享库或 DLL 的简单名字,而 symbol 是进入点函数的名字。
- 我们所说的 “简单名字”是指,没有任何与特定平台有关的前缀或扩展名的名字;服务管理器会根据平台附加适当的前缀或扩展名。
- 例如:简单名字 MyService 在 Windows 上对应的是名为 MyService.dll 的 DLL,
在 Linux 上对应的是名为 libMyService.so 的共享库。共享库或 DLL 所在的目录必须出现在Windows 上的 PATH 或 POSIX 系统上的 LD_LIBRARY_PATH 中。
* 对于 Java 服务,进入点就是服务实现类的完整类名 (包括任何 package)。
- 这个类必须位于 IceBox 服务器的类路径上。
- 跟在 entry_point 后面的任何参数都会被检查。
- 如果某个参数的形式是 --name=value,它就会被解释为属性定义,将会出现在传给服务的 start 操作的通信器的属性集中。这些参数将被移除,剩下的参数会放在 args 参数中传给 start 操作。
C++ 例子
IceBox.Service.Hello=HelloService:create \
--Ice.Trace.Network=1 hello there
使用这个配置,将会创建一个名为 Hello 的服务。
这个服务应当位于 HelloService.dll (Windows)或 libHelloService.so (Linux) 中
进入点函数 create 会被调用,创建服务的一个实例。
参数 -- Ice.Trace.Network=1被转换成属性定义,
参数hello和there则会成为传给 start 方法的 args 序列参数中的两个元素。
Java 例子
IceBox.Service.Hello=HelloServiceI \
--Ice.Trace.Network=1 hello there
使用这个配置,将会创建一个名为 Hello 的服务。
这个服务应当位于 HelloServiceI 类中。
参数 --Ice.Trace.Network=1 被转换成属性定义,
参数 hello 和 there 则会成为传给 start 方法的 args 序列参数中的两个元素。
Freeze 配置
Freeze 服务支持一个额外的配置属性,用于定义服务管理器创建 Freeze数据库环境所用的目录的路径名:
IceBox.DBEnvName.name=path
属性键的 name 部分是服务名。
共享一个通信器
IceBox.UseSharedCommunicator=1
加载服务
在缺省情况下,服务管理器加载服务的次序是不确定的,也就是说,同一个 IceBox 服务器中的各个服务不应该相互依赖。
如果多个服务必须按照特定的次序加载,可以使用 IceBox.LoadOrder 属性:
IceBox.LoadOrder=Service1,Service2
在这个例子中, Service1 首先加载,接着是 Service2。剩下的其他服务在 Service2 之后以不确定的次序加载
Freeze 服务
module IceBox {
local interface FreezeService extends ServiceBase {
void start(string name,
Ice::Communicator communicator,
Ice::StringSeq args,
Freeze::DBEnvironment dbEnv) throws FailureException;
};
};
启动IceBox
启动C++服务器
IceBox.ServiceManager.Endpoints=tcp -p 10000
IceBox.Service.Hello=HelloService:create
Hello.Endpoints=tcp -p 10001
注意,我们为 Hello 服务创建的对象适配器定义了一个端点。
假定这些属性位于名为 config 的配置文件中,我们可以这样启动 C++ IceBox 服务器:
$ icebox –Ice.Config=config
启动Java服务器
IceBox.ServiceManager.Endpoints=tcp -p 10000
IceBox.Service.Hello=HelloServiceI
Hello.Endpoints=tcp -p 10001
假定这些属性位于名为 config 的配置文件中,我们可以这样启动 Java IceBox 服务器:
$ java IceBox.Server –Ice.Config=config
在启动时, IceBox 服务器会检查它的配置,查找所有具有前缀 IceBox.Service 的属性,并初始化每个服务。如果某个服务的初始化失败了, IceBox 服务器会调用任何已初始化的服务的 stop 操作,报告错误并终止。