企业级服务器设计与实现经验之插件系统基础篇

最初之所以要采用插件的形式进行开发,主要是为了解决功能服务的“热插拔”问题,在决定采用“框架+插件”的方式进行设计后,我们就更进一步,打算将一个个可以分割开来的拥有完整功能的组件都做成插件的形式,并且使同类型的插件的接口兼容,这样在以后需要改变时就可以灵活的进行替换。比如,将通信部分做成通信插件、日志记录部分做成日志插件等等。

首先,我们要弄清楚,什么是插件?我给出了一个定义,可能有失偏颇。

插件又称为扩展,是一种特殊的组件,用于增强和扩展基本框架的行为能力。插件和框架的通信协议是一组接口,插件的各种特性都可以通过该接口进行访问。插件主要有如下特点:

(1)一个插件是一个独立的物理单元。它可以独立的提供一项完整的服务(功能),而不需要依赖于其它插件。

(2)插件能自我描述 ―― 插件的所有对外的发布信息都由插件自己内部提供,而不依赖于外部文件或注册表。

(3)插件能自我管理 ―― 插件如果需要配置信息,则插件自己能读取和修改配置信息,而不是框架来完成这些事情。

(4)插件自我独立   ―― 一个插件不得引用其它的插件。如果一个插件与另一个插件关系紧密,那么应该将这两个插件合成一个插件,或者重新分解为两个独立的插件.

在DataServer系统中,所有的插件从IAddin继承,IAddin接口定义如下:

public interface IAddin
     {
        void Start() ; //不同类型的插件对开始和停止的解释不一样,如果一个插件没有此意义,可实现为空
        void Stop() ;
        int ServiceKey {get ;}
        string ServiceName {get ;}
        string Description {get ;} //插件说明信息
        AddinAppendixInfo AddinAppendixInfo {get ;} 

        string AddinType {get ;}
    }    

接口中的所有方法属性的意义一目了然,其中,ServiceKey是插件关键字,用于区分不同的插件。我们可以把同一类型的插件的关键字限定在某个范围之内,比如,我将通信插件的关键字范围限定在2000-2999之间。AddinAppendixInfo用于描述插件的附加信息,如作者、创建日期、版本号等。

public class AddinAppendixInfo
     {
        public string Author ;
        public string TimeCreated ;
        public string TimeLastRevised ;
        public string AddinVersion ;
    }

AddinType是插件类型,在DataServer中,有如下几种插件类型:

public class AddinTypes
     {
        public const string Net                = "通信插件" ;
        public const string Function           = "功能插件" ;
        public const string Reporter           = "报告者插件" ;
        public const string BasicReqDealer     = "基本请求处理者插件" ;
        public const string RespondInterceptor = "回复截获者插件" ;
    }

每种类型的插件的功用将在后面说明。

大部分插件都需要进行配置,我将配置部分抽象为一个公共的接口,IAddinConfig定义如下:

public interface IAddinConfig
     {
        //以下方法返回的控件或窗体必须实现EnterpriseServerBase.Configure.IConfigControl接口
        IConfigControl GetAddinConfigForm() ;
        IConfigControl GetAddinConfigControl() ;
    }

这样,一个插件如果需要配置信息,则实现该接口即可。前面已经提到“插件如果需要配置信息,则插件自己能读取和修改配置信息,而不是框架来完成这些事情”,插件就是通过IAddinConfig接口来操作配置信息的。GetAddinConfigForm用于获取一个独立的配置窗体,通过此窗体可以完成对插件配置,而GetAddinConfigControl获取的是一个配置控件,一般其结构与功能和配置窗体一样,只不过它可以嵌入到其它任意的窗体中,比如到时,我们可以在主框架中设置一个专门用于配置的TabControl,而其中的每一页就用于加载一个GetAddinConfigControl返回的配置控件,从而实现对配置的统一管理。

IConfigControl究竟是如何操作配置信息的?其定义如下:

public interface IConfigControl
     {
        bool Initialize(string configPath ,string objName) ; //objName 是配置文件中的对象名
        bool SaveConfig() ;
        bool ReDisplayConfigInfo() ; //显示更新后的配置信息

        event EventHandler ConfigChanged ;
    }    

