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. xe8 单元别名

    xe8 单元别名 Unit scope F2613 Unit 'Graphics' not found. Project>Option>Unit scope names> vcl.I ...

  2. SpringMVC前后台数据传递中Json格式的相互转换(前台显示格式、Json-lib日期处理)及Spring中的WebDataBinder浅析

    两个方向: 一.前台至后台: Spring可以自动封装Bean,也就是说可以前台通过SpringMVC传递过来的属性值会自动对应到对象中的属性并封装成javaBean,但是只能是基本数据类型(int, ...

  3. 一道容易栽坑的有趣的面试题(关于js,定时器,闭包等)

    1.首先下面代码输出什么? for (var i = 0; i < 5; i++) { console.log(i); } 输出:0 1 2 3 4 2.上面只是普通的输出,没有陷阱再看下面这个 ...

  4. NoSuchBeanDefinitionException:No qualifying bean of type found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency.

    报错如下: NoSuchBeanDefinitionException:No qualifying bean of type   found for dependency: expected at l ...

  5. 纸牌游戏CardBattle的设计与开发

  6. Spring Data JPA 参考指南 中文版

    附下载地址:https://www.gitbook.com/book/ityouknow/spring-data-jpa-reference-documentation/details

  7. freemaker 优缺点 及 应用配置

    通俗的讲,freemaker其实就是一个模板引擎.什么意思呢?——Java可以基于依赖库,然后在模板上进行数据更改(显示). 在模板中,您专注于如何呈现数据,而在模板外(后台业务代码),您将专注于呈现 ...

  8. 手把手教你生成二维码-google.zxing

    一.目标 输入网址,生成网址的二维码 二.概况 1.效果:UI丑,但功能实现了 2.项目目录 三.用到的第三方资源 1.google的扫码包zxing 2.JQuery 四.步骤(用myEclipse ...

  9. static_cast, dynamic_cast, reinterpret_cast, const_cast区别比较

    隐式转换(implicit conversion) ; int b; b=a; short是两字节,int是四字节,由short型转成int型是宽化转换(bit位数增多),编译器没有warning,如 ...

  10. smarty 使用php函数

    strtotime() time() <{if strtotime($activity.start_time) gt time()}> <a href="?action=d ...