OSGi.NET 學習筆記 [模塊可擴展支持][概念][實例]


Demo 點擊下載

目錄】- 【模塊可擴展支持】-【概念】 

  目前為止我們已經了解了模塊化的隔離策略,面向服務的交互策略,現在就該來看看更高級的模塊擴展策略,這里的“可擴展”在官方文檔是這么介紹的
  1) 擴展點:通過標准XML節點<ExtensionPoint>來定義一個模塊向其它模塊暴露的擴展點。暴露擴展點的模塊會監聽並處理其它模塊對其的擴展。
  2) 擴展:通過標准XML節點<Extension>來定義一個模塊對暴露擴展點的模塊的擴展。這個XML節點會通過擴展點變更事件傳遞到暴露擴展點的模塊。
  3) 動態擴展:模塊在啟動和停止時,會分別向平台注冊和卸載相應的擴展點及擴展,該平台通過模塊上下文暴露擴展點變更事件來處理動態的擴展信息。
  4) 零耦合:模塊的擴展沒有任何的耦合,僅通過標准XML來配置。


  為什么要引入擴展機制呢?這得從現實的使用場景來說,除了必要的邏輯模塊外,其實一個程序大部分的工作都是和前台,即UI來打交道,這時候就避免不了要為每個功能模塊在界面上設置一個按鈕,一個下拉菜單等等的”交互點“。這個時候,對於一個插件框架來說,就必須能處理一個模塊對界面的“擴展”,也就是支持邏輯模塊對界面模塊的擴充或改變。當然這只是一個典型的例子,擴展的功用遠大於此。


  我們再看一個具體的場景,一個音樂播放器,它默認只支持MP3格式,現在准備讓它支持更多,比如FLAC,APE等,播放這些格式需要特定的解碼模塊支持,那么如何讓主程序知道且能自動識別各個格式的解碼模塊呢?而且是動態的?而且是不需要修改主程序的?一種可行的辦法就是利用上一節講的面向服務來定義一個接口,具體的解碼模塊來實現它並注冊到服務總線上,但服務總線在這里稍顯“繁瑣”。OSGi.NET提供了更簡單的方式,就是這里所說的“擴展點”和“擴展”,如下圖
  

  我們還是拿主板來做比較,這里的插件A就像是主板上的USB,支持2.0規范,它的作用就是暴露出一個接口,使得一個同樣支持2.0的U盤,即插件B,可以插入此接口,完成與主板的連接。
  


  如果假設這里的USB是主程序中的一個模塊,則它的功能大致是
  1) 定義一個“契約”,類似這里的USB 2.0規范
  2) 當一個符合定義好的契約的模塊插入接口時,識別它
  3) 將這個識別的模塊附加信息讀取出來,以供主程序或者其他模塊使用
  這是我們可以說這個模塊具有了“擴展點”。


  同理,如果U盤也是一個模塊,則它需要有以下功能
  1) 符合上面模塊所定義的契約
  2) 將自己的模塊附加信息暴露給上面的模塊以便識別和讀取
  則它是上面擴展點的一個“擴展”。


  接着,我們再來看看前面提到的音樂播放器自動支持多種格式的問題,我們假設播放器的“格式識別”是一個模塊,他定義了一個“AudioFormat”的擴展點,那其他解碼模塊只要依照這個擴展點定義擴展它並附帶上自己的解碼類型,如APE,和處理方法,如APE.PlayAPEFile,則格式識別模塊會將這些信息收集起來並以服務的形式供主程序檢索和調用。這種擴展機制明顯比服務總線來說簡單且沒有任何模塊間的依賴。


  此外,OSGi.NET的擴展點和擴展都是定義在相應模塊的Mainfest.xml文件中的,就非常容易后期維護和更改。模塊與模塊之間就可以完成“擴展點和擴展”,當然主程序中啟動的運行時環境也能直接處理指定“擴展點”的“擴展”。


  下一節,我們看一個如何編寫這個音樂播放器。