一般,配置信息保存于配置文件中,所以初始化时要给出配置路径,而objName参数的作用,可以参见前面的《如何使用XCodeFactory自动生成XML配置文件和对应的解析类?》这篇文章,我的所有于配置文件相关的解析类和配置窗体都是通过XCodeFactory自动生成的。XCodeFactory接口的其它几个方法的意思很明显,就不用解释了。

接下来,我们看看如何将插件加载到系统中。

我们都知道,一个插件是一个独立的物理单元,我们如何获得该插件的类型了?有很多办法可以解决,比如,我们访问插件目录下的每个插件,通过Assembly.LoadFrom加载一个插件,然后Type. IsSubclassOf查看其是否实现了某种插件类型的接口,从而判断其类型。我采用了更直观的方式,用插件的名字来标志其类型,比如所有的通信插件都以NetAddin.dll结尾。

可以用一个特定的模块来加载插件,我称之为“插件加载器”,插件加载器用于加载某目录下的所有特定类型的插件,"特定"表现在两个方面:(1)插件的名字以[addinSign].dll结尾;(2)插件中的主类是从[baseAddinType]继承。插件加载器的接口定义如下:

public interface IAddinLoader
     {
        ArrayList LoadAddins(string addinFolderPath ,string addinSign ,Type baseAddinType) ;
    }

很简单,只有一个方法,该方法加载某目录下的所有某特定类型的插件,而返回的列表中的每个元素就引用着一个插件。

插件加载器仅仅负责将某种类型的插件加载进来,但是如何实现将所有的插件加载进来、并动态的加载/移除插件了?我们需要一个管理器组件来完成这件事情,它就是IAddinManagement,其接口定义如下:

public interface IAddinManagement
     {
        void LoadAllAddins(string addin_FolderPath ) ;
        bool ReLoadAddins(out int increment) ;
        void UnloadAllAddins() ;
        bool DynRemoveAddin(int serviceKey) ;
        bool DynRemoveAddin(string serviceName) ;
        void StartAllAddin() ;
        void StopAllAddin() ;

        ArrayList AddinBoxList  {get ;}
        Hashtable GetAllServiceList() ; //key - name

        event CallBackSimple AddinsChanged ;
    }

可以看到,IAddinManagement实现了对所有插件的全部管理,其还发布了一个事件AddinsChanged,就是当插件列表发生变化的时候用于通知外部。

关于插件的基础部分,就先介绍这么多,在后面的章节中,我们将深入到各种类型的插件的内部。

原文链接:

企业级服务器设计与实现经验之插件系统基础篇

时间: 2024-10-13 08:26:38

企业级服务器设计与实现经验之插件系统基础篇的相关文章

2016年netty/mina/java nio视频教程java游戏服务器设计教程

2016年netty/mina/Javanio视频教程Java游戏服务器设计教程 需要的加qq:1225462853,备注:程序员学习视频 其他视频都可以索要(Netty   NET    C++ 等等) 互联网架构师教程:http://blog.csdn.net/pplcheer/article/details/71887910 netty录制时间为2015.11-2016.2月份  netty教程为加密视频!      netty12个课程已全部录制完成,相信通过这12节课的分析能让大家对n

FPS游戏服务器设计的问题 【转】

一.追溯 去gameloft笔试,有一个题目是说: 叫你去设计一个FPS(第一人称射击游戏),你是要用TCP呢还是要用UDP,说明理由 . 二.学习 这是两篇网上找到的文章,写非常不错. 当时笔试的时候自己没想到这么全,但大概想法都是一致的,摘录下来再学习一下. 1.网络游戏程序员须知 UDP vs TCP 作者:[email protected] 首发链接:http://blog.csdn.net/rellikt/archive/2010/08/21/5829020.aspx 这篇教程让我们就

高性能服务器设计[转自腾讯km,由qzhang同学翻译]

