ice并不大众,但功能却很强大,能跨平台,能分布式.关于ice,有位大神总结的非常棒,关于它的前生今世都说的非常清楚,ICE简单介绍及使用示例.
我这里再总结一下,便于自己的记忆吧.
安装ICE
先在https://zeroc.com/distributions/ice下载安装文件,我用的是3.31.
配置环境
安装完成后,将环境变量ICE_HOME设置后,将%ICE_HOME%/bin目录加到path中,再将%ICE_HOME%/lib/bd.jar和%ICE_HOME%/lib/Ice.jar也加class环境中.
编写ICE文件
不带包
module demo {
interface Zan{
void printString(string s);
void add(int a ,int b);
};
};
带包
[["java:package:cn.cai.ice"]]
module component {
interface Zan{
string doRequest(string jsonStr);
};
};
生成文件
在Zan.ice文件保存目录(不能在磁盘目录)执行命令:
slice2java Zan.ice
搞定。代码编写
Server
public class Server {
public static void main(String[] args) {
PropertyConfigurator.configure("src/log4j.properties");
int status = 0;
Ice.Communicator ic = null;
try {
// 初使化连接,args可以传一些初使化参数,如连接超时时间,初使化客户连接池的数量等
ic = Ice.Util.initialize(args);
//创建名为SimplePrinterAdapter的适配器,并要求适配器使用缺省的协议(TCP/IP侦听端口为10000的请求)
Ice.ObjectAdapter adapter = ic.createObjectAdapterWithEndpoints("SimplePrinterAdapter", "default -p 10000");
/**方法一
//实例化一个ZanImpl对象,为Printer接口创建一个服务对象
Ice.Object object = new ZanImpl();
//将服务单元增加到适配器中,并给服务对象指定名称为SimplePrinter,该名称用于唯一确定一个服务单元
adapter.add(object,Ice.Util.stringToIdentity("SimplePrinter"));
*/
/**方法二*/
ComponentServantLocator componentServantLocator = new ComponentServantLocator(new HashMap<String, String>());
adapter.addServantLocator(componentServantLocator, "");
//激活适配器,这样做的好处是可以等到所有资源就位后再触发
adapter.activate();
ic.waitForShutdown();
} catch (Ice.LocalException e) {
e.printStackTrace();
status = 1;
} catch (Exception e) {
System.err.println(e.getMessage());
} finally {
if (ic != null) {
ic.destroy();
}
}
System.exit(status);
}
}
客户端
public class Client {
public static void main(String[] args) {
int status = 0;
Ice.Communicator ic = null;
try {
//初使化
ic = Ice.Util.initialize(args);
//传入远程服务单元的名称、网络协议、IP及端口,获取ZanPrx的远程代理,这里使用的stringToProxy方式
/**对应方法一
Ice.ObjectPrx base = ic.stringToProxy("SimplePrinter:default -p 10000");
*/
/**对应方法二*/
Ice.ObjectPrx base = ic.stringToProxy(ZanPrx.class.getName()+":default -p 10000");
//通过checkedCast向下转换,获取Printer接口的远程,并同时检测根据传入的名称获取的服务单元是否Printer的代理接口,如果不是则返回null对象
ZanPrx zan = ZanPrxHelper.checkedCast(base);
if (zan == null) {
System.err.println("Ivalid proxy");
}
zan.add(1, 2);
zan.printString("Hello World");
} catch (Ice.LocalException e) {
status = 1;
e.printStackTrace();
} catch (Exception e) {
status = 1;
System.err.print(e.getMessage());
} finally {
if (ic != null) {
ic.destroy();
}
}
System.exit(status);
}
}
实现类
public class ZanImpl extends _ZanDisp{
@Override
public void printString(String s, Current __current) {
System.out.println(s);
}
@Override
public void add(int a, int b, Current __current) {
System.out.println(a+b);
}
}
定位器
public class ComponentServantLocator extends LocalObjectImpl implements ServantLocator {
public static Logger logger = LoggerFactory.getLogger(ComponentServantLocator.class);
private static AtomicLong requestCountTotal = new AtomicLong(0L);
private Map<String, String> config = null;
private boolean accessControl = false;
private Map<InetAddress, Boolean> permission = new ConcurrentHashMap<InetAddress, Boolean>();
ComponentServantLocator(Map<String, String> config) {
this.config = config;
String ac = (String) config.get("server.access_control");
String as = (String) config.get("server.access_servers");
this.accessControl = (("true".equals(ac)) && (null != as) && (!"".equals(as)));
if ((null != as) && (!"".equals(as))) {
String[] items = as.trim().split(";");
for (String item : items) {
try {
String[] host = item.split(":");
InetAddress h = InetAddress.getByName(host[0]);
Boolean flag = Boolean.valueOf(host[1]);
this.permission.put(h, flag);
} catch (Exception ex) {
logger.error("无法解析访问控制项:{}", item);
}
}
}
}
public void deactivate(String arg) {
logger.debug("====什么方法======"+arg);
}
public void finished(Current current, Ice.Object servant, Object cookie) throws UserException {
logger.debug("完成");
}
public Ice.Object locate(Current current, LocalObjectHolder holder) throws UserException {
logger.info("connect!");
requestCountTotal.addAndGet(1L);
ConnectionI conn = (ConnectionI) current.con;
Transceiver trans = conn.getTransceiver();
SocketChannel sc = (SocketChannel) trans.fd();
Socket socket = sc.socket();
InetAddress clientAddress = socket.getInetAddress();
InetAddress localAddress = socket.getLocalAddress();
if (logger.isDebugEnabled()) {
logger.debug("Transceiver:" + trans);
logger.debug("SocketChannel:" + sc);
logger.debug("Socket:" + socket);
logger.debug("localAddress:" + localAddress);
logger.debug("clientAddress:" + clientAddress);
}
if (!checkPermission(clientAddress, localAddress)) {
throw new RuntimeException("非法地址访问");
}
if (current.id.name != null) {
Ice.Object target = ComponentServantProvider.getServantBean(current.id.name);
return target;
}
return null;
}
private boolean checkPermission(InetAddress clientAddress, InetAddress localAddress) {
if (this.accessControl) {
Boolean flag = (Boolean) this.permission.get(clientAddress);
return null == flag ? true : flag.booleanValue();
}
return true;
}
public static long getRequestCountTotal() {
return requestCountTotal.get();
}
}
public class ComponentServantProvider {
private static Logger logger = LoggerFactory.getLogger(ComponentServantProvider.class);
private static Map<String, Ice.Object> servantCache = new ConcurrentHashMap<String, Ice.Object>(200, 0.75F, 256);
public static Ice.Object getServantBean(String strToProxy) {
logger.info("查找代理类:"+strToProxy);
Ice.Object servant = (Ice.Object) servantCache.get(strToProxy);
if (servant == null) {
String itfc = buildInterfaceStr(strToProxy);
String impl = buildImplementStr(strToProxy);
logger.info("itfc"+itfc+";impl:"+impl);
if (logger.isDebugEnabled()) {
logger.debug("查找ice服务(servant对象), 使用标识(strToProxy):" + strToProxy);
logger.debug("使用ice服务接口类[" + itfc + "]创建服务.");//demo.Zan
logger.debug("使用ice服务实现类[" + impl + "]提供服务.");//demo.impl.ZanImpl
}
servant = loadServantInstance(itfc, impl);
servantCache.put(strToProxy, servant);
}
return servant;
}
private static String buildImplementStr(String strToProxy) {
int prxIndex = strToProxy.lastIndexOf("Prx");
if (prxIndex <= 0) {
throw new RuntimeException("非法请求");
}
int lastPointIndex = strToProxy.lastIndexOf(".");
String lastSub = strToProxy.substring(lastPointIndex + 1);
if (!lastSub.endsWith("Prx")) {
throw new RuntimeException("非法请求");
}
String shortClazzName = lastSub.substring(0, lastSub.length() - 3);
StringBuilder sb = new StringBuilder(strToProxy.length() + 10);
sb.append(strToProxy.substring(0, lastPointIndex));
sb.append(".impl.").append(shortClazzName).append("Impl");
String impl = sb.toString();
return impl;
}
private static String buildInterfaceStr(String strToProxy) {
int prxIndex = strToProxy.lastIndexOf("Prx");
String itfc = strToProxy.substring(0, prxIndex);
return itfc;
}
private static Ice.Object loadServantInstance(String itfc, String impl) {
try {
Class clazz = Class.forName(impl);
Object target = clazz.newInstance();
return (Ice.Object) target;
} catch (Throwable thr) {
logger.error("未找到实例");
}
return null;
}
}
方法一是简单的应用,每次只能公共化一个接口,不适宜框架级应用,方法二初始化无须具体服务对象,更适应框架级应用.
实际项目中,往往只对外提供一个方法,如第二个ice文件,只对外提供string doRequest(string jsonStr);实现类在impl包下, 把具体的请求类、方法、参数通过一定的形式转化为json字符串传过来,一个后端初始框架就完成了。往外引申很大,这里就不详细叙说了。