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. nginx基本配置与参数说明-【转】

    #运行用户 user nobody; #启动进程,通常设置成和cpu的数量相等 worker_processes 1; #全局错误日志及PID文件 #error_log logs/error.log; ...

  2. Python常见函数用法

    1. shape()函数 在numpy模块 输入参数:类似数组(比如列表,元组)等,或是数组 返回:一个整型数字的元组,元组中的每个元素表示相应的数组每一维的长度 # shape[0]返回对象的行数, ...

  3. MyBatis 体系结构

  4. spring的传播行为和隔离级别

    7个传播行为,4个隔离级别(转自 http://www.blogjava.net/freeman1984/archive/2010/04/28/319595.html) Spring事务的传播行为和隔 ...

  5. Linux下Mysql数据库互为主从的配置过程

    配置准备: 两台机器:A(193.168.10.101)  B(193.168.10.102) mysql大版本需要一致,小版本可忽略 配置过程: A(193.168.10.101) 机器配置: 执行 ...

  6. 各种mac软件地址

    http://www.sdifenzhou.com/  各种软件地址

  7. solr自动提示 - jquery ui autocomplete

    需求: 搜索框中 输入部分关键词之后,有下拉联想提示.选中提示,使用鼠标或者使用enter键,则触发搜索功能.没有选择搜索提示,使用部分输入关键词作为搜索,直接使用enter键也能触发搜索功能.整个过 ...

  8. IIS7日志中时间与系统时间不一致的原因

    最近在分析web日志,发现IIS7日志中时间与系统时间不一致,即本该上班时间才产生的产并发访问日志,全部发生在凌晨至上班前. 本以为是系统时间设置错误,检查后一切正常.后查询资料,原来是这个原因: 日 ...

  9. StringBuffer详解

  10. (转)介绍一些.net开源项目

    强大的插件系统,通过Addin构建成一个功能齐全的.net开发IDE.核心是AddInTree.跟随这个项目开发许多有用的组件,比如功能文本编辑器(ICSharpCode.TextEditor),Sh ...