插件是一種遵循統一的預約義接口規範編寫出來的程序,應用程序在運行時經過接口規範對插件進行調用,以擴展應用程序的功能。在英文中插件一般稱爲plug-in、plugin或者plug in。插件最典型的例子是Eclipse開發平臺,Microsoft的ActiveX控件和COM(Component Object Model,部件對象模型)實際上ActiveX控件不過是一個更高繼承層次的COM而已。此外還有Photoshop的濾鏡(Filter)也是一種比較常見的插件,還有就是Mozilla Firefox,Foobar等等也遵循着插件機制。數據庫
插件最吸引人的地方固然就是其所實現「運行時(Run-time)」功能擴展。這意味着軟件開發者能夠經過公佈插件的預約義接口規範,從而容許第三方的軟件開發者經過開發插件對軟件的功能進行擴展,而無需對整個程序代碼進行從新編譯。運行時是相對於編譯時(Assembly-time)而言的。通常來講,軟件開發者對軟件功能更新時,是在源代碼級別進行更新,而後對整個程序進行從新編譯,進而發佈應用程序的新版本,這就是編譯時的軟件更新。編程
插件的本質在於不修改程序主體(或者程序運行平臺)的狀況下對軟件功能進行擴展與增強,當插件的接口公開後,任何公司或我的均可以製做本身的插件來解決一些操做上的不便或增長新的功能,也就是實現真正意義上的「即插即用」軟件開發。「平臺+插件軟件結構」是將一個待開發的目標軟件分爲兩部分,一部分爲程序的主體或主框架,可定義爲平臺,另外一部分爲功能擴展或補充模塊,可定義爲插件。多線程
在進行軟件開發以前,是否採用「平臺+插件軟件結構」進行軟件開發,還要依據具體的軟件需求狀況進行肯定,但通常來說,使用「平臺+插件軟件結構」進行軟件設計會給所開發軟件增長新的生命力。當肯定「平臺+插件的軟件結構」以後,就要分析哪些部分功能由主體完成(即平臺的基本功能),哪些部分功能由插件完成(即須要擴展的插件功能)。平臺所完成的功能應爲一個軟件系統的核心和基礎,這些基本功能便可爲用戶使用,也可爲插件使用,就是又能夠把平臺基本功能分爲兩個部分,內核功能和插件處理功能。平臺的內核功能是整個軟件的重要功能,一個軟件的大部分功能因由內核功能完成。平臺的插件處理功能用於擴展平臺和管理插件,爲插件操縱平臺和與插件通訊提供標準平臺擴展接口。插件所完成的功能是對平臺功能的擴展與補充,通常插件完成系列化功能。架構
爲了實現平臺+插件結構的軟件設計須要定義兩個標準接口,一個爲由平臺所實現的平臺擴展接口,一個爲插件所實現的插件接口。這裏須要說明的是:平臺擴展接口徹底由平臺實現,插件只是調用和使用,插件接口徹底由插件實現,平臺也只是調用和使用。平臺擴展接口實現插件向平臺方向的單向通訊,插件經過平臺擴展接口可獲取主框架的各類資源和數據,可包括各類系統句柄,程序內部數據以及內存分配等。插件接口爲平臺向插件方向的單向通訊,平臺經過插件接口調用插件所實現的功能,讀取插件處理數據等。框架
平臺插件處理功能包括插件註冊、管理和調用,以及平臺擴展接口的功能實現。插件註冊爲按照某種機制首先在系統中搜索已安裝插件,以後將搜索到的插件註冊到平臺上,並在平臺上生成相應的調用機制,這包括菜單選項、工具欄、內部調用等。插件管理完成插件與平臺的協調,爲各插件在平臺上生成管理信息以及進行插件的狀態跟蹤。插件調用爲調用各插件所實現的功能。平臺插件處理功能實現的另外一部分功能爲平臺擴展接口的具體實現。函數
開發支持插件功能的應用程序必須解決一個問題:如何在主程序與插件間正確地互相通訊。爲了在主程序與插件之間能正確地互相通訊,應該先制定一套通訊標準,這套通訊標準就是接口,主程序與插件只能經過制訂好的接口進行通訊。軟件開發中,接口只是定義功能並規定調用功能的形式,而不包含功能的實現。接口實質上是軟件模塊的調用規範。在後續章節中咱們將會介紹kettle開發的插件中,經常使用的幾種通信方式。工具
就開發支持插件功能的應用程序而言,通常來講由主程序的開發者來制訂接口,若是但願其餘的開發人員能開發相關的插件,只要公開相關接口便可。接口功能通常由插件方實現。由於插件的實現也要調用主程序的功能,因此接口功能也可能由主程序來實現。也就是說,主程序與插件的信息流多是雙向的。ui
接口的調用規範與功能實現互相分離有一個很大的優勢:儘管不一樣的插件開發者對同一個接口的具體實現不一樣,可是在主程序中對這些插件的調用方式是同樣的。若是有主程序實現的接口,在不一樣的插件中也能夠用相同的使用方式調用主程序的功能。這極大的提升了應用程序的靈活性。spa
主程序中,插件管理部分用於管理插件的安裝和刪除,並將全部安裝插件的信息保存到適合的地方,例如保存到註冊表或配置文件中。主程序啓動時,根據插件的配置信息加載插件模塊,而後得到插件的輸出函數或輸出類的指針並加以保存,若是須要的話,能夠向主程序增長界面接口元素,如菜單、工具條按鈕等。在主程序中當點擊與插件相關聯的接口元素時,就會觸發插件調用函數,在插件調用函數中使用主函數中所保存的插件信息調用插件中實現的功能。在調用插件輸出函數時也能夠把主程序中實現的接口傳遞給插件方。插件
圖 2‑1 Kettle插件架構
Kettle分爲kettle平臺、各種插件。其中kettle平臺是整個系統的基礎,包括UI、插件管理、元數據管理和數據集成引擎。UI顯示Spoon這個核心組件的界面,經過xul實現菜單欄、工具欄的定製化,顯示插件界面接口元素。元數據管理引擎管理ktr、kjb或者元數據庫,插件經過該引擎獲取基本信息。插件管理引擎主要負責插件的註冊。數據集成引擎負責調用插件,並返回相應信息。
Kettle是衆多「可供插入的地方」(擴展點)和「能夠插入的東西」(擴展)共同組成的集合體。在咱們的生活中,電源接線板就是一種「擴展點」,不少「擴展」(也就是電線插頭)能夠插在它上面。
在Kettle中不論是之後的擴展仍是系統集成的功能,本質上來說都是插件,管理方式和運行機制是一致的。系統集成的功能點也均實現了對應的擴展接口,只是在插接的說明上略有不一樣。
Kettle的擴展點包括step插件、job entry插件、Database插件、Partioner插件、debugging插件,這裏咱們重點介紹step、job entry、database插件。暴露的擴展點以下表所示:
表 1 Step擴展接口
Java接口 |
基類 |
主要功能 |
StepMetaInterface |
BaseStepMeta |
存儲step設置信息 驗證step設置信息 序列化step設置信息 提供獲取step類的方法 |
StepDialogInterface |
BaseStepDialog |
step屬性信息配置窗口 |
StepInterface |
BaseStep |
處理rows |
StepDataInterface |
BaseStepData |
爲數據處理提升數據存儲 |
表 2 job entry擴展接口
Java接口 |
基類 |
主要功能 |
JobEntryInterface |
JobEntryBase |
存儲job entry設置信息 序列化job entry設置信息 提供獲取job entry類的方法 執行job entry任務 |
JobEntryDialogInterface |
JobEntryDialog |
job entry屬性信息配置窗口 |
表 3 Database 擴展接口
Java接口 |
基類 |
主要功能 |
DatabaseInterface |
BaseDatabaseMeta |
訪問各種數據庫 |
Kettle中的插件包含兩部分,一是系統自己就已經實現的功能點,在源碼目錄src中說明,如kettle-steps.xml;二是系統以外開發的插件,在plugins目錄對應插件目錄下的plugins.xml說明,plugins/steps/S3CsvInput/plugins.xml。
表 4 系統自帶插件定義
內容 |
位置 |
插件說明信息 |
src/kettle-steps.xml,全部插件集中說明 |
插件源碼 |
src與src-ui下,org.pentaho.di.steps.插件名 |
插件圖片 |
插件說明xml中說明 |
插件界面文字說明 |
org.pentaho.di.steps.插件名.messages |
插件說明信息中包括描述信息、類名(包括package,反射用)、父級目錄(Spoon左側欄目錄)、提示信息和圖片信息。Kettle使用國家化方式編程,因此軟件中的全部文字描述均由messages_**.properties提供。
圖 2‑2 系統集成插件說明xml結構
因此新開發的擴展插件,均放在同一的目錄下進行管理,插件管理模塊會自動去該目錄下進行搜索查找。插件目錄結構以下所示:
圖 2‑3 擴展插件目錄結構
表 5 擴展插件定義
內容 |
位置 |
插件說明信息 |
plugins/插件類型/插件名稱/plugin.xml |
插件源碼 |
*.jar |
插件圖片 |
plugins/插件類型/插件名稱/ |
插件依賴包 |
plugins/插件類型/插件名稱/ |
擴展插件與系統集成插件的說明內容類似,擴展插件增長ID屬性和依賴屬性,同時他的目錄結構、描述信息和提示信息均能進行國際化配置。
圖 2‑4 擴展插件說明xml結構
Spoon在啓動的時候會對全部插件進行註冊,並保存在PluginRegistry類裏面。平臺經過查找PluginRegistry註冊表獲取插件信息。Kettle安裝插件須要進行重啓,卸載插件也只需簡單的刪除plugins目錄結構下對應的文件便可。
圖 2‑5 插件註冊時序圖
圖 2‑6 plugin註冊相關的UML類圖
PluginRegistry首選註冊本系統的插件類型處理類,源碼中註冊了7中類型,咱們這裏僅介紹3中,並以StepPluginType爲例。註冊類型處理類後,PluginRegistry按照不一樣的類型進行插件搜索(模板模式),基類BasePluginType提供了本地搜索、jar搜索、xml信息搜索3種鉤子。根據搜索結果,按照不一樣的插件類型存儲在PluginRegistry中。
PluginRegistry提供了插件查找功能,準確的來講是插件信息的查找功能。以steps在左側功能欄裏面的顯示爲例,進行插件查找的說明。提供了getPlugins獲取指定插件類型列表、getPlugin獲取指定成名插件、getCateories獲取目錄結構、getClass獲取指定插件類等方法。
圖 2‑7 Spoon中step列表
左側顯示由Spoon.refreshCoreObjects()函數實現,若是選擇時trans相關的內容,將顯示全部的step插件。流程圖以下所示:
圖 2‑8 spoon界面step插件顯示流程
Kettle中調用插件時,平臺經過元素管理引擎獲取對應的插件信息,經過反射生成插件對象,調用對應的函數。Kettle之外觀模式的方式調用插件,咱們以雙擊某個插件圖表,彈出對應配置界面爲例進行說明,具體的轉換時調用將在後面進一步說明。
Spoon界面交互相關的處理器都封裝到SpoonDelegates中,根據不一樣的事件類型調用對應的事件處理函數。UML類圖以下所示。
圖 2‑9 事件代理類
SpoonStepsDelegate提供了與UI交互相關的處理事件,如複製、刪除、粘貼、編輯等。雙擊某個step時會調用編輯功能,編輯功能是對插件StepDialogInterface的封裝。時序圖以下:
圖 2‑10 雙擊編輯step時序圖
雙擊是TransGraph對象註冊的時間,雙擊是根據頁面上的座標信息獲取雙擊的stepmeta對象(來自於*.ktr)。而後,將這個對象傳給事件代理類處理,根據stepmeta對象,獲取對應的插件類名,經過反射生成StepDialogInterface的實例並調用open()方法。
Kettle插件之間天生就具備通訊共享數據的特色,kettle中最主要通訊方式是經過插件時間共同關聯一個數據類對象的方式進行通訊;使用單例模式實現插件間信息共享。
第一種方式還設計多線程同步的問題,在後面的章節中將會進行重點介紹。
Kettle並不能作到熱插拔,每次添加或者刪除插件的時候都須要重啓。安裝或刪除插件,只須要在plugins文件夾下添加或刪除對應的文件便可。
元數據主要包括轉換元數據(.ktr)和Job元數據(.kjb),元數據也能夠存儲在數據庫中,這裏咱們主要介紹文件存儲形式的。
元數據管理類包括TransMeta,該類定義了一個轉換(對應一個.ktr文件),提供了保存和加載該文件的方法;JobMeta類,一樣對應於一個工做(.kjb文件),提供保存和加載方法。StepMeta類保存的是Step的一些公共信息的類,每一個類的具體的元數據將保存在顯示了StepMetaInterface的類裏面。
兩個類中主要保存的信息以下:
代碼 1 TransMeta類主要屬性
1 private List<StepMeta> steps; 2 3 private List<TransHopMeta> hops; 4 5 private String name; 6 7 private Result previousResult;//上一個jobentry的執行結果。 8 9 private List<RowMetaAndData> ;//resultRows;此次trans執行後的數據結果。 10 11 private List<ResultFile> resultFiles;
steps字段對應於.ktr中的<step>節點,hops字段對應於<hop>節點。resultRows、previousResult其實是插件見的通訊類。
代碼 2 JobMeta類主要屬性
1 protected String name; 2 3 protected String filename; 4 5 public List<JobEntryInterface> jobentries;//保存jobentry列表 6 7 public List<JobHopMeta> jobhops;//保存jobentries之間的連接關係。 8 9 public List<DatabaseMeta> databases;
圖 3‑1 TransGraph類與顯示
選中轉換標籤後,紅框內的編輯區對象對應org.pentaho.di.ui.spoon.trans包中的TransGraph類。
圖 3‑2 JobGraph與顯示
選中Job標籤後,紅框內的編輯區對象對應org.pentaho.di.ui.spoon.job包中的JobGraph類。
Trans類負責轉換執行相關的全部任務,包括轉換加載、相關插件的實例化、初始化、運行、監視轉換執行,並把內容放置到TransInfo類中。
Step初始化線程包裝類,使用多線程,調用全部StepInterface實現類的Init函數。
把插件的主要實現類所有存儲在這個類中,方便集中調用。
1 public class StepMetaDataCombi 2 3 { 4 5 public StepMeta stepMeta; 6 7 public String stepname; 8 9 public int copy; 10 11 public StepInterface step; 12 13 public StepMetaInterface meta; 14 15 public StepDataInterface data; 16 17 }
步驟處理線程包裝類,這個類可以處理異常並將其記錄到日誌中。同時,也可以在異常發生或者執行結束後,記錄相關內容、關閉相關資源。
Job的執行類,自己實現了Thread是一個單獨的線程。Job entry能夠是單獨的線程,也能夠是順序執行,大多數狀況都是順序執行下一步以上一步的執行結果爲基礎。Job類也包括轉換加載、相關插件的實例化、初始化、運行、監視Job執行。