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. Oracle11gR2导入导出实战之表空间传输

    Oracle11gR2导入导出实战之使用Datapump进行表空间传输 表空间检查 [oracle@localhost database]$ ps -ef|grep smon oracle 8981 ...

  2. CentOS 安装python3.5

    1.刚开始centos可能会缺少gcc等组件,先安装组件 yum groupinstall "Development Tools" 2.下载源码,解压后进入目录 #下载地址http ...

  3. 数字1的ASCII值是多少

    ASCII表是计算机将字符转为数字存储的一张转换表.因此,只有字符才有ASCII值,数字是没有的. 答案:数字1没有ASCII值,数字1在计算机中就是按数值1存储的. 字符1的ASCII值是 49

  4. Linux服务管理总结

    简介与分类 系统的运行级别 运行级别 含义 0 关机 1 单用户模式,可以想象为windows的安全模式,主要用于系统修复 2 不完全的命令行模式,不含NFS服务 3 完全的命令行模式,就是标准字符界 ...

  5. 压力测试工具--Siege

    Siege是一款开源的压力测试工具,设计用于评估WEB应用在压力下的承受能力.可以根据配置对一个WEB站点进行多用户的并发访问,记录每个用户所有请求过程的相应时间,并在一定数量的并发访问下重复进行.s ...

  6. Thinking in 查询设计

    近日,互联网动物园的各位小伙伴们召开了一次会议,考虑到大火的电子商务,准备在动物园里开发一个电商系统.首先上台的是销售山鸡,清了清嗓子,说道,人类正在进行电商革命,动物园也需要上一个电商系统,必要性有 ...

  7. java的web配置文件的“<load-on-startup>的说明[转]

    <servlet> <servlet-name>log4jInitServlet</servlet-name> <servlet-class>org.s ...

  8. 10个实用的Django技巧和建议

    Django 作为一个杰出的Python开源框架,或许得不到和其它流行框架如Rails这样多的赞美,但是它和其他框架一样精炼,非常注重DRY(Don’t Repeat Yoursef)原则.组件的重用 ...

  9. 白盒测试实践--Day0

    白盒测试实践--Day0 累计完成任务情况: 阶段内容 参与人 开会学习作业要求,取得共识 全体 注: 1."阶段内容"划斜线表示完成. 2.采用倒序. 具体情况: 组长提前组织分 ...

  10. Web测试实践-任务进度-Day02

    小组成员 华同学.郭同学.覃同学.刘同学.穆同学.沈同学 任务进度 在经过任务分配阶段后,大家都投入到了各自的任务中,以下是大家今天任务的进度情况汇总. 华同学 & 刘同学(任务1) 1.对爱 ...