OSGI.NET 模块化示例演示

Sample 01:一个简单的模块

1 新建一个名为SimpleModuleShell的“控制台宿主应用程序”项目。

image.png

2 添加一个新建项目,名称为SimpleModule项目,其项目路径指向SimpleModuleShell项目的bin\plugins文件夹,这样一个默认的模块便创建完成。

image.png

3 新建的SimpleModule模块由Activator.cs文件和Manifest.xml文件组成。

4 Manifest.xml是模块的配置信息,默认创建的内容如下。

<?xml version="1.0" encoding="utf-8"?>
<!-- 定义一个模块,其特征名称为SimpleModule。特征名称是唯一标识一个模块的名称。 -->
<Bundle xmlns="urn:uiosp-bundle-manifest-2.0" Name="SimpleModule" SymbolicName="SimpleModule" Version="1.0.0.0" InitializedState="Active">
  <!-- 模块激活器定义。 -->
  <Activator Type="SimpleModule.Activator" Policy="Immediate" />
  <Runtime>
    <!-- 模块本地程序集声明。 -->
    <Assembly Path="bin\SimpleModule.dll" Share="false" />
  </Runtime>
</Bundle>

这个模块配置定义了模块的特征名称是SimpleModule,激活器是SimpleModule.Activator,包含一个模块工程下的“bin\SimpleModule.dll”本地程序集。一旦SimpleModuleShell运行,SimpleModule模块会被按装到系统并调用SimpleModule.ActivatorStart方法启动模块,反之,一旦停止,Stop方法会被调用。

 

注意:Manifest.xml默认编辑器是UIOSP编辑器,它是一个图形化编写模块配置的工具,如下所示。

image.png

如果要查看Manifest.xml文件,按F7或者右键查看代码。

5 Activator.cs是激活器的定义,在该模块我们定义的激活器如下。

using System;
using System.Collections.Generic;
using UIShell.OSGi;
 
namespace SimpleModule
{
    /// <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)
        {
            Console.WriteLine("SimpleModule is started.");
        }
 
        /// <summary>
        /// 模块停止时调用的方法。
        /// </summary>
        /// <param name="context">模块上下文。</param>
        public void Stop(IBundleContext context)
        {
            Console.WriteLine("SimpleModule is stopped.");
        }
    }
}

6 运行SimpleModuleShellSimpleModule模块默认会被启动。该模块在启动时会在控制台输出“SimpleModule is started.”。

image.png

7 使用Remote Console查看模块运行状态,其结果如下

image.png

8 Remote Console输入“stop/start 3”分别用于停止和启动SimpleModule模块,模块状态便发生改变,且激活器Stop/Start方法会被分别调用,并在控制台打印以下信息。

image.png

Sample 02:模块初始状态

1 Sample01基础上,修改Manifest.xmlBundle节点,添加一个“InitializedState="Install"”的XML属性。InitializedState是模块初始状态,可能为Install或者Active,如果不指定默认为Active。或者在编辑器上直接取消“Start the bundle when the framework is activated.

image.png

2 运行SimpleModuleShell,利用Remote Console查看UIOSP模块状态,如下。

image.png

此时,SimpleModule的状态为Install状态。

Sample 03:模块激活器与晚激活

1 Sample01基础上,修改Mainfest.xmlActivator配置节点,添加“Policy="Lazy"”属性。模块有两种激活方式:立即激活和晚激活。立即激活意味着模块一旦被启动,其激活器的Start方法便会调用;而晚激活则会将激活器Start方法的调用推迟到“第一次尝试从该模块加载一个类”时机。

2 运行SimpleModuleShell,通过Remote Console查看模块运行情况如下。

image.png

3 SimpleModule添加一个ClassLoadingToActivate类,该类为测试类,不做任何实现。

namespace SimpleModule
{
    public class ClassLoadingToActivate
    {
    }
}

4 添加另一个模块LoadClassModule,该模块用于加载SimpleModuleClassLoadingToActivate类,从而导致SimpleModule执行激活。

1)修改Manifest.xml,将该模块初始状态变为Install,即默认为不启动;此外,添加对SimpleModule模块的依赖。

<?xml version="1.0" encoding="utf-8" ?>
<!-- 初始状态更改为Install,即默认不启动。 -->
<Bundle xmlns="urn:uiosp-bundle-manifest-2.0" SymbolicName="LoadClassModule" InitializedState="Install">
  <Activator Type="LoadClassModule.Activator"/>
  <Runtime>
    <Assembly Path="bin\LoadClassModule.dll"/>
<!-- 添加对SimpleModule模块的依赖 -->
<Dependency BundleSymbolicName="SimpleModule"/>
  </Runtime>
</Bundle>

2)在Activator中,加载ClassLoadingToActivate类。

namespace LoadClassModule
{
    public class Activator : IBundleActivator
    {
        public void Start(IBundleContext context)
        {
            IBundle simpleModule = context.GetBundleByName("SimpleModule");
            Type classLoadingToActivateType = simpleModule.LoadClass(
"SimpleModule.ClassLoadingToActivate");
        }
 
        public void Stop(IBundleContext context)
        {
            //todo:
        }
    }
}

5 运行SimpleModuleShell,启动Remote Console查看模块运行情况如下。

image.png

6 Remote Console执行“start 2”,启动LoadClassModule。一旦LoadClassModule被启动,它的激活器会从SimpleModule加载ClassLoadingToActivate类,从而触发SimpleModule进入Active状态。

image.png

此时,在控制台上,将打印SimpleModule is started.”。

image.png

Sample 04:模块本地程序集

1 Sample01基础上,新建一个SimpleModuleLib类库程序集,并添加一个SayHello类。

namespace SimpleModuleLib
{
    public class SayHello
    {
        public void Hello(string name)
        {
            Console.WriteLine(string.Format("Hello, {0}.", name));
        }
    }
}

2 SimpleModule中添加对SimpleModuleLib项目引用,并修改Manifest.xmlRuntime配置节点,添加一个“<Assembly Path="bin\SimpleModuleLib.dll"/>”子节点。

<?xml version="1.0" encoding="utf-8" ?>
<Bundle xmlns="urn:uiosp-bundle-manifest-2.0" SymbolicName="SimpleModule">
  <Activator Type="SimpleModule.Activator"/>
  <Runtime>
    <Assembly Path="bin\SimpleModule.dll"/>
<!-- 添加模块依赖的本地程序集。这样做的目的:(1)使CLR类加载器能够加载到该类;(2)支持类型晚加载。 -->
<Assembly Path="bin\SimpleModuleLib.dll"/>
  </Runtime>
</Bundle>

3 Runtime配置节点定义了模块运行过程中需要的类型信息,Assembly配置节点定义了模块的本地程序集。这样的定义,其目的是(1)是CLR类加载其能够从不在标准文件目录下的程序集加载到所需的类型;(2)支持从程序集晚加载所需类型。

4 运行SimpleModuleShell,结果如下。

image.png

5 注意:如果模块引用了一个程序集,但是在Manifest.xmlRuntime没有相关的本地程序集Assembly配置,在类型加载时,会发生类型查找不到的异常。

6 Assembly配置节点Path属性是必填的项,它用于指定本地程序集相对于模块根路径的相对路径。

Sample 05:模块类型复用与依赖

1 UIOSP中,模块间可以实现类型复用。这个示例基于Sample 04之上,实现了类型复用的示例。首先修改SimpleModuleManifest.xml中的SimpleModuleLib本地程序集声明,为该声明一个Share属性。Share属性则表示该程序集是否能够与其它Bundle复用。

<?xml version="1.0" encoding="utf-8" ?>
<Bundle xmlns="urn:uiosp-bundle-manifest-2.0" SymbolicName="SimpleModule">
  <Activator Type="SimpleModule.Activator"/>
  <Runtime>
    <Assembly Path="bin\SimpleModule.dll"/>
<!-- 添加模块依赖的本地程序集。这样做的目的:(1)使CLR类加载器能够加载到该类;(2)支持类型晚加载。 -->
<!-- Share用于声明一个程序集是否可以被其它模块复用。 -->
<Assembly Path="bin\SimpleModuleLib.dll" Share="true"/>
  </Runtime>
</Bundle>

或者通过编辑器添加一个如下程序集。

image.png

2 新建一个DependencyModule控制台插件应用程序,然后浏览并引用SimpleModule模块下的bin\SimpleModuleLib.dll程序集,需要注意的是,我们必须把这个引用的“复制本地”变为false。如下图。

image.png

3 Manifest.xml添加对SimpleModule程序集的依赖。

<?xml version="1.0" encoding="utf-8" ?>
<Bundle xmlns="urn:uiosp-bundle-manifest-2.0" SymbolicName="DependencyModule">
  <Activator Type="DependencyModule.Activator"/>
  <Runtime>
    <Assembly Path="bin\DependencyModule.dll"/>
<!-- 添加对SimpleModuleLib程序集的依赖。 -->
<Dependency BundleSymbolicName="SimpleModule" AssemblyName="SimpleModuleLib"/>
  </Runtime>
</Bundle>

4 Activator使用SimpleModuleLib中的SayHello类。

namespace DependencyModule
{
    public class Activator : IBundleActivator
    {
        public void Start(IBundleContext context)
        {
            //todo:
            SimpleModuleLib.SayHello sayHello = new SimpleModuleLib.SayHello();
            sayHello.Hello("DependencyModule");
        }
 
        public void Stop(IBundleContext context)
        {
            //todo:
        }
    }
}

5 运行SimpleModuleShell,结果如下。

image.png

Sample 06:模块启动级别

1 模块启动级别在模块Manifest.xml,用于设置模块启动顺序、框架安全启动、屏蔽异常模块等。框架系统模块启动级别为1,级别越小优先级越高。框架默认启动级别为100,即小于等于100的模块会被框架启动,大于100则不会。

2 Sample 01基础上,新建SimpleModule1SimpleModule2控制台插件应用程序。

