已閱讀5頁,還剩39頁未讀, 繼續免費閱讀
版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
關于本教程OSGi 是目前動態模塊系統的事實上的工業標準,雖然一開始只是作為嵌入式設備和家庭網關的框架來使用,但是實際上它適用于任何需要模塊化、面向服務、面向組件的應用程序。而 Equinox 則是的 Eclipse 所使用的 OSGi 框架,是 Eclipse 強大的插件體系的基礎,Eclipse 的穩定可靠性也為該框架帶來了聲譽。本教程就將演示如何在 Eclipse 環境下利用 Equinox 框架進行 OSGi 應用開發。首先解釋了實現上述應用程序所必需了解的基本概念和基礎知識,并結合示例代碼演示 OSGi 開發的一些重要技術,最后探討了基于 OSGi 應用程序一般所采用的架構,以及如何將 Equinox OSGi 應用程序脫離 Eclipse 而部署為一個標準的 Java 應用程序。目標在本教程中,您將學習: OSGi 及框架簡介 編寫第一個 OSGi 應用程序 重要的理論知識 開發一個真實的 OSGi 應用程序 探討 OSGi 應用架構 部署 OSGi 應用程序先決條件本教程假設讀者熟悉基本 Java 語言以及 Eclipse 開發環境的使用。系統需求本教程假設您有一個可以工作的 Eclipse 3.x 環境。如果還沒有,請在 Eclipse 網站 上找到相關下載的鏈接,以幫助您在自己的系統上操作示例步驟以及運行示例代碼。OSGi 及框架簡介OSGi 簡介OSGi 是目前動態模塊系統的事實上的工業標準,雖然一開始只是作為嵌入式設備和家庭網關的框架來使用,但是實際上它適用于任何需要模塊化、面向服務、面向組件的應用程序。目前 OSGi 規范已經發展到第四版(R4), 由 OSGi 聯合組織(OSGi Alliance)負責進行維護管理,相關的規范資料也可以從該網站獲得。(參考資料)OSGi 框架開發基于 OSGi 的應用程序離不開實現了 OSGi 標準的框架,就好比是基于 J2EE 的開發離不開應用服務器一樣。目前比較流行的基于 OSGi R4 標準實現的 OSGi 框架有三個:1. Equinox:這是大名鼎鼎的 Eclipse 所使用的 OSGi 框架,Eclipse 強大的插件體系就是構建在 OSGi bundles 的基礎之上,Eclipse 的穩定可靠性為該框架帶來了聲譽,而且由于有 IBM 公司的強力支持,其后續的開發和文檔資料也有了一定的保障。一般情況下,我們推薦您使用該框架進行 OSGi 開發。本教程的后續部分也將演示如何使用 Equinox 框架來進行 OSGi 應用程序的開發。2. Makewave Knopflerfish:這是另外一個比較知名的 OSGi 框架,目前的版本已經支持 R4 規范,其特點在于為應用程序的開發提供了大量的 bundle 。3. Apache Flex:由 Apache 基金組織開發的面向社區的 OSGi 框架實現,提供了標準的服務和一些有趣的和 OSGi 相關的服務實現。Hello World!編寫第一個 OSGi 應用程序準備工作1. 從附屬資料中下載 Eclipse 3.x 版本,Eclipse 3.2+ 版本已經全面支持 OSGi R4 規范。目前最佳實踐是下載 Eclipse 3.3.2 版本。(下載請見:參考資料)2. 將 Eclipse 解壓縮到 d:workseclipse 目錄,開始我們的 OSGi 之旅。Hello World一般情況下,學習一門新的技術,程序員都習慣于首先開發一個 hello world 應用程序,這似乎也是一種“工業標準”。好的,讓我們開始吧,開發一個簡單的 OSGi 應用程序并不難,步驟如下:1. 建立一個 plug-in 工程,File New Project,選擇 Plug-in development Plug-in Project 圖 1. 新建 plug-in 工程2. 在建立工程的第一個向導,填入工程的名稱:osgi.test.helloworld,使用缺省的工程路徑。注意目標平臺的選擇,由于我們的項目是一個通用的 OSGi bundle,所以選擇 equinox 。 圖 2. 填入工程名及選擇目標平臺3. 在下一個向導界面中,填入需要的一些插件信息(注意 Eclipse 中的插件概念基本類似于 OSGi 中的 bundle 的概念),這里需要填入的是 OSGi 的 provider(供應商)和 classpath 。如果沒有特別的設計,一般可以忽略這兩個字段 。最后是關于 activator 的部分,如果不是一個 fragment bundle 則需要填入,除非您的 bundle 自己實現框架的事件監聽,這個似乎也沒有必要。因此,建議使用缺省的設置,如圖 3:圖 3. 使用缺省設置Activator:這是 bundle 啟動時首先調用的程序入口,相當于 Java 模塊中的 main 函數。不同的是,main 需要通過命令行調用,而 OSGi 的 Activator 是被動的接受 OSGi 框架的調用,收到消息后才開始啟動。最佳實踐:不要在 Activator 中寫太多的啟動代碼,否則會影響 bundle 啟動速度,相關的服務啟動可以放到服務的監聽器中。4. 最后一步,不使用任何的模板,所以勾掉缺省的選項,點擊完成,如圖 4: 圖 4. 勾掉缺省的選項5. 完成,基本的插件視圖如圖 5,Eclipse 會在工程名下建立相同路徑的 Java Package,其中包含了 Activator 類,插件的配置信息也都放在 MANIFEST.MF 文件中,將來我們相當多的工作都是在其中完成。 圖 5. 基本的插件視圖6. 編輯 Activator.java,輸入 hello world 語句,代碼如下: 清單 1. 編輯 Activator.javapackage osgi.test.helloworld; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class Activator implements BundleActivator /* * (non-Javadoc) * see org.osgi.framework.BundleActivator * #start(org.osgi.framework.BundleContext) */ public void start(BundleContext context) throws Exception System.out.println(hello world); /* * (non-Javadoc) * see org.osgi.framework.BundleActivator * #stop(org.osgi.framework.BundleContext) */ public void stop(BundleContext context) throws Exception 7.8. 我們可以看到每個 Activator 實際都是實現了 BundleActivator 接口,此接口使 Activator 能夠接受框架的調用。在框架啟動后,啟動每個 bundle 的時候都會調用每個 bundle 的 Activator 。9. 注意:bundle 的 Activator 必須含有無參數構造函數,這樣框架才能使用 Class.newInstance() 方式反射構造 bundle 的 Activator 實例。10. 這里我們在 start 方法中填入了我們希望輸出的 hello world 字符串。那么,怎么才能啟動這個 bundle 呢?11. 執行:選擇 Run Open Run Dialog,進入運行菜單,在 OSGi framework 中右鍵點擊選擇 new 一個新的 OSGi 運行環境,如圖: 圖 6. 新建 OSGi 運行環境在右邊的運行環境對話框中,輸入運行環境的名字、start level 和依賴的插件,由于我們目前不需要其它的第三方插件,因此只需要勾上系統的 org.eclipse.osgi 插件,如果不選擇此插件,hello world 將無法運行。如圖 7,只有當您點擊了 validate bundles 按鈕 ,并且提示無問題之后,才表明您的運行環境基本 OK 了。圖 7. 選擇 org.eclipse.osgi插件依賴插件的選擇:圖 8. 依賴插件的選擇好的,如果您的運行環境已經 OK,那么就點擊 Run 吧。圖 9. 運行 OSGi 項目恭喜您,成功了!OSGi 控制臺OSGi 控制臺對于習慣開發普通 Java 應用程序的開發人員來說,還是比較新鮮的。一般來說,通過 OSGi 控制臺,您可以對系統中所有的 bundle 進行生命周期的管理,另外也可以查看系統環境,啟動、停止整個框架,設置啟動級別等等操作。如圖 10,鍵入 SS 就可以查看所有 bundle 的狀態:圖 10. 查看所有 bundle 的狀態下面列出了主要的控制臺命令:表 1. Equinox OSGi 主要的控制臺命令表類別 命令 含義 控制框架launch 啟動框架shutdown 停止框架close 關閉、退出框架exit 立即退出,相當于 System.exitinit 卸載所有 bundle(前提是已經 shutdown)setprop 設置屬性,在運行時進行控制 bundleInstall 安裝uninstall 卸載Start 啟動Stop 停止Refresh 刷新Update 更新展示狀態Status 展示安裝的 bundle 和注冊的服務Ss 展示所有 bundle 的簡單狀態Services 展示注冊服務的詳細信息Packages 展示導入、導出包的狀態Bundles 展示所有已經安裝的 bundles 的狀態Headers 展示 bundles 的頭信息,即 MANIFEST.MF 中的內容Log 展示 LOG 入口信息其它Exec 在另外一個進程中執行一個命令(阻塞狀態)Fork 和 EXEC 不同的是不會引起阻塞Gc 促使垃圾回收Getprop 得到屬性,或者某個屬性控制啟動級別Sl 得到某個 bundle 或者整個框架的 start level 信息Setfwsl 設置框架的 start levelSetbsl 設置 bundle 的 start levelsetibsl 設置初始化 bundle 的 start levelMANIFEST.MFMANIFEST.MF 可能出現在任何包括主類信息的 Jar 包中,一般位于 META-INF 目錄中,所以此文件并不是一個 OSGi 特有的東西,而僅僅是增加了一些屬性,這樣也正好保持了 OSGi 環境和普通 Java 環境的一致性,便于在老的系統中部署。表 2 列出此文件中的重要屬性及其含義:表 2. MANIFEST.MF 文件屬性屬性名字 含義 Bundle-Activator Bundle 的啟動器Bundle-SymbolicName 名稱,一般使用類似于 JAVA 包路徑的名字命名Bundle-Version 版本,注意不同版本的同名 bundle 可以同時上線部署Export-Package 導出的 package 聲明,其它的 bundle 可以直接引用Import-Package 導入的 packageEclipse-LazyStart 是否只有當被引用了才啟動Require-Bundle 全依賴的 bundle,不推薦Bundle-ClassPath 本 bundle 的 class path,可以包含其它一些資源路徑Bundle-RequiredExecutionEnvironment 本 bundle 必須的執行環境,例如 jdk 版本聲明重要的理論知識好的,剛才我們已經從頭到尾開發了一個基于 Equinox 框架的 Hello world 應用程序。我們發現似乎并不是很困難,很多工作 Eclipse 已經幫我們做好了,例如 Activator 代碼框架和 MANIFEST.MF 文件,我們也學會了如何控制 OSGi 的控制臺和編寫 MANIFEST.MF 文件,但是,您真的明白它們是如何運行的么?下面我們將重點介紹一些 OSGi 運行必備的基礎知識。什么是 bundle?我們已經看到,編寫一個很普通的 Hello world 應用,必須首先創建一個 plug-in 工程,然后編輯其 Activator 類的 start 方法,實際我們這樣做的本質是為 OSGi 運行環境添加了一個 bundle,那么一個 bundle 必須的構成元素是哪些呢?1. MANIFEST.MF:描述了 bundle 的所有特征,包括名字、輸出的類或者包,導入的類或者包,版本號等等,具體可以參考 表 2. MANIFEST.MF 文件屬性。 2. 代碼:包括 Activator 類和其它一些接口以及實現,這個和普通的 Java 應用程序沒有什么特殊的區別。3. 資源:當然,一個應用程序不可能沒有資源文件,比如圖片、properties 文件、XML 文件等等,這些資源可以隨 bundle 一起存在,也可以以 fragment bundle 的方式加入。4. 啟動級別的定義:可以在啟動前使用命令行參數指定,也可以在運行中指定,具體的 start level 的解釋,請參考 后面的說明。 框架做了些什么?好了,我們已經明白 bundle 是什么了,也知道如何開發一個基本的 bundle 了,那么我們還必須要明白,我的 bundle 放在 Equinox 框架中,它對我們的 bundle 做了些什么?圖 11. Equinox 框架架構實際上,目標平臺已經為我們準備了 N 個 bundle,它們提供各種各樣的服務,OSGi 中,這些 bundle 的名字叫 system bundle,就好比精裝修的房子,您只需要拎包入住,不再需要自己鋪地板,裝吊頂了。我們的 bundle 進入 Equinox 環境后,OSGi 框架對其做的事情如下:1. 讀入 bundle 的 headers 信息,即 MANIFEST.MF 文件;2. 裝載相關的類和資源;3. 解析依賴的包;4. 調用其 Activator 的 start 方法,啟動它;5. 為其提供框架事件、服務事件等服務;6. 調用其 Activator 的 stop 方法,停止它;Bundle 的狀態變更OK, 現在我們大概明白了一個 bundle 的定義和其在 OSGi 框架中的生命周期,前面我們看到控制臺可以通過 ss 命令查看所有裝載的 bundle 的狀態,那么 bundle 到底具有哪些狀態,這些狀態之間是如何變換呢?我們知道了這些狀態信息,對我們有何益處?首先,了解一下一個 bundle 到底有哪些狀態:表 3. Bundle 狀態表狀態名字 含義 INSTALLED 就是字面意思,表示這個 bundle 已經被成功的安裝了RESOLVED 很常見的一個狀態,表示這個 bundle 已經成功的被解析(即所有依賴的類、資源都找到了),通常出現在啟動前或者停止后STARTING 字面意思,正在啟動,但是還沒有返回,所以您的 Activator 不要搞的太復雜ACTIVE 活動的,這是我們最希望看到的狀態,通常表示這個 bundle 已經啟動成功,但是不意味著您的 bundle 提供的服務也是 OK 的STOPPING 字面意思,正在停止,還沒有返回UNINSTALLED 卸載了,狀態不能再發生變更了下面請看一張經典的 OSGi bundle 變更狀態的圖:圖 12. OSGi bundle 變更狀態圖Bundle 導入導出 packageOK,到現在為止,似乎一切都是新鮮的,但是您似乎在考慮,OSGi 到底有什么優勢,下面介紹一下其中的一個特點,幾乎所有的面向組件的框架都需要這一點來實現其目的: 面向服務、封裝實現 。這一點在普通的 Java 應用是很難做到的,所有的類都暴露在 classpath 中,人們可以隨意的查看您的實現,甚至變更您的實現。這一點,對于希望發布組件的公司來說是致命的。圖 13. OSGi bundle 原理OSGi 很好的解決了這個問題,就像上面的圖顯示的,每個 bundle 都可以有自己公共的部分和隱藏的部分,每個 bundle 也只能看見自己的公共部分、隱藏部分和其它 bundle 的公共部分。bundle 的 MANIFEST.MF 文件提供了 EXPORT/IMPORT package 的關鍵字,這樣您可以僅僅 export 出您希望別人看到的包,而隱藏實現的包。并且您可以為它們編上版本號,這樣可以同時發布不同版本的包。Bundle class path這一點比較難理解,一般情況下您不需要關心這個事情,除非事情出現了問題,您發現明明這個類就在這里,怎么就是報告 ClassNotFoundException/NoClassDefExcpetion 呢?在您垂頭喪氣、準備砸掉電腦顯示器之前,請看一下 bundle 中的類是如何查找的:1. 首先,它會找 JRE,這個很明顯,這個實際是通過系統環境的 JAVA_HOME 中找到的,路徑一般是 JAVA_HOME/lib/rt.jar、tools.jar 和 ext 目錄,endorsed 目錄。2. 其次,它會找 system bundle 導出的包。3. 然后,它會找您的 import 的包,這個實際包含兩種:一種是直接通過 require-bundle 的方式全部導入的,還有一種就是前面講的通過 import package 方式導入的包。4. 查找它的 fragment bundle,如果有的話。5. 如果還沒有找到,則會找自己的 classpath 路徑(每個 bundle 都有自己的類路徑)。6. 最后它會嘗試根據 DynamicImport-Package 屬性查找的引用。啟動級別 Start level在 Equinox 環境中,我們在配置 hello world 應用的時候,看到我們將 framework start level 保持為 4,將 Hello world bundle 的 start level 設置為 5 。 start level 越大,表示啟動的順序越靠后。在實際的應用環境中,我們的 bundle 互相有一定的依賴關系,所以在啟動的順序上要有所區別,好比蓋樓,要從打地基開始。實際上,OSGi 框架最初的 start level 是 0,啟動順序如下:1. 將啟動級別加一,如果發現有匹配的 bundle(即 bundle 的啟動級別和目前的啟動級別相等),則啟動這個 bundle;2. 繼續第一步,直到發現已經啟動了所有的 bundle,且活動啟動級別和最后的啟動的 bundle 啟動級別相同。停止順序,也是首先將系統的 start level 設置為 0:1. 由于系統當前活動啟動級別大于請求的 start level,所以系統首先停止等于當前活動啟動級別的 bundle;2. 將活動啟動級別減一,繼續第一步,直到發現活動啟動級別和請求級別相等,都是 0。開發一個真實的 OSGi 應用程序我們不能只停留在 hello world 的層面,雖然那曾經對我們很重要 ,但是現實需要我們能夠使用 OSGi 寫出激動人心的應用程序,它能夠被客戶接受,被架構師認可,被程序員肯定。好的,那我們開始吧。下面將會著重介紹一些現實的應用程序可能需要的一些 OSGi 應用場景。發布和使用服務由于 OSGi 框架能夠方便的隱藏實現類,所以對外提供接口是很自然的事情,OSGi 框架提供了服務的注冊和查詢功能。好的,那么我們實際操作一下,就在 Hello world 工程的基礎上進行。我們需要進行下列的步驟:1. 定義一個服務接口,并且 export 出去供其它 bundle 使用;2. 定義一個缺省的服務實現,并且隱藏它的實現;3. Bundle 啟動后,需要將服務注冊到 Equinox 框架;4. 從框架查詢這個服務,并且測試可用性。好的,為了達到上述要求,我們實際操作如下:1. 定義一個新的包 osgi.test.helloworld.service ,用來存放接口。單獨一個 package 的好處是,您可以僅僅 export 這個 package 給其它 bundle 而隱藏所有的實現類2. 在上述的包中新建接口 IHello,提供一個簡單的字符串服務,代碼如下: 清單 2. IHellopackage osgi.test.helloworld.service; public interface IHello /* * 得到 hello 信息的接口 . * return the hello string. */ String getHello(); 3.4. 再新建一個新的包 osgi.test.helloworld.impl,用來存放實現類。5. 在上述包中新建 DefaultHelloServiceImpl 類,實現上述接口: 清單 3. IHello 接口實現public class DefaultHelloServiceImpl implements IHello Override public String getHello() return Hello osgi,service; 6.7. 注冊服務,OSGi 框架提供了兩種注冊方式,都是通過 BundleContext 類實現的: a. registerService(String,Object,Dictionary) 注冊服務對象 object 到接口名 String 下,可以攜帶一個屬性字典 Dictionary;b. registerService(String,Object,Dictionary) 注冊服務對象 object 到接口名數組 String 下,可以攜帶一個屬性字典 Dictionary,即一個服務對象可以按照多個接口名字注冊,因為類可以實現多個接口;我們使用第一種注冊方式,修改 Activator 類的 start 方法,加入注冊代碼:清單 4. 加入注冊代碼public void start(BundleContext context) throws Exception System.out.println(hello world); context.registerService( IHello.class.getName(), new DefaultHelloServiceImpl(), null); 8. 為了讓我們的服務能夠被其它 bundle 使用,必須在 MANIFEST.MF 中對其進行導出聲明,雙擊 MANIFEST.MF,找到 runtime exported packages 點擊 add,如圖,選擇 service 包即可: 圖 14. 選擇導出的服務包9. 另外新建一個類似于 hello world 的 bundle 叫:osgi.test.helloworld2,用于測試 osgi.test.helloworld bundle 提供的服務的可用性;10. 添加 import package:在第二個 bundle 的 MANIFEST.MF 文件中,找到 dependencies Imported packages Add ,選擇我們剛才 export 出去的 osgi.test.helloworld.service 包: 圖 15. 選擇剛才 export 出去的 osgi.test.helloworld.service 包11. 查詢服務:同樣,OSGi 框架提供了兩種查詢服務的引用 ServiceReference 的方法: a. getServiceReference(String):根據接口的名字得到服務的引用;b. getServiceReferences(String,String):根據接口名和另外一個過濾器名字對應的過濾器得到服務的引用;12. 這里我們使用第一種查詢的方法,在 osgi.test.helloworld2 bundle 的 Activator 的 start 方法加入查詢和測試語句: 清單 5. 加入查詢和測試語句public void start(BundleContext context) throws Exception System.out.println(hello world2); /* * Test hello service from bundle1. */ IHello hello1 = (IHello) context.getService( context.getServiceReference(IHello.class.getName(); System.out.println(hello1.getHello(); 13. 修改運行環境,因為我們增加了一個 bundle,所以說也需要在運行配置中加入對新的 bundle 的配置信息,如下圖所示: 圖 16. 加入對新的 bundle 的配置信息14. 執行,得到下列結果: 圖 17. 執行結果恭喜您,成功了!使用事件管理服務 EventAdmin前面講過,OSGi 規范定義了很多可用的 bundle,您盡管使用它們完成您的工作,而不必另外再發明輪子,OSGi 框架定義的事件管理服務,類似于 JMS,但是使用上比 JMS 簡單。OSGi 整個框架都離不開這個服務 ,因為框架里面全都依靠事件機制進行通信,例如 bundle 的啟動、停止,框架的啟動、停止,服務的注冊、注銷等等等等都是會發布事件給監聽者,同時也在監聽其它模塊發來的自己關心的事件。 OSGi 框架的事件機制主要核心思想是:1. 用戶(程序員)可以自己按照接口定義自己的事件類型2. 用戶可以監聽自己關心的事件或者所有事件3. 用戶可以將事件同步的或者異步的提交給框架,由框架負責同步的或者異步的分發給監聽者說明:框架提供的事件服務、事件提供者、事件監聽者之間的關系如下:圖 18. 事件服務、事件提供者、事件監聽者之間的關系事件提供者 Publisher 可以獲取 EventAdmin 服務,通過 sendEvent 同步(postEvent 異步)方式提交事件,EventAdmin 服務負責分發給相關的監聽者 EventHandler,調用它們的 handleEvent 方法。這里要介紹一個新的概念 Topics,其實在 JMS 里面也有用,也就是說一個事件一般都有一個主題,這樣我們的事件接收者才能按照一定的主題進行過濾處理,例如只處理自己關心的主題的事件,一般情況下主題是用類似于 Java Package 的命名方式命名的。同步提交(sendEvent)和異步提交(postEvent) 事件的區別是,同步事件提交后,等框架分發事件給所有事件接收者之后才返回給事件提交者,而異步事件則一經提交就返回了,分發在另外的線程進行處理。下面的程序演示了事件的定義、事件的發布、事件處理,同時還演示了同步和異步處理的效果,以及運行環境的配置。(約定 osgi.test.helloworld 為 bundle1,osgi.test.helloworld2 為 bundle2)圖 19. 同步和異步處理演示1. 在 bundle1 中的 MANIFEST.MF 的 dependency 頁面中定義引入新的包:org.osgi.service.event。2. 在 bundle1 中的 osgi.test.helloworld.event 包中定義新的類 MyEvent,如下(注意其中的 topic 定義的命名方式): 清單 6. 定義新的類 MyEventimport java.util.Dictionary;import org.osgi.service.event.Event;public class MyEvent extends Event public static final String MY_TOPIC = osgi/test/helloworld/MyEvent; public MyEvent(String arg0, Dictionary arg1) super(MY_TOPIC, arg1); public MyEvent() super(MY_TOPIC, null); public String toString() return MyEvent; 3.4. 在 bundle1 的 DefaultHelloServiceHandler 類的 getHello 方法中,加入提交事件的部分,這樣 bundle2 在調用這個服務的時候,將觸發一個事件,由于采用了 Post 方式,應該是立刻返回的,所以在 postEvent 前后打印了語句進行驗證。 清單 7. getHello 方法import org.osgi.framework.BundleContext;import org.osgi.framework.ServiceReference;import org.osgi.service.event.EventAdmin;Override public String getHello() /post a event ServiceReference ref = context.getServiceReference(EventAdmin.class.getName(); if(ref!=null) eventAdmin = (EventAdmin)context.getService(ref); if(eventAdmin!=null) System.out.println(post event started); eventAdmin.postEvent(new MyEvent(); System.out.println(post event returned); return Hello osgi,service; 5.6. 定義監聽者,在 bundle2 中,也引入 osgi 的事件包,然后定義一個新的類:MyEventHandler 類,用來處理事件,這里故意加入了一個延遲,是為了測試異步事件的調用,實現如下: 清單 8. MyEventHandler 類import org.osgi.service.event.Event;import org.osgi.service.event.EventHandler;public class MyEventHandler implements EventHandler Override public void handleEvent(Event event) System.out.println(handle event started-+event); try Thread.currentThread().sleep(5*1000); catch (InterruptedException e) System.out.println(handle event ok-+event); 7.8. 注冊監聽器,有了事件處理器,還需要注冊到監聽器中,這里在 bundle2 的 Activator 類中加入此監聽器,也就是調用 context.registerService 方法注冊這個監聽服務,和普通服務的區別是要帶一個監聽事件類型的 topic,這里列出 Activator 類的 start 方法: 清單 9. start 方法import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry;import java.util.Hashtable;import org.osgi.framework.BundleActivator;import org.osgi.framework.BundleContext;import org.osgi.service.event.EventConstants;import org.osgi.service.event.EventHandler;import osgi.test.helloworld.event.MyEvent;import osgi.test.helloworld.service.IAppService;import osgi.test.helloworld.service.IHello;public void start(BundleContext context) throws Exception System.out.println(hello world2); /* * 添加事件處理器 . */ String topics = new String MyEvent.MY_TOPIC; Hashtable ht = new Hashtable(); ht.put(EventConstants.EVENT_TOPIC, topics); EventHandler myHandler = new MyEventHandler(); context.registerService( EventHandler.class.getName(), myHandler, ht); System.out.println(event handler registered); /* * Test hello service from bundle1. */ IHello hello1 = (IHello) context.getService( context.getServiceReference(IHello.class.getName(); System.out.println(hello1.getHello(); 9.10. 為了使用框架的事件服務,需要修改運行環境,加入兩個系統 bundle,分別是: a. org.eclipse.osgi.services b. org.eclipse.equinox.event 11. 好了一切準備好了,執行: 圖 20. 執行可以看到,post 事件后,不等事件真的被處理完成,就返回了,事件處理在另外的線程執行,最后才打印處理完成的語句。然后 ss 看一下,目前我們已經有五個 bundle 在運行了:圖 21. ss 查詢12. OK,修改代碼以測試同步調用的情況,我們只需要把提交事件的代碼由 postEvent 修改為 sendEvent 即可。其它不變,測試結果如下: 圖 22. 同步調用測試結果使用 Http 服務 HttpServiceOSGi 的 HTTP 服務為我們提供了展示 OSGi 的另外一個途徑,即我們可以專門提供一個 bundle 用來作為我們應用的 UI,當然這個還比較簡單,只能提供基本的 HTML 服務和基本的 Servlet 服務。如果想提供復雜的 Jsp/Struts/WebWorks 等等,或者想用現有的 Web 中間件服務器例如 Tomcat/Resin/WebSphere Application Server 等,都需要另外的途徑來實現,目前我提供一些基本的使用 HTTP 服務的方式。要使用 HTTP 服務,必然有三個步驟1. 獲取 HttpService,可以像 上述方式 那樣通過 context 的 getService 方法獲得引用;2. 使用 HttpService 的引用注冊資源或者注冊 Servlet: a. registerResources:注冊資源,提供本地路徑、虛擬訪問路徑和相關屬性即可完成注冊,客戶可以通過虛擬訪問路徑 + 資源名稱訪問到資源b. registerServlet:注冊 Servlet,提供標準 Servlet 實例、虛擬訪問路徑、相關屬性以及 HttpContext(可以為 null)后即可完成注冊,客戶可以直接通過虛擬訪問路徑獲取該 Servlet 的訪問3. 修改運行環境,加入支持 http 服務的 bundle那么,接下來我們實際操作一下:1. 首先,在 bundle1 的 src 中建立一個新的 package,名字叫 pages,用來存放一些 HTML 的資源文件,為了提供一個基本的 HTTP 服務,我們需要提供一個 index.html,內容如下: hello osgi http service2.3. 第二步,注冊資源服務,首先我們要為 bundle1 加入 HTTP 服務的 package 引用,即修改 MANIFEST.MF 文件的 dependencies,加入包:org.osgi.service.http;version=1.2.0,然后在 Activator 類的 start 方法中加入 HTTP 資源的注冊: 清單 10. 加入 HTTP 資源的注冊代碼httpService = (HttpService)context.getService (context.getServiceReference(HttpService.class.getName(); httpService.registerResources(/, /pages, null);4. 修改運行環境,在 target platform 的 bundle 列表中加入:org.eclipse.equinox.http 和 javax.servlet 這兩個 bundle 保證了 HttpService 的可用性: 圖 23. 加入 HttpService bundle5. 運行,然后打開 IE 訪問本機 http:/localhost/index.html: 圖 24. 運行結果6. 加入 servlet,首先在 bundle1 建立一個包:osgi.test.hellworld.servlet,建立一個新的類:MyServlet,要從 HttpServle
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 721模型職業發展規劃
- 兒童霧化康復指導
- 健康宣教活動照片怎么拍
- 煉乳結晶工崗前沖突解決考核試卷含答案
- 裝配工職業規劃方案
- 畢節消防安全云平臺
- 采購員安全生產基礎知識考核試卷含答案
- 印染助劑生產工工藝分析競賽考核試卷含答案
- 裂解汽油加氫裝置操作工持續改進測試考核試卷含答案
- 家用音頻產品維修工誠信考核試卷含答案
- GB/T 47067-2026塑料模塑件公差和驗收條件
- (2025年)市場監管法律知識復習試題考前模擬測試題附答案
- 新疆建設工程消防設計審查、驗收常見問題技術解析(2024年)
- 2026年國家公務員考試題庫500道附答案(綜合卷)
- 財稅培訓課件 接收虛開
- 資料室圖紙檔案管理制度
- 《DLT 1231-2018電力系統穩定器整定試驗導則》專題研究報告深度
- 2025元時空智能科技多崗位招聘15人筆試歷年難易錯考點試卷帶答案解析2套試卷
- 2025ACC心源性休克的評價和管理解讀
- VTE預防護理管理
- 包裝銷售話術
評論
0/150
提交評論