在上一篇文章中,我使用了自己实现的一个简单容器简单粗暴的启动一个ICE服务,正如上篇文章所总结的那样,这种部署服务的方式存在诸多缺点。
这里我们给出使用IceBox这个框架来开发和部署我们的Ice服务。
那么什么是IceBox框架呢?
这是IceBox的官方文档地址:IceBox 官方文档
这里我用简洁易懂的描述翻译一下 文档中所说的使用IceBox框架开发的好处:
(1):由同一个IceBox服务所加载的多个Ice服务之间可以得到调用优化。比如IceBox服务加载了A\B两个Ice服务,如果A服务调用B服务,通过配置IceBox的参数,这时候就不用发起网络寻址了,直接进行本地调用。
(2):如果一个应用程序是由多个服务组成,通过使用IceBox可以通过配置参数实现服务组合,而不必通过编译和连接,这就实现了不同服务之间的解耦。
(3):由一个IceBox服务所加载的不同Ice服务可以共用一个JVM实例,这样可以节省操作系统的资源
(4):服务通过实现IceBox Service接口,这为开发人员提供了统一的开发框架和集中的服务管理工具
(5):IceBox整合到了IceGrid,IceGrid可以实现服务的激活和部署。
IceBox其实就像我们部署web工程用的Tomcat容器一样,我们只要写好若干个服务,通过统一的配置文件配置服务列表,服务启动的次序等,然后启动IceBox,我们的服务就会被加载和启动。
接下来我们就用IceBox框架,来改造我们在上一篇博客中的查询雇员信息服务。
(1)改造服务端代码
/**
* 使用IceBox 来加载启动 ice服务
* 服务要实现Service接口 并重新start 和 stop方法
* @author yujie.wang
*
*/
public class QueryEmployeeServer implements Service{
//创建适配器实例
private ObjectAdapter adapter;
/**
* ice服务在start方法中初始化
* paramString :ice Object 标识符
* paramCommunicator: Ice 通信器
* paramArrayOfString : 服务启动的一些初始化参数
*/
@Override
public void start(String paramString, Communicator paramCommunicator,
String[] paramArrayOfString) {
// TODO Auto-generated method stub
adapter = paramCommunicator.createObjectAdapter(paramString);
QueryEmployeeImpl servant = new QueryEmployeeImpl();
adapter.add(servant, paramCommunicator.stringToIdentity(paramString));
// 激活adapter
adapter.activate();
System.out.println("adapter has been activate");
}
@Override
public void stop() {
// TODO Auto-generated method stub
adapter.destroy();
System.out.println("adapter has been destory");
}
}
start方法为服务启动方法,创建adapter,创建服务实现servant,激活adapter.
stop方法为服务停止方法,这里销毁服务所使用的资源
服务的客户端代码是不变的,还是上篇博客中的客户端代码示例。
(2)配置IceBox的配置文件
IceBox的配置文件内容分为两部分,一部分是具体Ice服务所有的属性,另一部分是所有Ice服务共用的属性
我们直接看本项目所使用的配置文件如下配置文件命名为config.properties:
#IceBox 实例名字
IceBox.InstanceName=YuJieIceBox 1
#让所有Ice服务实例都使用公共的配置参数
IceBox.InheritProperties=1
#所有服务都初始化完成之后会打印YuJieIceBox 1 ready
IceBox.PrintServicesReady=YuJieIceBox 1
#IceBox远程服务管理组件 默认是关闭的
IceBox.serviceManager.Endpoints=tcp -p 9999 -h 10.4.30.81
#performance properties
IceBox.ThreadPool.Server.Size=4
IceBox.ThreadPool.Server.SizeMax=100
IceBox.ThreadPool.Server.SizeWarn=40
IceBox.ThreadPool.Client.Size=4
IceBox.ThreadPool.Client.SizeMax=100
IceBox.ThreadPool.Client.SizeWarn=40
#for system stronger
Ice.ACM.Client=300
Ice.ACM.Server=300
#log and trace
#Ice.LogFile=iceserver.log
Ice.PrintStackTraces=1
Ice.Trace.Network=2 #开启网络事件追踪日志
Ice.Trace.ThreadPool=1 #开启线程池事件追踪日志
Ice.Warn.Connections=1
Ice.Warn.Dispatch=1
Ice.Warn.Endpoints=1
#Ice具体服务定义开始
#queryServer为Ice对象标识符 必须是唯一的
#com.yujie.ice.server.QueryEmployeeServer为实现IceBox.Service接口的实现类全路径
#prop1=1 prop2=2 prop3=3 Ice服务初始化参数
IceBox.Service.queryServer=com.yujie.ice.server.QueryEmployeeServer prop1=1 prop2=2 prop3=3
#配置一个Ice对象标识符为SMSService的Ice服务
#IceBox.Service.SMSService=com.SMSServiceI2
queryServer.Endpoints=tcp -p 10006 -h 10.4.30.81
#SMSService.Endpoints=tcp -p 10007 -h 10.4.30.81
#Ice具体服务定义结束
#可以配置服务启动的次序 如果有多个Ice服务可以配置如下
#IceBox.LoadOrder=queryServer ,SMSService
IceBox.LoadOrder=queryServer
#值为1表示开启本地调用优化
IceBox.UseSharedCommunicator.queryServer=1
#IceBox.UseSharedCommunicator.SMSService=1
(3)部署Ice服务
我们这里还是利用上篇文章我自己写的一个简单容器来部署这个Ice服务,将修改过的代码打包成yujie-ice-test2.jar 放入容器lib目录
不过 增加了一个conf目录用来存放IceBox的配置文件config.properties
并且修改了启动脚本
最终容器目录如下:
我们执行 sh startIceServer.sh & 启动服务,之后调用客户端代码
服务启动后输出:
客户端调用服务之后输出:
(4)总结
目前为止我们这种部署方式仍然存在一个很严重的问题,就是客户端服务寻址的问题,我们目前都是讲服务端的EndPoint写死到客户端的,一是这样部署不灵活,客户端要随着服务端的迁移和重写,二是无法实现服务的负载均衡。
下篇博客 我将引出另一个Ice组件来解决这个问题。