最近在升级一个服务组件,写到一半突然想起,何不先到km里面去挖挖矿,之后就发现此文,倍感珍贵,强行(违规)分享出来…… 引言本文将与你分享我多年来在服务器开发方面的一些经验.对于这里所说的服务器,更精确的定义应该是每秒处理大量离散消息或者请求的服务程序,网络服务器更符合这种情况,但并非所有的网络程序都是严格意义上的服务器.使用“高性能请求处理程序”是一个很糟糕的标题,为了叙述起来简单,下面将简称为“服务器”. 本文不会涉及到多任务应用程序,在单个程序里同时处理多个任务现在已经很常见.比如你的浏览

基于内存,redis,mysql的高速游戏数据服务器设计架构

转载请注明出处,欢迎大家批评指正 1.数据服务器详细设计 数据服务器在设计上采用三个层次的数据同步,实现玩家数据的高速获取和修改. 数据层次上分为:内存数据,redis数据,mysql数据 设计目的:首先保证数据的可靠,防止数据丢失,保证数据完整.然后实现数据的高速访问,减少由玩家数量增加对数据服务器性能造成的影响.最后实现运维数据的入库,以及数据持久化. 在这个基础上数据服务器不再是一个单一服务器,它涉及到与其他服务器之间的交互. 数据服务器的核心在于redis数据层面.通过redis加快玩家

Linux服务器运维安全策略经验分享

http://jxtm.jzu.cn/?p=3692 大家好,我是南非蚂蚁,今天跟大家分享的主题是:线上Linux服务器运维安全策略经验.安全是IT行业一个老生常谈的话题了,从之前的“棱镜门”事件中折射出了很多安全问题,处理好信息安全问题已变得刻不容缓.因此做为运维人员,就必须了解一些安全运维准则,同时,要保护自己所负责的业务,首先要站在攻击者的角度思考问题,修补任何潜在的威胁和漏洞.今天,我为大家讲的,主要分五部分展开:账户和登录安全账户安全是系统安全的第一道屏障,也是系统安全的核心,保障登录

企业级服务器简介

什么是服务器?服务器是通过网络对外提供各种服务的计算机.既然是计算机,就包括硬件和软件.服务器的硬件设计通常使用的硬件与PC有所区别,因为服务器需要长时间的连续运行.服务器上运行的操作系统一般与PC也有所区别,比如Linux服务器版本.Windows服务器版本.服务器是构建IT系统最基础的设备之一.IT系统从技术层面来说,主要包括数据的计算.数据的存储.数据的传输.IT=PC(peer to peer--Client/Server(B/S)架构)=DC 服务器常见使用场景服务器=DC广泛应用在I

百万级高并发WebRTC流媒体服务器设计与开发教程云

百万级高并发WebRTC流媒体服务器设计与开发 资源获取链接:点击获取完整教程 百万级高并发WebRTC流媒体服务器设计与开发 5G时代音视频为王,随着实时音视频应用的爆发,来自Google 的WebRTC成为了人们关注的焦点,但很多人却不知道如何使用WebRTC实现多人实时互动,本课就将围绕与浏览器互通.级联.可扩展等6大痛点手把手带你学习大负载.高并发.高性能 WebRTC 流媒体服务器的设计与开发,揭秘万人互动直播背后的深层奥秘,打造可负载百万用户量的企业级的流媒体服务器 播答题的核心需求

网络并发服务器设计---9

网络并发服务器设计 1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/socket.h> 4 #include <string.h> 5 #include <netinet/in.h> 6 7 #include <unistd.h> 8 9 #define portnum 3333 10 11 int main() 12 { 13 int sockfd; 14

(3)MEF插件系统中通信机制的设计和实现

1.背景 一般的WinForm中通过C#自带的Event机制便能很好的实现事件的注册和分发,但是,在插件系统中却不能这么简单的直接用已有的类来完成.一个插件本不包含另外一个插件,它们均是独立解耦的,实现插件和插件间的通信还需要我们设计出一个事件引擎来完成这个需求. 目前很多高级语言中基本都实现了观察者模式,并进行了自己的包装.比如C#中的delegate和event组合,java awt中的Event和addActionListener组合,Flex中的Event.addEventListene