资源描述
插件框架
插件介绍
概念
Eclipse插件架构
插件内部结构
典型插件定义
插件加载
插件类加载-ClassLoader
插件加载过程
Eclipse插件加载过程
插件框架概述
开放工厂OSGi.NET插件框架,是OSGi R4.2规范移植到.NET平台的实现。OSGi全称为Open Service Gateway Initiative,它一方面指由IBM、Oracle、BEA、SAP等国际IT巨头组成的OSGi联盟组织;另一方面指该组织制定的一个基于Java语言的服务规范——OSGi服务平台。
OSGi.NET插件框架提供了模块化与插件化、面向服务架构和模块扩展三大功能,适用于控制台、WinForm、Windows服务、WPF、ASP.NET和移动平台等任意.NET应用环境。
目前,OSGi已经得到广泛的应用,如下所示。
插件程序结构
基于OSGi.NET插件框架的应用程序体系结构如下图所示。在这里,应用程序由主程序和插件组成。主程序是具体的应用环境的入口,它用于启动OSGi.NET插件框架并进入插件框架暴露出来的入口点;应用插件则是实现软件不同功能的业务模块。
OSGi.NET插件框架优点
开放、规范、统一:符合规范的模块均可被OSGi.NET插件框架加载。
快速集成:将模块放在插件模块即实现功能集成。
高度可重用:仅通过拷贝即可实现重用,无需修改任何代码。
热插拔与动态:每一个模块都可被动态安装、启动、停止和卸载。
标准模块化与模块物理隔离:模块具有统一规范且互相独立。
面向服务编程支持:提供基于面向服务架构编程模型以支持模块通讯。
动态可扩展:通过暴露扩展点实现动态扩展。
多环境支持:支持各种.NET应用环境。
插件框架原理
插件和插件运行时
在OSGi.NET插件框架中,插件即Bundle,它具备物理隔离、热插拔和动态特性。每一个插件都是完全可复用的,可以被动态的安装、启动、停止、卸载或更新。
插件运行时即BundleRuntime,则是插件的运行容器,它负责从插件目录中加载和启动插件。
面向服务
在OSGi.NET插件框架中,插件具备高内聚、低耦合特性,也就是说插件间耦合度非常低。服务即Service,是插件通讯的方式。在这里,“服务=接口 + 实现”。接口是服务的契约,服务提供商实现了服务的接口并将服务注册到服务总线,服务消费者则通过服务契约从服务总线搜索服务并绑定使用。这里,服务是动态,可以被动态注册、卸载和更新,一个服务契约也可能有多个服务实现。
插件扩展
在OSGi.NET插件框架,插件具备可扩展性,可以在不变更插件代码情况下,更改或者扩展插件的行为。这个扩展机制是通过一对基于XML格式的“扩展点 + 扩展”来实现的。一个插件可以通过定义“扩展点”来实现可扩展,而其它插件则通过定义对应的“扩展”来注册/更新功能。扩展/扩展点在插件启动时注册到插件运行时,相反,在卸载时,则从插件运行时卸载。
片段插件
在OSGi.NET,有一种特殊的插件,称为片段插件,即Fragment Bundle。片段插件相当于子插件,其作用是为了扩充其它插件的类型空间、扩展信息。除了片段插件的插件,都是宿主插件(Host Bundle)。与宿主插件不同的是,片段插件不能被启动、停止,没有类加载器,不允许从片段插件加载类型。当宿主插件被启动后,片段插件会自动附加到宿主插件,即将片段插件的类型空间、扩展信息合并到宿主插件。
开放工厂原理
开放工厂原理概述
开放工厂主要由iOpenWorks开放工厂平台和OSGi.NET插件SDK组成。开发者从iOpenWorks开放工厂平台中下载到OSGi.NET插件SDK, 并使用该SDK的项目模板来创建一个插件应用程序。
开放工厂原理图如下所示。
iOpenWorks开放工厂平台主要由插件仓库和插件仓库OpenAPI组成。插件仓库实现插件的版本管理、OSGi.NET内核文件版本管理、SDK及客户端 管理,而插件仓库OpenAPI则向外暴露了插件及其版本信息、内核文件及其版本信息从而为客户端提供内核及插件的自动升级支持。
OSGi.NET插件SDK由开发者安装,向开发者提供了OSGi.NET插件框架、OSGi.NET Web扩展、iOpenWorks启动程序这三个开发程序集,此外,还提供了插件项目模板、 远程管理控制台(用于调试用,可以查看OSGi.NET内核情况)、文档、示例。开发者使用OSGi.NET插件SDK的项目模板来创建WinForm或者Web插件 应用程序时,这个模板默认实现了:(1)调用iOpenWorks启动程序程序集来检查内核文件版本并执行更新;(2)创建插件运行时BundleRuntime 并运行,从而启动插件内核,默认从Plugins目录加载插件;(3)高级模板默认包含了页面流服务插件、应用中心插件、插件管理服务插件、 远程管理服务插件、WebService包装器服务插件(插件自动升级插件没有在模板中包含,可以从插件仓库中下载)
OSGi.NET插件应用程序运行流程及插件协作关系概述
使用OSGi.NET插件SDK创建的插件应用程序结构如下所示。
这个默认的模板中包含了开放工厂原理图所述的iOpenWorks启动程序、OSGi.NET插件框架、默认的几个插件。
当这个插件程序运行后,它首先调用iOpenWorks启动程序来检测OSGi.NET插件框架等内核文件版本并下载更新,接着启动插件运行时, 从Plugins目录中加载并启动插件。在这里,iOpenWorks启动程序将调用开放工厂平台的插件仓库OpenAPI检查是否有新版本的内核并从 仓库中下载最新版本的文件(如原理图的箭头7所示)。
在启动插件过程中,如果应用程序下载安装了自动更新插件,该插件会调用插件管理服务来检查插件仓库更新情况,并自动下载最新版本 的更新包,等重新启动应用程序时,执行自动更新。在这里,插件管理服务将调用开放工厂平台的插件仓库OpenAPI来获取插件仓库的新插件 和新版本的插件并利用OpenAPI进行下载安装或升级插件(如原理图的箭头5、6所示)。
插件运行时启动完成后,主程序从运行时获取页面流服务,获取入口点并运行入口插件的程序,进入主界面或者插件中心插件(如原理图的箭头1所示)。
插件中心插件也将调用插件管理服务,获取开放工厂插件仓库的新插件和插件的最新版本,当点击下载插件时,利用插件管理服务从插件仓库 下载安装或升级插件(如原理图的箭头4、6所示)。
此外,当插件运行时启动完成后,远程管理服务插件利用WebService服务包装器将OSGi.NET内核管理功能暴露成Web服务,这样OSGi.NET 插件SDK的远程管理控制台运行起来后,便可以调用该Web服务实现内核插件、服务浏览以及插件启动、停止、卸载和安装操作,方便插件程序的 调试(如原理图的箭头2、3所示)。
开放工厂插件机制
插件
在OSGi.NET插件框架中,插件是一个具备物理隔离性、完全重用的功能模块。在这里“插件=Manifest.xml + 类 + 资源”,Manifest.xml是插件的描述文件,位于插件目录的根目录下;类即插件的类型空间,由插件自身的程序集和依赖的插件/依赖的程序集组成,资源类似与类,由插件本身的资源和依赖的资源组成。
插件目录
插件由Manifest.xml插件清单文件、程序集、资源组成,程序集和资源位于插件根目录或者子目录下。其标准目录结构如下。
插件类加载
在OSGi.NET插件框架中,插件拥有独立的目录结构,具备物理隔离性。相应地,每一个插件有独立的类型空间,这个类型空间由插件程序集、插件依赖的程序集、片段插件程序集和片段插件依赖的程序集组成。插件的类型是由插件类加载器来加载的。
当你在插件中使用一个类型创建一个对象时,比如MyClassInBundle myClass = new MyClassInBundle(),插件类加载器会按照上面的顺序搜索需要加载的MyClassInBundle类型。与此同时,你也可以通过调用插件对象的LoadClass方法(IBundle.LoadClass)从插件类型空间中动态加载一个类型。
插件生命周期
在OSGi.NET插件框架中,插件具有生命周期。插件生命周期状态有:Installed、Resolved、Active、Uninstalled四个可见状态和Starting、Stopping两个临时状态。其中,Installed表示插件已经安装;Resolved表示插件依赖的程序集或者依赖的插件已经满足,这个插件可以被正常启动;Active则表示插件已经被成功启动;Uninstalled表示插件已经被卸载。Starting是一个过渡状态,当启动插件时,如果插件使用了晚激活策略,则插件在注册扩展信息、服务信息之后,直接返回,不会执行激活器的Start方法,这个方法会推迟到第一次从这个插件加载类型时调用并进入Active状态;反之,如果没有使用晚激活策略,插件会调用激活器Start方法并进入Active状态。在启动过程,如果出现异常,则插件会自动转回Resolved状态。Stopping是另一个临时状态,在停止插件时,首先进入该状态,然后调用激活器的Stop方法后进入Resolved状态。
插件运行时和插件启动过程
插件框架启动时,首先从插件目录中发现并加载所有的插件;然后,对插件进行依赖解析,判断插件依赖的程序集和依赖的插件是否满足;接着,按照启动级别顺序启动所需的插件;一旦插件启动完成,则插件框架便完成启动。
在插件启动过程中,将按照创建插件上下文、注册扩展点/扩展信息、注册服务信息、创建插件激活器并调用Start方法的顺序完成一个插件的启动过程。如果插件实现的晚激活,则推迟最后一步的执行,直到第一次从插件加载类型;如果插件没有定义激活器,则忽略最后一步。
插件相关对象
插件运行时BundleRuntime
插件运行时BundleRuntime代表插件框架内核对象,它是所有插件的运行容器。 在示例中,控制台主程序在Program的Main函数中,通过创建BundleRuntime对象并调用其 Start方法来启动插件框架内核。当Start方法调用完成后,BundleRuntime对象将从插件目 录中加载插件并启动插件。
通过以下代码,您就可以创建并启动插件框架,然后加载并启动所有插件。
认识插件
插件也称为Bundle,从OSGi.NET规范上讲,“插件=Manifest.xml + 类 + 资源”。其中, Manifest.xml即插件清单文件,用于描述插件的基本信息、类型信息和扩展信息; 插件具备隔离的类型空间,由插件本身的程序集和依赖的插件的程序集组成; 插件拥有自己的资源,存放在私有的文件夹。
在定义一个插件时,您只需要关注三个非常重要的接口,分别是:插件激活器IBundleActivator、 插件IBundle和插件上下文IBundleContext。
其中,插件激活器由开发人员自己定义;而插件IBundle和插件上下文IBundleContext则由插件内核创建, 你可以在插件激活器获取中获取到这两个对象。
插件清单Manifest.xml
插件清单文件(Manifest.xml)位于模块标准目录结构的根目录之下,它定义了模块的基本信息、模块激活信息、模块类加载相关的运行时信息、服务定义信息、模块扩展定义信息以及模块详细信息。
以上清单文件定义了该模块的一个本地程序集“bin\ShellPlugin.dll”,该程序集位置相对于模块的根目录,当然,你也可以指定一个绝对目录。模块还定义了一个激活器和扩展点。
IBundleActivator
IBundleActivator表示插件激活器,是插件的入口和出口,用于在插件启动或停止时执行相关操作。
插件激活器通过Manifest.xml的Activator节点配置,当插件被启动时插件激活器的Start方法被调用, 当停止时Stop方法被调用。
在插件激活器的Start/Stop方法的context参数,即插件上下文IBundleContext对象,通过IBundleContext 您还可以获取对应的插件IBundle实例。
以下是一个激活器定义的示例。你需要在插件清单文件Manifest.xml添加一个激活器配置: <Activator Type="HelloBundle.Activator" Policy="Immediate" />。
· using System;
· using System.Collections.Generic;
· using UIShell.OSGi;
·
· namespace HelloBundle
· {
· /// <summary>
· /// 模块激活器,它是一个模块启动和停止的入口。当模块被启动时,激活器的Start方法会被调用;
· /// 如果是被停止,则其Stop方法会被调用。一般而言,一个模块会在Start方法中向系统提供功能、
· /// 注册服务、申请如线程等资源等,在Stop方法会执行回收操作,比如关闭功能、卸载服务、释放
· /// 资源等。需要注意的是,在Start方法中申请的资源必须在Stop方法中得到释放,而且一个模块
· /// 的Start/Stop方法在运行过程可能会被调用多次,必须确保再次调用Start/Stop方法不会出现
· /// 异常。
· /// </summary>
· public class Activator : IBundleActivator
· {
· /// <summary>
· /// 模块启动时调用的方法。
· /// </summary>
· /// <param name="context">模块上下文,通过模块上下文可以获取对框架功能访问、
· /// 服务注册表访问、模块生命周期等功能访问。
· /// 模块上下文是框架提供给模块唯一的对象。</param>
· public void Start(IBundleContext context)
· {
· // 向屏幕打印消息“HelloBundle is started.”
· Console.WriteLine(string.Format("{0} is started.", context.Bundle.Name));
· }
·
· /// <summary>
· /// 模块停止时调用的方法。
· /// </summary>
· /// <param name="context">模块上下文。</param>
· public void Stop(IBundleContext context)
· {
· Console.WriteLine(string.Format("{0} is Stopped.", context.Bundle.Name));
· }
· }
· }
认识IBundle
IBundle表示由内核创建的一个插件,一般而言,“Bundle=Manifest.xml + 类 + 资源”。
插件对象向您暴露了以下功能:
(1)类型加载。
(2)资源加载。
(3)插件生命周期操作。
认识IBundleContext
IBundleContext表示插件上下文,实现了对插件框架的反射,通过模块激活器IBundleActivator的 Start/Stop方法的参数获取该对象。
插件上下文向您暴露了以下功能:
(1)获取对应的插件实例。
(2)对插件执行生命周期操作,安装其它插件。
(3)插件仓库查询。
(4)服务注册与绑定。
(5)获取本插件的扩展点和扩展。
(6)监听框架事件、服务事件、插件事件和扩展事件。
展开阅读全文