ESFramework介绍之(26)-- 支持复杂插件(InnerDealer 和 InnerDispatcher)

    (本文内容适合于 ESFramework V0.2+)
    通常,最单纯的情况是一个插件对应某一特定类型的功能请求,但是,在有的应用中也会出现这样的情况,有多种类型的功能请求相互关联、并且可能交叉,如果是这样,对应每种类型的请求都开发一个插件可能会非常困难,因为这可能会牵涉到插件之间的相互引用/访问,这违背了插件的“自治”性。最好的办法还是将它们放在一个插件中,通过ServiceItemIndex(你一定还记得消息头定义中除了ServiceKey外还有个ServiceItemIndex属性)来区分相互关联的各种请求类型。
    当涉及的请求类型非常多时,我们的插件会变得非常复杂,通常的解决方案是在插件内部构建“内部处理器”InnerDealer,然后将ServiceItemIndex映射到对应的“内部处理器”上,这个映射可以由“内部分派器”InnerDispatcher完成。需要注意的是,并不需要为每个ServiceItemIndex都构建一个“内部处理器”,一个“内部处理器”可能能处理多个ServiceItemIndex的请求类型。下面我们重点关注“内部处理器”和“内部分派器”的实现。
   
    内部分配器接口IInnerDispatcher定义如下:

    public interface IInnerDispatcher
    {        
        string AddinAssemblyName{set ;} //本插件程序集的名称

        void Initialize() ;
        IInnerDealer GetDealer(int serviceIndex) ;
    }

    最主要是GetDealer()方法的实现,它根据消息头中的ServiceItemIndex返回对应的内部处理器,你也许想到了,这可以通过Switch分支将serviceItemIndex映射到对应的内部处理器,然后这种集中管理的方式不是很方便,比如,当增加/删除一个内部处理器时,就要在这里增加/删除对应的分支语句。更好的办法是,让内部处理器能自己暴露它能处理的ServiceItemIndex的集合,这样,在运行时,可以通过反射动态的构建Mapping表,从而就避开了Switch语句及其引入的繁琐。
    内部处理器接口定义如下,它通过ServiceIndexCollection属性暴露了它能处理的ServiceItemIndex集合。

    public interface IInnerDealer
    {
        int[] ServiceIndexCollection{get ;}

        NetMessage DealRequest(NetMessage reqMsg) ;
    }

    
    现在,我们可以实现IInnerDispatcher的Initialize方法来动态构建Mapping表了:

        private void Initialize()
        {
            Assembly[] asses = AppDomain.CurrentDomain.GetAssemblies();
            Type supType = typeof(IInnerDealer)  ;

            foreach (Assembly ass in asses)
            {
                string[] names = ass.FullName.Split(',') ;
                if(names[0].Trim() == this.addinAssemblyName)
                {
                    foreach(Type t in ass.GetTypes())
                    {
                        if(supType.IsAssignableFrom(t) && (!t.IsAbstract) && (! t.IsInterface) )
                        {
                            IInnerDealer dealer = (IInnerDealer)Activator.CreateInstance(t) ;
                            if(dealer.ServiceIndexCollection != null)
                            {
                                foreach(int serKey in dealer.ServiceIndexCollection)
                                {
                                    this.htDealer.Add(serKey ,dealer) ;
                                }
                            }
                        }
                    }

                    break ;
                }
            }
        }

    可以在IAddin.OnLoading方法中调用InnerDispatcher的Initialize方法进行初始化。

    IInnerDispatcher的GetDealer方法就显而易见了:

        public IInnerDealer GetDealer(int serviceIndex)
        {
            return (IInnerDealer)this.htDealer[serviceIndex] ;
        }

    功能插件的DealRequestMessage就变得相当简单:

        public ESFramework.Network.NetMessage DealRequestMessage(ESFramework.Network.NetMessage reqMsg)
        {        
            IInnerDealer dealer = this.dispatcher.GetDealer(reqMsg.Header.ServiceItemIndex) ;
            if(dealer == null)
            {
                return null ;
            }

            return dealer.DealRequest(reqMsg) ;
        }

    
    插件中接下来需要做的工作就是实现你需要的IInnerDealer,实现的内部处理器不需要进行注册,它会在初始化插件时动态创建并被加入到Mapping表。需要注意的是,内部处理器的实现必须有一个无参的构造函数,否则,反射创建处理器实例将会抛出异常。
   

上一篇文章:ESFramework介绍之(25)-- 在插件中使用NHibernate

转到  :ESFramework 可复用的通信框架(序) 

时间: 2024-07-30 16:35:39

ESFramework介绍之(26)-- 支持复杂插件(InnerDealer 和 InnerDispatcher)的相关文章

ESFramework介绍之(29)―― 插件公共设施 AddinUtil

    (本文适用于 ESFramework V0.2+)    不知你是否还记得,前面我们讲过,ESFramework规定了插件有如下特点: (1)一个插件是一个独立的物理单元.它可以独立的提供一项完整的服务(功能),而不需要依赖于其它插件. (2)插件能自我描述 ―― 插件的所有对外的发布信息都由插件自己内部提供,而不依赖于外部文件或注册表. (3)插件能自我管理 ―― 插件如果需要配置信息,则插件自己能读取和修改配置信息,而不是框架来完成这些事情.(4)插件自我独立   ―― 一个插件不得

ESFramework介绍之(20)―― 插件自动升级

    当我们的服务平台搭建成功后,所需要做的主要事情就是开发服务端功能插件(IFunAddin)和客户端插件(IPassiveAddin),每个插件对(AddinPair)实现了一组相似或相近的需求/功能.     好了,我们已经开发了十多对插件对,然后分别XCopy到了各个服务器节点上,"整个系统"已经投入了运行.通过前面的介绍(回顾),相信大家对我们的"整个系统"有了个大致的映像.我们的IRAS服务器通常只存在于一个节点上,而我们的AS和对应的多个FS通常分布

ESFramework介绍之(30)―― 消息侦察者 INetMessageSpy

    (本文适用于ESFramework V0.2+)     现在我们回想一下,当网络组件(Tcp/Udp组件)接收到一个消息后,这个消息会流经哪些组件,然后再通过网络组件发送出去了.如果你研究过ESFramework V0.1,你会发现,消息"行走"的路线模型可以用下图表示出来:    请求消息(路径由黑线表示)经过网络组件后,会被Hook链中的各个Hook按照特定的顺序处理,然后到达消息处理器,消息处理器处理请求消息,并给出回复消息(路径由红线表示),回复消息同样再经过Hook

ESFramework介绍之(22)―― 服务器系统自动升级

    (本文名字取为"服务器系统自动升级",实际上适用于所有应用程序自动升级的情况.)    前文介绍了在服务器或客户端应用程序运行的过程中,插件如何自动升级.更新.基于前文相同的理由,AS.FS.IRAS也需要有自动升级的功能.     与插件在运行时动态更新不同,服务器系统无法在运行时动态更新,只有在服务器系统重新启动的时候,才是自动升级的切入点.(1)对于功能服务器FS,可以采用持续/逐个更新的方式,即依次重启每个功能服务器.这样可以避免功能服务被中断的情况发生.需要注意的是,

ESFramework介绍之(27)-- 支持OverdueMessage

   (本文适用于ESFramework V0.2+)     QQ上,你给好友发消息,如果对方不在线,则服务器会把这个消息持久化存起来,等好友下次上线时,再转发给他.像这样的消息在ESFramework中称为OverdueMessage.显然,MSN没有支持OverdueMessage. 当然了,ESFramework中的OverdueMessage不仅仅是文字消息,而是可以为任何类型的消息,比如,音频.视频.文件等等.     ESFramework中对所有P2P的消息的处理都是由P2PMe

ESFramework介绍之(13)-- 功能插件处理器工厂

    上文讲述的是AS中的基于连接池的消息处理器,现在我们把焦点转移到功能服务器FS上来,看看FS上消息分派的过程.当FS接收到到一个请求后,会从已加载的功能插件列表中选择一个合适的插件来处理这个消息,而每一个功能插件就相当于一个消息处理器.FS和AS的结构一致:    要注意的是,功能服务器FS上收到的所有消息都应该交给功能插件来处理,不存在其它的处理方式.这是使得FS"纯粹"的必须要求.上图已经很清楚的表示了功能插件处理器工厂的位置和作用.它借助插件管理器实现"工厂&q

ESFramework介绍之(9)-- 插件对(Addin Pair)调试“框架”

    使用ESFramework开发C/S(通常为4层.3层也没问题)应用,当需要增加一项新的业务时,我们需要做的仅仅是开发两个插件,一个是服务端的业务功能插件(FunAddin),一个是客户端插件(PassiveAddin),这两个插件合在一起称为Addin Pair.开发这两个插件,只需要关注于业务,而其它与业务无关的比如网络通信.加密.数据安全,都不用管.ESFramework很好的将这些关注点分离开来,使得写"业务"插件的程序员的工作变得非常单纯,在ESFramework介绍

ESFramework介绍之(17)―― 支持漫游用户和跨区域功能请求

    对于漫游用户的支持和跨区域功能请求的支持是ESFramework最基本的目的之一(回顾),在详细讲述解决方案之前,先了解一下关于这个问题的上下文.    在我们前面讲述的4层C/S架构中,每个AS负责一块区域.比如上海AS负责处理所有目标城市为上海的功能请求和管理所有在上海AS上注册的用户(比如PDA用户或手机用户).如果一个本是在上海注册的用户出差来到了武汉,最方便的,他会连上武汉的AS,这样对于武汉AS来说,这个用户就是漫游用户了.    如果上海的用户登陆上了上海的AS,但是他需要

ESFramework介绍之(8)-- 客户端插件IPassiveAddin

    前文已经提到了,在IServerAgent的基础上,客户端也可以采用插件的结构形式,客户端插件需要实现IPassiveAddin接口.    我的想法是,当客户端主程序加载一个新的PassiveAddin时,可以在某个菜单的子Items上添加一项,当双击这个子菜单项时,则弹出该客户端插件提供的"业务操作窗体".这只是使用客户端插件的可行方式之一,你完全可以根据你的应用来决定使用形式.IPassiveAddin接口定义如下:  1     /// <summary>