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. Itext读取PDF模板文件渲染数据后创建新文件

    Maven导入依赖 <properties> <itextpdf.version>5.5.0</itextpdf.version> <itext-asian. ...

  2. ffmpeg源码分析四:transcode_step函数 (转4)

    原帖地址:http://blog.csdn.net/austinblog/article/details/25099979 该函数的主要功能是一步完整的转换工作,下面看看源代码: static int ...

  3. Sass 入门 (一) 安装Sass

    Sass安装 ruby安装 因为sass依赖于ruby环境,所以装sass之前先确认装了ruby.先导官网下载个ruby 在安装的时候,请勾选Add Ruby executables to your ...

  4. win10 IIS 10.0 无法安装 URL Rewrite Module 重写模块

      打开注册表 win+R 输入 regidit在HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\InetStp位置 修改注册表 把MajorVersion的值改为9 安装 ...

  5. MyBatis 学习记录2 Mapper对象是如何生成的

    主题 以前我一直有一个问题不懂.并且觉得很神奇.就是Mybatis我们开发的时候只需要定义接口,并没有写实现类,为什么我们运行的时候就可以直接使用? 现在我想分享下这部分大致是怎么实现的. 在启动的时 ...

  6. AspectJ的通知类型

  7. 阻塞和唤醒线程——LockSupport功能简介及原理浅析

    目录 1.LockSupport功能简介 1.1 使用wait,notify阻塞唤醒线程 1.2 使用LockSupport阻塞唤醒线程 2. LockSupport的其他特色 2.1 可以先唤醒线程 ...

  8. [codevs3981]动态最大子段和不带修改(线段树)

    解题关键:最大子段和需要多个信息维护. 注意查询时的pushup. #include<cstdio> #include<cstring> #include<algorit ...

  9. python 字符编码处理问题总结

    Python中常常遇到这种字符编码问题,尤其在处理网页源代码时(特别是爬虫中): UnicodeDecodeError: ‘XXX' codec can't decode bytes in posit ...

  10. 怎样取得selected的option选项的value值

    现在有一id=test的下拉框,怎么拿到选中的那个值呢?   分别使用javascript原生的方法和jquery方法   <select id="test"  name=& ...