目錄】- 【模塊可擴展支持】-【實例】

  同前面的實例一樣
  1) 第一步,我們依然通過OSGi.NET提供的項目模板來創建一個“控制台主應用程序”,這個主程序主要完成與用戶的交互以及信息的輸出。這里我們把這個主程序起名為OSGi.NET.AudioPlayerShell,這個Shell表示這是一個“外殼”、框架,也就是啟動OSGi.NET內核的入口程序
  

  2) 接着我們在創建兩個“虛擬目錄”,FormatTypes和FormatServices,用來將我們的模塊進行分類,FormatTypes下還包含Lossless和Lossy,分別代表無損格式和有損格式。
  

  3) 如前面概念所介紹的,我們這個播放器需要一個“格式識別”模塊,它作為一個服務用來識別其他解碼模塊並向主程序暴露。這里起名為OSGi.NET.AudioFormatService,並把它放在Services虛擬目錄中。注意它是一個“服務”,名稱中帶有Service后綴且路徑是在Shell主程序下Plugins\FormatServices,和上面的實例稍有不同
  

  4) 接下來我們為有損格式創一個OSGi.NET.MP3DecoderPlugin的“控制台插件”,為無損格式創建一個OSGi.NET.APEDecoderPlugin的“控制台插件”。注意這里我們使用了Plugin作為模塊名稱的后綴,代表他是一個插件,且路徑是Plugins\FormatTypes\Lossy,同理OSGi.NET.APEDecoderPlugin是Plugins\FormatTypes\Lossless
  
  
  

  5) 創建完成后,解決方案如下圖所示
  

  文件結構如下圖所示
  

  6) 編譯整個解決方案后,按F5啟動,只有默認輸出。查看bin目錄下的log.txt可以看到全部模塊都正常啟動並處於“激活(Active)”狀態,表示我們現在使用的新的目錄架構對程序沒有任何影響。這點對超過一定數量,比如100個模塊以上,的大型系統來說,非常方便,可按照一定的類別划分各個模塊並放入相應的目錄中
  

  7) 現在我們來給OSGi.NET.AudioFormatService添加“擴展點”,擴展點可在Manifest編輯器中直接添加,“點”這里為“OSGi.NET.AudioFormat”,如下圖
  
  Manifest.xml中會添加這樣一行
  
  添加擴展點完成。


  8) 接着來給OSGi.NET.MP3DecoderPlugin和OSGi.NET.APEDecoderPlugin添加具體的解碼邏輯,簡單的只是輸出一行提示信息。這里先給OSGi.NET.AudioFormatService添加一個IAudioDecoder的接口
  

  並實現它
  
  
  
  此處同樣需要添加依賴關系,可參考上一節“面向服務架構支持”的相關實例。

  9) 然后來給OSGi.NET.MP3DecoderPlugin添加對上面擴展點的“擴展”,依然在編輯器中。這里我們只是簡單的附加了兩條信息,一個是格式名,還有就是格式的解碼類名
  

  Manifest.xml如下
  

  
  Manifest.xml如下
  
  完成擴展定義。


  10) 接着我們來考慮一下OSGi.NET.AudioFormatService如何來響應和讀取這些來自其他模塊的擴展信息,並通過服務的形式暴露給主程序
    a) 首先將默認的ICustomService.cs接口、Impl目錄下的CustomService.cs實現以及Activator.cs中的服務注冊對象,更名為IAudioFormatExtensionService和AudioFormatExtensionService
    

    b) 接着創建一個AudioFormatExtension類,用來描述讀取到的擴展信息
    

    c) 再來定義IAudioFormatExtensionService接口
    

    d) 准備工作完成后,現在才真正的來通過OSGi.NET提供的擴展機制來實現對擴展信息的動態捕獲,在Activator,激活器,的start函數中添加如下代碼,用來從運行時獲取指定擴展點名的所有擴展。
    

    ExtensionChanged事件的處理,我們放在小結中給大家演示。


    e) 接着,我們創建AudioFormatExtensionContainer來處理擴展信息
    

    f) 簡單完成后,我們就可以來實現AudioFormatExtensionService了
    

    g) OK,現在就可以在主程序中直接調用了
    

    運行效果
    

    h) 注意當你點擊回車結束程序時,會有異常發生
    

    這點我們下一步做演示時會解決掉它。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM