Zero ICE在跨平台、跨语言的环境中是一种非常好的RPC方案,而且使用简单。早期在使用ICE时,每一个后端功能模块都以独立服务方式部署,在功能模块较少时不会有明显的问题,但是随着功能模块的增多,部署的服务越来越多,产生的直接问题有:

  1. 每个服务都需要开启一个监听端口,新增服务必须配置防火墙,且影响安全性;
  2. 每个服务即为一个进程,增大系统负担。

想到能否按照插件方式来开发功能模块,同时还能解决上面两个问题。因为所有的后端服务使用Java语言开发,于是选择了java平台下的轻量级插件框架pf4j(关于pf4j的详细资料,请参考github.com上项目说明)。

下面,我以最少的代码来阐述这个插件式ICE服务框架。

  • 定义插件扩展接口

IceService.java

 package server;

 import ro.fortsoft.pf4j.ExtensionPoint;

 public interface IceService extends ExtensionPoint {
Ice.Object getObject();
String getName();
String getGUID();
}

为了演示插件接口的可扩展性,定义了一个IceServiceV2.java

package server;

public interface IceServiceV2 extends IceService {
String getVersion();
}
  • 开发插件

插件1—Echo

package plugin.echo;

import Ice.Object;
import ro.fortsoft.pf4j.Extension;
import ro.fortsoft.pf4j.Plugin;
import ro.fortsoft.pf4j.PluginWrapper;
import server.IceService;
import server.IceServiceV2; public class EchoPlugin extends Plugin { public EchoPlugin(PluginWrapper wrapper) {
super(wrapper);
} @Override
public void start()
{
System.out.println("start plugin " + this.getClass().getName());
} @Override
public void stop()
{
System.out.println("stop plugin " + this.getClass().getName());
} @Extension
public static class EchoService implements IceServiceV2 {
Ice.Object object; public Object getObject() {
object = new EchoI();
return object;
} public String getName() {
return "Echo";
} public String getGUID()
{
return "1234-5678";
} @Override
public String getVersion() {
return "V2";
}
}
}

其中,EchoI类的定义如下

package plugin.echo;

import Ice.Current;

public class EchoI extends rpc._EchoDisp {

    @Override
public String reply(String message, Current __current) {
System.out.println("Receive " + message);
return message;
}
}

其实现了如下ice接口

module rpc
{
interface Echo
{
string reply(string message);
};
};

插件2—Hello

package plugin.hello;

import Ice.Object;
import ro.fortsoft.pf4j.Extension;
import ro.fortsoft.pf4j.Plugin;
import ro.fortsoft.pf4j.PluginWrapper;
import server.IceService; public class HelloPlugin extends Plugin { public HelloPlugin(PluginWrapper wrapper) {
super(wrapper);
} @Override
public void start()
{
System.out.println("start plugin " + this.getClass().getName()); } @Override
public void stop()
{
System.out.println("stop plugin " + this.getClass().getName());
} @Extension
public static class HelloService implements IceService
{
Ice.Object object; @Override
public Object getObject() {
object = new HelloI();
return object;
} @Override
public String getName() {
return "Hello";
} public String getGUID()
{
return "5678-5678";
}
}
}

其中,HelloI类的定义如下

package plugin.hello;

import Ice.Current;

public class HelloI extends rpc._HelloDisp {

    public void sayHello(String message, Current __current) {
System.out.println("Hello " + message);
}
}

其实现了如下ice接口

module rpc
{
interface Hello
{
void sayHello(string message);
};
};
  • 制作插件

在这里,有必要提一下我遇到的波折。查看了pf4j的文档后得知,每个插件的目录结构为

