IceBox是一个易于使用的Ice应用程序服务的框架。服务配置器模式[1]是配置服务和集中管理的有用技术。实际上,这意味着服务被开发为可动态加载的组件,其可以被配置为通用目的“超级服务器”,无论任何组合是必要的。 IceBox是Ice服务的Service Configurator模式的实现。
一个通用的IceBox服务器取代了你通常写的典型的整体Ice服务器。 IceBox服务器通过属性配置特定于应用程序的服务,它负责加载和管理,它可以远程管理。使用这种架构有几个优点:
由相同的IceBox服务器加载的服务可以配置为利用Ice的搭配优化。例如,如果一个服务是另一个服务的客户端,并且那些服务驻留在同一IceBox服务器中,则可以优化它们之间的调用。
撰写由各种服务组成的应用程序是通过配置完成的,而不是通过编译和链接。这使服务与服务器分离,允许根据需要组合或分离服务。
多个Java服务可以在Java虚拟机(JVM)的单个实例中处于活动状态。与运行多个单独的服务器(每个都在其自己的JVM中)相比,这节省了操作系统资源。
服务实现了IceBox服务接口,为开发人员和集中式管理设施提供了一个通用框架。
IceBox支持集成到IceGrid,服务器激活和部署服务。
IceBox提供了一个清晰的视角变化:开发人员专注于写作服务,而不是应用程序。应用程序的定义也会改变;使用IceBox,应用程序变成离散服务的集合,其组成由配置动态地确定,而不是由链接器静态地确定。
开发IceBox服务
IceBox服务接口
编写IceBox服务需要实现IceBox服务接口:
module IceBox {
local interface Service {
void start(string name, Ice::Communicator communicator, Ice::StringSeq args);
void stop();
};
};
可以看到,一个服务只需要实现两个操作,启动和停止。这些操作由服务器调用;在服务加载后调用start,而当IceBox服务器关闭时调用stop。
启动操作是服务的初始化机会;这通常包括创建对象适配器和服务器。 name和args参数从服务的配置提供信息,而communicator参数是由服务器创建的用于服务使用的Ice :: Communicator对象。根据服务配置,此通信器实例可能由同一IceBox服务器中的其他服务共享,因此应注意确保诸如对象适配器之类的项目具有唯一的名称。
停止操作必须回收该服务使用的任何资源。通常,服务停用其对象适配器,并且还可能需要调用对象适配器上的waitForDeactivate,以便确保在清理进程可以继续之前所有未决请求已经完成。服务器负责销毁传递给启动的通信器实例。
服务的实现是否停止应该显式地销毁其对象适配器取决于其他因素。例如,如果服务使用共享通信器,则适配器应该被销毁,特别是如果服务最终可以重新启动。在其他情况下,服务可以允许其适配器被销毁作为通信器的破坏的一部分。
这些接口被声明为本地的,原因如下:它们表示服务器和服务之间的合同,并且不打算供远程客户端使用。服务与远程客户端的任何交互都通过由服务创建的服务器完成。
IceBox服务示例在C ++中
我们在这里展示的例子取自Ice分发中提供的IceBox / hello示例程序。
我们的服务的类定义很简单,但有一些值得一提的方面:
#include <IceBox/IceBox.h>
#if defined(_WIN32)
# define HELLO_API __declspec(dllexport)
#else
# define HELLO_API /**/
#endif
class HELLO_API HelloServiceI : public IceBox::Service {
public:
virtual void start(const std::string&,
const Ice::CommunicatorPtr&,
const Ice::StringSeq&);
virtual void stop();
private:
Ice::ObjectAdapterPtr _adapter;
};
首先,我们包括IceBox头文件,以便我们可以从IceBox :: Service中导出我们的实现。 第二,预处理器定义是必要的,因为在Windows上,此服务驻留在动态链接库(DLL)中,因此我们需要导出类以便服务器可以正确加载它。
成员定义同样简单:
#include <Ice/Ice.h>
#include <HelloServiceI.h>
#include <HelloI.h>
using namespace std;
void
HelloServiceI::start(
const string& name,
const Ice::CommunicatorPtr& communicator,
const Ice::StringSeq& args)
{
_adapter = communicator->createObjectAdapter(name);
Ice::ObjectPtr object = new HelloI(communicator);
_adapter->add(object, communicator->stringToIdentity("hello"));
_adapter->activate();
}
void
HelloServiceI::stop()
{
_adapter->deactivate();
}
start方法创建与服务具有相同名称的对象适配器,激活一个类型为HelloI的单个服务方(未示出),并激活对象适配器。 停止方法简单地停用对象适配器。
C ++服务入口点
最后一个谜题是入口点函数,IceBox服务器调用它来获取服务的实例:
extern "C" {
HELLO_API IceBox::Service*
create(Ice::CommunicatorPtr communicator)
{
return new HelloServiceI;
}
}
在此示例中,create函数返回Hello服务的新实例。 函数的名称不重要,但它必须具有上面显示的签名。 特别是,函数必须具有C链接,接受Ice :: CommunicatorPtr类型的单个参数,并返回一个指向IceBox :: Service的本地指针。
C链接是必需的,以便IceBox服务器可以在动态加载的库中定位此函数。 使用C连接的函数的限制阻止我们使用正常的Ice调用约定,它不会返回本地指针,并且总是通过const引用传递智能指针。 例如,这样的函数不能返回对象类型(例如智能指针),这迫使我们返回本地指针。
配置IceBox服务提供了有关入口点的更多信息,并介绍如何将服务配置到IceBox服务器中。
Java中的IceBox服务示例
与上一节中提到的C ++示例一样,Java示例的完整源代码可以在Ice发行版的IceBox / hello目录中找到。 我们的服务的类定义如下:
public class HelloServiceI implements IceBox.Service
{
public void
start(String name, Ice.Communicator communicator, String[] args)
{
_adapter = communicator.createObjectAdapter(name);
Ice.Object object = new HelloI(communicator);
_adapter.add(object, communicator.stringToIdentity("hello"));
_adapter.activate();
}
public void
stop()
{
_adapter.deactivate();
}
private Ice.ObjectAdapter _adapter;
}
start方法创建与服务具有相同名称的对象适配器,激活一个类型为HelloI的单个服务方(未示出),并激活对象适配器。 停止方法简单地停用对象适配器。
服务器要求服务实现具有默认构造函数。 这是Java IceBox服务的入口点; 也就是说,服务器动态加载服务实现类并调用默认构造函数以获取服务的实例。
这个例子是一个简单的服务,你的可能会更有趣,但这表明它是多么容易是一个IceBox服务。 编译服务实现类后,可以将其配置为IceBox服务器,如配置IceBox服务中所述。
IceBox服务示例在C#
C#示例的完整源代码可以在Ice发行版的IceBox / hello目录中找到。 我们的服务的类定义如下:
class HelloServiceI : IceBox.Service
{
public void
start(string name, Ice.Communicator communicator, string[] args)
{
_adapter = communicator.createObjectAdapter(name);
_adapter.add(new HelloI(), communicator.stringToIdentity("hello"));
_adapter.activate();
}
public void
stop()
{
_adapter.deactivate();
}
private Ice.ObjectAdapter _adapter;
}
start方法创建与服务具有相同名称的对象适配器,激活一个类型为HelloI的单个服务方(未示出),并激活对象适配器。 停止方法简单地停用对象适配器。
服务器要求服务实现具有默认构造函数。 这是C#IceBox服务的入口点; 也就是说,服务器从程序集动态加载服务实现类并调用默认构造函数以获取服务的实例。
这个例子是一个简单的服务,你的可能会更有趣,但这表明它是多么容易是一个IceBox服务。 编译服务实现类后,可以将其配置为IceBox服务器,如配置IceBox服务中所述。
IceBox服务失败
服务实现其入口点,启动或停止方法时引发的异常会导致IceBox记录消息。 服务器启动期间发生的异常也会导致服务器终止。
服务实现可以通过提升IceBox :: FailureException来指示失败:
module IceBox {
local exception FailureException {
string reason;
};
};
注意,作为本地异常,C ++用户必须使用文件和行号信息来实例化FailureException:
throw IceBox::FailureException(__FILE__, __LINE__, "my error message");