3 分别设置SimpleModuleSimpleModule1SimpleModule2的启动级别为234

4 运行SimpleModuleShell,其结果如下。

image.png

Sample 07:片段模块

1 Sample 01基础上创建一个FragmentModule的控制台插件应用程序。片段模块和宿主模块相比,它不是一个正常的模块,不能被启动、停止,不能从片段模块加载任何资源。片段模块声明的所有配置最终将合并到它指定的宿主模块。如果我们需要依赖一个片段的程序集,那么我们声明的依赖必须指向该片段模块的宿主模块。

2 删除Activator.cs,修改Manifest.xml文件将Activator配置节删掉。

3 修改Manifest.xmlBundle配置节点,添加“HostBundleSymbolicName="SimpleModule"”属性,设置FragmentModule模块的HostBundleSimpleModule

image.png

4 FragmentModule添加一个SayHelloFromFragment类,如下。

namespace FragmentModule
{
    public class SayHelloFromFragment
    {
        public void Hello(string name)
        {
            Console.WriteLine(string.Format("Hello, {0}.", name));
        }
    }
}

5 SimpleModuleActivator加载SayHelloFromFragment类型,并利用反射调用其Hello方法。

namespace SimpleModule
{
    public class Activator : IBundleActivator
    {
        public void Start(IBundleContext context)
        {
            Type sayHelloFromFragmentType = context.Bundle.LoadClass(
"FragmentModule.SayHelloFromFragment");
            if (sayHelloFromFragmentType != null)
            {
                object sayHello = System.Activator.CreateInstance(sayHelloFromFragmentType);
                MethodInfo helloMethod = sayHello.GetType().GetMethod("Hello");
                helloMethod.Invoke(sayHello, new object[] { "FragmentModule." });
            }
        }
 
        public void Stop(IBundleContext context)
        {
        }
    }
}

6 新建一个FragmentDependencyModule的控制台插件应用程序。修改Manifest.xml添加对SimpleModule模块依赖,如下。

<?xml version="1.0" encoding="utf-8" ?>
<Bundle xmlns="urn:uiosp-bundle-manifest-2.0" SymbolicName="FragmentDependencyModule">
  <Activator Type="FragmentDependencyModule.Activator"/>
  <Runtime>
    <Assembly Path="bin\FragmentDependencyModule.dll"/>
    <Dependency BundleSymbolicName="SimpleModule"/>
  </Runtime>
</Bundle>

7 在FragmentDependencyModule模块激活器中使用片段模块的SayHelloFromFragment类。

using System;
using System.Collections.Generic;
using UIShell.OSGi;
using FragmentModule;
 
namespace FragmentDependencyModule
{
    public class Activator : IBundleActivator
    {
        public void Start(IBundleContext context)
        {
            SayHelloFromFragment sayHelloFromFragment = new SayHelloFromFragment();
            sayHelloFromFragment.Hello("FragmentDependencyModule");
        }
 
        public void Stop(IBundleContext context)
        {
            //todo:
        }
    }
}

8 运行SimpleModuleShell,结果如下。

image.png

Sample 08:模块与程序集版本

1 该框架支持多版本模块和程序集。一个模块可以在Bundle配置定义添加一个Version属性来设置版本,一个程序集可以在Assembly配置定义添加一个Version属性设置程序集的版本号。依赖于该模块或者程序集的模块可以在Dependency定义中设定依赖的版本范围或者是特定的版本。

2 Sample 05基础之上,修改SimpleModule模块Manifest.xml,添加模块版本和程序集版本。定义如下。

<?xml version="1.0" encoding="utf-8" ?>
<!-- 设置模块的版本号为1.2。 -->
<Bundle xmlns="urn:uiosp-bundle-manifest-2.0" SymbolicName="SimpleModule" Version="1.1">
<Activator Type="SimpleModule.Activator"/>
<Runtime>
<Assembly Path="bin\SimpleModule.dll"/>
<!-- 设置该模块一个共享程序集,否则会出现类型加载失败。 -->
<Assembly Path="bin\SimpleModuleLib.dll" Share="true"/>
</Runtime>
</Bundle>

3 修改DependencyModule模块的Manifest.xml,设置版本依赖约束如下。

<?xml version="1.0" encoding="utf-8" ?>
<Bundle xmlns="urn:uiosp-bundle-manifest-2.0" SymbolicName="DependencyModule">
  <Activator Type="DependencyModule.Activator"/>
  <Runtime>
    <Assembly Path="bin\DependencyModule.dll"/>
<!-- 添加对SimpleModuleLib程序集的依赖,它设置的版本范围为0.0~2.0。 -->
<Dependency BundleSymbolicName="SimpleModule" BundleVersion="[0.0, 2.0]" 
AssemblyName="SimpleModuleLib" AssemblyVersion="[0.0, 2.0]" />
  </Runtime>
</Bundle>

4 运行SimpleModuleShell,结果如下。

image.png


本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年4月    »
1234567
891011121314
15161718192021
22232425262728
2930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864