echo +
|
-- classes +
| |
| -- META-INF +
| | |
| | --extensions.idx
| | |
| | --MANIFEST.MF
| -- (编译后的插件代码)
-- lib +
|
-- (插件依赖的第三方jar

由于我使用eclipse编辑和生成代码,因此在编译代码时并没有为@Extension标注生成extensions.idx文件,所以第一次验证插件是否生效时,loadplugins和startplugins都没有问题,但是执行List<IceService> exts = manager.getExtensions(IceService.class)时并没有找到extension,这是掉的第一个坑。

由于我并不想使用maven来生成代码,于是手动创建了插件的extensions.idx文件,其中echo插件的内容是

plugin.echo.EchoPlugin$EchoService

MANIFEST.MF文件的内容为

Manifest-Version: 1.0
Plugin-Dependencies:
Plugin-Version: 0.0.
Plugin-Id: echo-plugin
Plugin-Provider: Super
Plugin-Class: plugin.echo.EchoPlugin
Build-Jdk: 1.8.0_92

在准备好插件必要的文件后,再次执行代码,遇到了第二个坑,这个坑有点深——将整个项目编译后的代码都拷贝到了两个插件中,这直接导致的后果是依然找不到extension。直至我在看了N遍pf4j的demo代码,并使用maven生成并成功执行其demo后,才确定了这个深坑。

  • 执行主程序
package server;

import java.util.List;

import ro.fortsoft.pf4j.DefaultPluginManager;

public class Entry {

    public static void main(String[] args) {

        try {
DefaultPluginManager manager = new DefaultPluginManager();
manager.loadPlugins();
manager.startPlugins(); Ice.Communicator ic = Ice.Util.initialize();
Ice.ObjectAdapter adapter = ic.createObjectAdapterWithEndpoints("IceAdapter", "default -p 9005"); List<IceService> exts = manager.getExtensions(IceService.class);
for (IceService ext : exts) {
System.out.println("Add object " + ext.getName() + ", GUID=" + ext.getGUID());
if (ext instanceof IceServiceV2)
{
System.out.println(((IceServiceV2)ext).getVersion());
}
adapter.add(ext.getObject(), ic.stringToIdentity(ext.getName())); }
System.out.println("Active adapter");
adapter.activate();
ic.waitForShutdown();
} catch (Exception ex) {
ex.printStackTrace();
}
} }

当然,我实际编写的ICE服务框架比这个要复杂的多,包括使用到Java Service Wrapper,仅装载.zip格式的插件,增加异常处理等。

最后给出Ice的Client代码

package client;

public class Echo {

    public static void main(String[] args) {
Ice.Communicator ic = null;
try {
ic = Ice.Util.initialize();
Ice.ObjectPrx base = ic.stringToProxy("Echo:default -p 9005");
rpc.EchoPrx proxy = rpc.EchoPrxHelper.checkedCast(base);
if (proxy == null) {
throw new Error("Invalid proxy");
}
for (int i = 0; i < 10; i++) {
System.out.println(proxy.reply("message " + i));
} } catch (Ice.LocalException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
if (ic != null) {
try {
ic.destroy();
} catch (Exception ex) {
ex.printStackTrace();
}
}
System.out.println("exit");
}
}

【原创】插件式ICE服务框架的更多相关文章

  1. MAF+WPF实现插件式应用程序框架

    关于maf和wpf大家感兴趣的话可以去百度学习一下,下面展示一下成果: 登录界面 主界面:默认的是我的应用,表示已经下载到本地的应用. 辅助应用类似appstore功能,指示未下载或者需要升级的程序列 ...

  2. 插件式WebApi服务及自动生成Api帮助文档

    上一篇博客中,讲到了将WebApi Host到控制台和IIS,本篇总结一下如何将WebApi的Service以插件的形式进行动态部署,并设置Hoster的首页显示Api帮助文档,当然,也包括动态部署进 ...

  3. 微服务框架Lagom介绍之一

    背景 Lagom是JAVA系下响应式 微服务框架,在阅读本文之前请先阅读微服务架构设计,Lagom与其他微服务框架相比,与众不同的特性包括: 目前,大多数已有的微服务框架关注于简化单个微服务的构建-- ...

  4. 使用 SailingEase WinForm 框架构建复合式应用程序(插件式应用程序)

    对于一些较小的项目,具备一定经验的开发人员应该能够设计和构建出便于进行维护和扩展的应用程序.但是,随着功能模块数量(以及开发维护这些部件的人员)的不断增加,对项目实施控制的难度开始呈指数级增长. Sa ...

  5. 插件式Web框架

    转载构建高性能插件式Web框架 基于MVC插件模式构建支持数据库集群.数据实时同步.数据发布与订阅的Web框架系统.如下图: 1.基于插件式开发 采用插件模式开发的优点是使得系统框架和业务模式有效地进 ...

  6. 构建高性能插件式Web框架

    基于MVC插件模式构建支持数据库集群.数据实时同步.数据发布与订阅的Web框架系统.如下图: 1.基于插件式开发 采用插件模式开发的优点是使得系统框架和业务模式有效地进行分离,系统更新也比较简单,只需 ...

  7. Asp.net MVC 插件式应用框架

    Asp.net MVC 插件式应用框架 2013年05月13日 10:16供稿中心: 互联网运营部 摘要:这几年来做了很多个网站系统,一直坚持使用asp.net mvc建站,每次都从头开始做Layou ...

  8. (1)从底层设计,探讨插件式GIS框架的实现

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 研一时,听当时的师兄推荐,买了蒋波涛的一本关于GIS插件框架的书.当时 ...

  9. MXBridge - 插件式JS与OC交互框架

    概述 MXBridge,提供一个插件式的JavaScript与Objective-C交互的框架,通过JavaScriptCore实现,插件式扩展Obejctive-C接口以供JavaScript调用. ...

随机推荐

  1. rtmp一些状态信息详解-as连接FMS服务器报错状态汇总~~

    原地址:http://help.adobe.com/zh_CN/AIR/1.5/jslr/flash/events/NetStatusEvent.html 下表说明了 code 和 level 属性可 ...

  2. 深入理解Java线程池

    我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁 ...

  3. Java并发之AQS详解(转)

    一.概述 谈到并发,不得不谈ReentrantLock:而谈到ReentrantLock,不得不谈AbstractQueuedSynchronized(AQS)! 类如其名,抽象的队列式的同步器,AQ ...

  4. Android——eclipse共享library以及导出jar包[转]

    目录(?)[-] 一apk之间共享Class 二apk导出jar包   android的apk在在eclipse上进行开发的时候,有时候需要import其它包中的一些class,正常的方法就是在jav ...

  5. Unity iOS 项目的一种性能评测方法

    [Unity iOS 项目的一种性能评测方法]

  6. Excel VBA入门(五)Excel对象操作

    本章是本系列教程的重点.但我觉得应该不是难点.从第零章开始到学完本章,应该可以把VBA用于实战中了. Excel对象主要有4个: 工作薄 Workbook 工作表 Worksheet 单元格区域 Ra ...

  7. JAVA中的数组对象

    代码:Student [] sd=new Student[5];//新建一个学生类的数组对象sd.        sd[0]=new Student("kj",13);//为数组对 ...

  8. 高性能Web服务器Nginx的配置与部署研究(7)核心模块之主模块的非测试常用指令

    1. error_log 含义:指定存储错误日志的文件 语法:error_log <file> [debug|info|notice|warn|error|crit] 缺省:${prefi ...

  9. UNITY把3D模型显示在UI层级上的思路

    一般UI是处理于显示最高层级的, 因此这里的做法是 使用镜子效果,做镜子可使用renderTexture 然后启用一个摄像机对renderTexture进行数据填充, 然后在ui上使用Raw Imag ...

  10. cocos2d-js反射

    如何在android平台上使用js直接调用Java方法 在cocos2d-js 3.0beta中加入了一个新特性,在android平台上我们可以通过反射直接在js中调用java的静态方法.它的使用方法 ...