基于 OSGi 的面向服务的组件编程
一. OSGi 簡(jiǎn)史
OSGi 是由 1999 年成立的 OSGi 聯(lián)盟提出的一個(gè)開(kāi)放的服務(wù)規(guī)范,最初的目的是為嵌入式設(shè)備,確切地說(shuō)是為可以通過(guò)網(wǎng)絡(luò)訪問(wèn)的設(shè)備提供一個(gè)通用的軟件運(yùn)行平臺(tái),屏蔽不同設(shè)備之間的硬件和操作系統(tǒng)差異,使軟件可以動(dòng)態(tài)地部署和更新。后來(lái) Eclipse 組織注意到了 OSGi 的優(yōu)點(diǎn),決定將 Eclipse3.0 及后續(xù)版本的插件體系結(jié)構(gòu)基于 OSGi 來(lái)實(shí)現(xiàn),并專門(mén)成立了一個(gè)子項(xiàng)目 Equinox 來(lái)實(shí)現(xiàn) OSGi R4 規(guī)范,把 Equinox 作為 Eclipse 的底層運(yùn)行平臺(tái)。Eclipse 組織的這一決定帶來(lái)了雙贏的局面,今天的 Eclipse 由于其出色的可擴(kuò)展的體系結(jié)構(gòu),已經(jīng)不再是一個(gè)單純的 Java IDE,而是一個(gè)開(kāi)放的開(kāi)發(fā)平臺(tái),一個(gè)通用的可擴(kuò)展的軟件框架,OSGi 也不再局限于嵌入式領(lǐng)域,而是成為了一個(gè)通用的動(dòng)態(tài)組件開(kāi)發(fā)環(huán)境,在桌面,服務(wù)器端等領(lǐng)域得到了大量應(yīng)用。
對(duì)模塊化的支持是 Java 的一個(gè)重要的發(fā)展方向,目前 Java 的模塊化標(biāo)準(zhǔn)還存在著JSR 277:Java Module Systems 和 JSR 291:Dynamic Component Support for Java 之爭(zhēng)論,其中JSR291 的主要目的就要將 OSGi 引入到 Java 標(biāo)準(zhǔn)中去,JSR277 則是 SUN 發(fā)起的一個(gè)Java 模塊化標(biāo)準(zhǔn)。但 OSGi 事實(shí)上已經(jīng)得到了許多國(guó)際IT大企業(yè)的支持,并且已經(jīng)有許多商業(yè)軟件產(chǎn)品基于 OSGi 來(lái)開(kāi)發(fā),如 IBM 包括 Websphere Application Server(WAS), Rational Software Architecture(RSA) 在內(nèi)的許多重量級(jí)軟件產(chǎn)品均已基于 OSGi 來(lái)實(shí)現(xiàn),著名的 IoC 框架 Spring 正在整合 OSGi 技術(shù),現(xiàn)在基于 Eclipse 開(kāi)發(fā) RCP,插件程序也非常流行,可以預(yù)見(jiàn)基于OSGi 的 Java 應(yīng)用程序?qū)?huì)越來(lái)越多,也將會(huì)有越來(lái)越多的軟件開(kāi)發(fā)組織改變其軟件設(shè)計(jì)思想和開(kāi)發(fā)方式,擁抱 OSGi 并開(kāi)始享受 OSGi 帶來(lái)的好處。
二. 使用 Eclipse 開(kāi)發(fā) OSGi 應(yīng)用
本文假設(shè)讀者已經(jīng)了解 OSGi 編程的基本概念以及如何在 Eclipse 環(huán)境中來(lái)開(kāi)發(fā)OSGi Bundle。如果您還不了解這些知識(shí),可以先閱讀相關(guān)資料如:?http://www.eclipse.org/equinox網(wǎng)站以及 developerworks 網(wǎng)站上的文章:?利用 Eclipse 開(kāi)發(fā)基于 OSGi 的 Bundle 應(yīng)用
Eclipse 開(kāi)發(fā)平臺(tái)中對(duì)基于 OSGi 開(kāi)發(fā)應(yīng)用程序已經(jīng)提供了較為完善的支持,在 Eclipse 集成開(kāi)發(fā)環(huán)境中可以輕松地完成對(duì)一個(gè)或多個(gè) bundle 的開(kāi)發(fā)、調(diào)試、部署、測(cè)試等工作。本文將基于 Equinox OSGi 框架,使用 Eclipse 開(kāi)發(fā)平臺(tái)來(lái)開(kāi)發(fā)一個(gè)示例性的系統(tǒng)管理程序,主要目的是給讀者演示基于 OSGi 開(kāi)發(fā)一個(gè)應(yīng)用程序的過(guò)程并讓讀者體會(huì)基于OSGi 編程帶來(lái)的模塊化,動(dòng)態(tài)性,擴(kuò)展性等優(yōu)點(diǎn)。為了便于讀者理解,本文會(huì)盡可能的保持代碼簡(jiǎn)單易懂,本文中的代碼在 WindowsXP,Eclipse3.2,Sun JDK1.5 環(huán)境下測(cè)試通過(guò)。
三. 需求分析與模塊劃分
OSGi 帶來(lái)了規(guī)范化的模塊劃分,低耦合的模塊間關(guān)系,統(tǒng)一的模塊開(kāi)發(fā)方式,可動(dòng)態(tài)插拔的模塊管理環(huán)境。開(kāi)發(fā) OSGi 應(yīng)用程序的第一步是在需求分析的基礎(chǔ)上進(jìn)行精心的模塊劃分,模塊劃分的原則是盡量保持單個(gè)模塊的獨(dú)立性,使模塊與模塊之間的耦合降到最小,每一個(gè)模塊暴露給其它模塊的信息最少,盡量讓模塊之間使用 OSGi 框架提供的服務(wù)注冊(cè)機(jī)制來(lái)通信。一般可采用一個(gè)模塊一個(gè) Bundle 的方式,并為每一個(gè) Bundle 在 Eclipse 環(huán)境中建立一個(gè) Project 來(lái)進(jìn)行開(kāi)發(fā),由于模塊與模塊之間的耦合很小,各個(gè) Bundle 之間并不會(huì)象傳統(tǒng)的開(kāi)發(fā)方式中的各模塊之間那樣存在糾纏不清的包和類的引用關(guān)系,因此大部分Bundle的開(kāi)發(fā)工作可以并行進(jìn)行而不會(huì)互相影響。
本文實(shí)現(xiàn)的系統(tǒng)管理程序,可以提供一系列的系統(tǒng)管理服務(wù)來(lái)管理計(jì)算機(jī)內(nèi)的各類設(shè)備。為簡(jiǎn)便起見(jiàn),我們首先只實(shí)現(xiàn)一項(xiàng)管理服務(wù):Monitor,此項(xiàng)服務(wù)可以監(jiān)視計(jì)算機(jī)內(nèi)各類設(shè)備的運(yùn)行狀態(tài),我們可以將整個(gè)軟件劃分為如下的一些Bundle:
- Services Bundle:在OSGi中,服務(wù)是通過(guò)Java的接口來(lái)定義的,我們可以把定義服務(wù)的Java接口集中一個(gè)Services Bundle中,并由這個(gè)Bundle向其它Bundle提供接口。
- 服務(wù)提供者Bundle:實(shí)現(xiàn)Services Bundle提供的接口并向OSGi框架注冊(cè)服務(wù)。在本例中,我們要實(shí)現(xiàn)對(duì)各類設(shè)備的監(jiān)視,對(duì)于每一個(gè)需要監(jiān)視的設(shè)備,均可以實(shí)現(xiàn)一個(gè)單獨(dú)的服務(wù)提供者Bundle來(lái)提供相應(yīng)的監(jiān)視功能。
- 服務(wù)使用者Bundle:引用Services Bundle提供的接口向OSGi框架請(qǐng)求相應(yīng)的服務(wù),本例中主要實(shí)現(xiàn)一個(gè)服務(wù)使用者Bundle,它是一個(gè)控制臺(tái)程序,用于執(zhí)行相應(yīng)的系統(tǒng)管理服務(wù),并在控制臺(tái)中向用戶顯示相應(yīng)的系統(tǒng)管理信息。
整個(gè)程序是由OSGi框架以及運(yùn)行于OSGi框架內(nèi)的一批Bundles組成,Bundle之間的協(xié)作關(guān)系見(jiàn)下圖:
圖1 程序的總體架構(gòu)圖
四. 實(shí)現(xiàn)Bundle
1. 實(shí)現(xiàn)Services Bundle
新建一個(gè)Eclipse plugin-in project,將其命名為com.systemmanagement.services,注意創(chuàng)建OSGi Bundle工程時(shí),一定要選中“an OSGi framework”做為工程的目標(biāo)平臺(tái),并選擇Equinox或standard,這兩個(gè)選項(xiàng)的區(qū)別是:Equinox對(duì)OSGi 規(guī)范第4版進(jìn)行了一些擴(kuò)展,如果開(kāi)發(fā)出來(lái)的Bundle希望能夠在其它的OSGi實(shí)現(xiàn)框架如Oscar,Knopflerfish上順利運(yùn)行,此處最好選擇standard。這個(gè)Bundle的實(shí)現(xiàn)很簡(jiǎn)單,它無(wú)需實(shí)現(xiàn)BundleActivator類,只需定義一個(gè)接口即可:
代碼清單1: MonitorService.java
| 1 2 3 4 5 | package com.systemmanagement.services.monitor; ? public interface MonitorService { ??public String getMonitorMessage(); } |
同時(shí)勿忘在此Bundle的MANIFEST.MF文件中將相應(yīng)的package導(dǎo)出:
代碼清單2:MANIFEST.MF
| 1 2 3 4 5 6 7 8 | Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Services Plug-in Bundle-SymbolicName: com.systemmanagement.services Bundle-Version: 1.0.0 Bundle-Vendor: cyz Bundle-Localization: plugin Export-Package: com.systemmanagement.services.monitor |
如果將來(lái)需要擴(kuò)充新的系統(tǒng)管理服務(wù),需在此Bundle中增加新的接口并將其所屬的package在MANIFEST.MF文件中導(dǎo)出。
2. 實(shí)現(xiàn)服務(wù)提供者Bundle
新建一個(gè)Eclipse plugin-in project,將其命名為com.systemmanagement.cpumonitor,此Bundle負(fù)責(zé)監(jiān)視CPU,提供相應(yīng)的監(jiān)視信息,它需要實(shí)現(xiàn)services bundle提供的MonitorService接口,同時(shí)它需要向OSGi框架注冊(cè)服務(wù),因此首先需要在其MANIFEST.MF文件中導(dǎo)入相應(yīng)的包:
代碼清單3:MANIFEST.MF
| 1 2 3 4 5 6 7 8 9 | Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Cpumonitor Plug-in Bundle-SymbolicName: com.systemmanagement.cpumonitor Bundle-Version: 1.0.0 Bundle-Activator: com.systemmanagement.cpumonitor.CpuMonitorActivator Bundle-Vendor: cyz Bundle-Localization: plugin Import-Package: com.systemmanagement.services.monitor, org.osgi.framework;version="1.3.0" |
此Bundle的實(shí)現(xiàn)主要包括兩部分工作:一個(gè)實(shí)現(xiàn)MonitorService的類,用于提供CPU的監(jiān)視信息(如代碼清單4所示)。一個(gè)BundleActivator類用于在Bundle啟動(dòng)時(shí)向OSGi框架注冊(cè)服務(wù),在Bundle停止時(shí)將服務(wù)注銷(如代碼清單5所示)。
代碼清單4:CpuMonitor.java
| 1 2 3 4 5 6 7 8 | Package com.systemmanagement.cpumonitor.impl; import com.systemmanagement.services.monitor.MonitorService; ? public class CpuMonitor implements MonitorService { ??public String getMonitorMessage() { ????????return "CPU--溫度:40度,電壓:1.4v"; ??} } |
代碼清單4僅為演示之用途,在真正開(kāi)發(fā)應(yīng)用時(shí),可以在此處實(shí)現(xiàn)真實(shí)的CPU監(jiān)視功能,例如你可以使用Java的JNI機(jī)制來(lái)調(diào)用一些操作系統(tǒng)底層的或第三方的API獲得相關(guān)的CPU信息,這些技術(shù)與本文的主題OSGi關(guān)系不大,在此略過(guò)。
代碼清單5:CpuMonitorActivator.java
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | Package com.systemmanagement.cpumonitor; ? import java.util.Hashtable; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceRegistration; import com.systemmanagement.cpumonitor.impl.CpuMonitor; import com.systemmanagement.services.monitor.MonitorService; ? public class CpuMonitorActivator implements BundleActivator { ????private BundleContext context=null; ????private ServiceRegistration serviceRegistration=null; ????? ????public void start(BundleContext context) throws Exception { ????????this.context=context; ????????MonitorService monitor=new CpuMonitor(); ????????Properties properties = new Properties(); ????????properties.put("device", "cpu"); ????????serviceRegistration=this.context.registerService( ????????????MonitorService.class.getName(), monitor, properties);? ????} ? ????public void stop(BundleContext context) throws Exception { ????????serviceRegistration.unregister(); ????????context=null; ????} } |
代碼清單5中最重要的功能就是向OSGi框架注冊(cè)了一個(gè)Monitor服務(wù),注冊(cè)服務(wù)時(shí)使用了一個(gè)Properties容器,容器中的key-value對(duì)說(shuō)明了當(dāng)前這個(gè)Monitor服務(wù)針對(duì)的是CPU,利用這個(gè)Properties容器,服務(wù)使用者Bundle就能夠判斷一個(gè)Monitor服務(wù)所針對(duì)的具體設(shè)備是什么。
針對(duì)其它需監(jiān)視的設(shè)備如內(nèi)存,網(wǎng)卡,電源,風(fēng)扇等,我們可以分別實(shí)現(xiàn)一個(gè)Bundle來(lái)提供相應(yīng)的監(jiān)視服務(wù),其實(shí)現(xiàn)過(guò)程與com.systemmanagement.cpumonitor這個(gè)Bundle是完全類似的,在此不再贅述。
3. 實(shí)現(xiàn)服務(wù)使用者Bundle
新建一個(gè)Eclipse plugin-in project,將其命名為com.systemmanagement.console,此Bundle是一個(gè)控制臺(tái)程序,它通過(guò)調(diào)用其它服務(wù)提供者Bundle提供的系統(tǒng)管理服務(wù),向用戶提供系統(tǒng)管理信息。同樣首先需要在其MANIFEST.MF文件中導(dǎo)入相應(yīng)的包:
代碼清單6:MANIFEST.MF
| 1 2 3 4 5 6 7 8 9 | Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Console Plug-in Bundle-SymbolicName: com.systemmanagement.console Bundle-Version: 1.0.0 Bundle-Activator: com.systemmanagement.console.ConsoleActivator Bundle-Vendor: cyz Bundle-Localization: plugin Import-Package: com.systemmanagement.services.monitor, org.osgi.framework;version="1.3.0", org.osgi.util.tracker;version="1.3.1" |
代碼清單6中導(dǎo)入的包org.osgi.util.tracker是OSGi框架提供的監(jiān)視Bundle提供的服務(wù)是否可用的機(jī)制,下文將會(huì)詳述。
此Bundle的實(shí)現(xiàn)主要包括三部分工作:一個(gè)ServiceTracker類,用于監(jiān)視服務(wù)提供者Bundle注冊(cè)的各類系統(tǒng)管理服務(wù)是否可用,并根據(jù)服務(wù)是否可用,采取相應(yīng)的動(dòng)作(如代碼清單7所示)。一個(gè)控制臺(tái)線程類,用于執(zhí)行各類系統(tǒng)管理服務(wù)并向用戶提供相應(yīng)的信息(如代碼清單8所示)。一個(gè)BundleActivator類用于在Bundle啟動(dòng)時(shí)啟動(dòng)Service Tracker服務(wù)監(jiān)視系統(tǒng)管理服務(wù)是否可用,啟動(dòng)控制臺(tái)線程類開(kāi)始執(zhí)行各類系統(tǒng)管理服務(wù)并顯示信息,在Bundle停止時(shí)停止Service Tracker服務(wù)和控制臺(tái)線程類。(如代碼清單9所示)。
代碼清單7: MonitorServiceTracker.java
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package com.systemmanagement.console; ? import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.osgi.util.tracker.ServiceTrackerCustomizer; import com.systemmanagement.services.monitor.MonitorService; ? public class MonitorServiceTracker implements ServiceTrackerCustomizer { ??private ConsoleThread thread; ??private BundleContext bc; ??? ??public MonitorServiceTracker(BundleContext bc,ConsoleThread thread) { ????this.thread = thread; ????this.bc = bc; ??} ??public Object addingService(ServiceReference reference) { ????MonitorService service = (MonitorService)bc.getService(reference); ????thread.addService(service); ????return service; ??} ??public void modifiedService(ServiceReference reference, Object serviceObject) { ????MonitorService service = (MonitorService)bc.getService(reference); ????thread.addService(service); ??} ??public void removedService(ServiceReference reference, Object serviceObject) { ????MonitorService service = (MonitorService)bc.getService(reference); ????thread.removeService(service); ??} } |
注意,在本文中只實(shí)現(xiàn)了Monitor一項(xiàng)服務(wù),將來(lái)如需擴(kuò)充到支持多項(xiàng)系統(tǒng)管理服務(wù),可以為每一項(xiàng)或某一類服務(wù)各自實(shí)現(xiàn)一個(gè)ServiceTracker類來(lái)監(jiān)視相應(yīng)服務(wù)的可用性。
代碼清單8:ConsoleThread.java
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | package com.systemmanagement.console; ? import java.util.HashSet; import java.util.Iterator; import com.systemmanagement.services.monitor.MonitorService; ? public class ConsoleThread extends Thread { ??private HashSet<MonitorService> monitorServices= ????new HashSet<MonitorService>(); ??private boolean running = true; ??public ConsoleThread(){}; ??? ??public void addService(MonitorService service){ ????this.monitorServices.add(service); ??} ??public void removeService(MonitorService service){ ????this.monitorServices.remove(service); ??} ??public void run() { ????while (running) { ????????for(Iterator<MonitorService> it=this.monitorServices.iterator(); ????????it.hasNext();){ ????????MonitorService service=it.next(); ????????System.out.println(service.getMonitorMessage()); ??????} ??????try { ????????Thread.sleep(5000); ??????} catch (InterruptedException e) { ????????System.out.println("ManagementThread ERROR: " + e); ??????} ????} ??} ??public void stopThread() { ????this.running = false; ????try { ??????this.join(); ????} catch (InterruptedException e) { ??????e.printStackTrace(); ????} ??} } |
代碼清單8是一個(gè)多線程程序,為演示之簡(jiǎn)便,在此例中它只是用一個(gè)HashSet持有當(dāng)前可用的系統(tǒng)管理服務(wù),并無(wú)限循環(huán),依次執(zhí)行各項(xiàng)系統(tǒng)管理服務(wù)。在實(shí)際情況中,完全可以與用戶交互,根據(jù)用戶的指令來(lái)執(zhí)行相應(yīng)的系統(tǒng)管理服務(wù)。
代碼清單9:ConsoleActivator.java
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | package com.systemmanagement.console; ? import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.util.tracker.ServiceTracker; import org.osgi.util.tracker.ServiceTrackerCustomizer; import com.systemmanagement.services.monitor.MonitorService; ? public class ConsoleActivator implements BundleActivator { ??? ??private BundleContext context = null; ??private ServiceTracker tracker = null; ??private ConsoleThread thread=new ConsoleThread(); ??? ??public void start(BundleContext context) throws Exception { ????this.context = context; ????tracker = new ServiceTracker(context, MonitorService.class.getName(), ????????new MonitorServiceTracker(context,thread)); ????tracker.open(); ????? ????this.thread.start(); ??} ? ??public void stop(BundleContext context) throws Exception { ????tracker.close(); ????this.thread.stopThread(); ??} } |
五.運(yùn)行和測(cè)試基于OSGi的應(yīng)用程序
一個(gè)基于OSGi的應(yīng)用程序是由OSGi框架本身以及若干個(gè)Bundle組成,為了對(duì)其進(jìn)行運(yùn)行和測(cè)試,通常需要將各個(gè)Bundle Project一一打包成Bundle(jar文件),并部署到一個(gè)OSGi框架中,還是比較麻煩的。幸運(yùn)的是,Eclipse已經(jīng)對(duì)此提供了很好的支持,Eclipse本身是基于OSGi框架Equinox的,在Eclipse環(huán)境中可直接將各Bundle部署到Equinox框架中并運(yùn)行之,對(duì)開(kāi)發(fā)者來(lái)說(shuō)十分便利,其具體步驟如下:
在Eclipse中選擇Run-->Run...菜單,在彈出的Run配置面板的左側(cè)選中“Equinox OSGi Framework”,然后再選擇其上方的“New”按鈕創(chuàng)建一個(gè)新的運(yùn)行配置,將其命名為“systemmanagement”,再選擇右側(cè)的Deselect All按鈕,然后只選擇我們想要運(yùn)行的4個(gè)Bundles:包括我們前面開(kāi)發(fā)的3個(gè)Bundle以及OSGi框架本身org.eclipse.osgi,其中還可以設(shè)置各個(gè)Bundle的Start Level, Start Level可用于控制各Bundle的啟動(dòng)順序,Start Level低的Bundle會(huì)優(yōu)先啟動(dòng),例如我們可以將服務(wù)提供者Bundle cpumonitor的Start Level設(shè)為1,而將服務(wù)使用者Bundle console的Start Level設(shè)為2,如下圖所示:
圖2 Bundle的運(yùn)行配置
在Eclipse環(huán)境中的運(yùn)行結(jié)果如下圖,在控制臺(tái)中會(huì)不斷的顯示一些系統(tǒng)管理信息,同時(shí)也可在控制臺(tái)中運(yùn)行各種OSGi控制臺(tái)命令,如ss命令可用于顯示各Bundle的狀態(tài),讀者可以通過(guò)help命令了解更多的OSGi控制臺(tái)命令。
圖3 在Eclipse中的運(yùn)行結(jié)果
我們也需要了解如何讓這些Bundle脫離Eclipse環(huán)境來(lái)運(yùn)行,首先需要將各個(gè)Bundle Project打包成一個(gè)Bundle(即一個(gè)jar文件),其步驟如下:
在Eclipse主菜單中選File->Export,再在彈出窗口中選擇Deployable plug-ins and fragments,再選下一步,在彈出窗口中選擇我們上面開(kāi)發(fā)的三個(gè)Bundle project,并指定Bundle的輸出目錄,點(diǎn)Finish即可,如下圖所示:
圖4 導(dǎo)出Bundle
然后可以在e:\system_management\plugins目錄下找到三個(gè)jar文件,現(xiàn)在我們需要一個(gè)OSGi框架來(lái)運(yùn)行它們。Equinox是目前最流行的OSGi框架,Equinox本身也被打包成一個(gè)Bundle,在Eclipse安裝目錄的plugins目錄下即可找到它,如org.eclipse.osgi_3.2.0.v20060601.jar,將這個(gè)文件拷到e:\system_management目錄下。在命令提示符下進(jìn)入e:\system_management目錄下,運(yùn)行如下命令啟動(dòng)Equinox:
java –jar org.eclipse.osgi_3.2.0.v20060601.jar –console
啟動(dòng)之后會(huì)出現(xiàn)一個(gè)OSGi控制臺(tái),并且已經(jīng)啟動(dòng)一個(gè)system bundle,這個(gè)bundle就是OSGi框架本身。現(xiàn)在我們可以在OSGi控制臺(tái)中手工安裝我們開(kāi)發(fā)的三個(gè)Bundle,如下圖所示:
圖5 安裝Bundle
隨后,可以依次啟動(dòng)三個(gè)Bundle,這樣整個(gè)應(yīng)用就運(yùn)行起來(lái)了,如下圖所示:
圖6 運(yùn)行Bundle
請(qǐng)保留這個(gè)OSGi控制臺(tái)并讓?xiě)?yīng)用繼續(xù)運(yùn)行,接下來(lái)我們還會(huì)在這個(gè)控制臺(tái)中進(jìn)行一些操作來(lái)體驗(yàn)OSGi的動(dòng)態(tài)性。
六. 體驗(yàn)OSGi的動(dòng)態(tài)性
除了模塊化以及面向服務(wù)編程之外,OSGi的另一個(gè)重要特點(diǎn)是其動(dòng)態(tài)性,Bundle以及Bundle提供的服務(wù)可以隨時(shí)消失或者重新加入,而其它使用服務(wù)的Bundle可以感知服務(wù)是否可用,并動(dòng)態(tài)地改變自己的行為。應(yīng)用程序在運(yùn)行過(guò)程中,可以隨時(shí)增加新的Bundle,停止或卸載已有的Bundle,如果有新的服務(wù)加入進(jìn)來(lái),這個(gè)服務(wù)也能立即被其它Bundle使用并由此動(dòng)態(tài)地改變整個(gè)應(yīng)用程序的行為,在整個(gè)動(dòng)態(tài)改變的過(guò)程中,OSGi框架本身是穩(wěn)定的,無(wú)需重啟。以下我們將通過(guò)一些示例來(lái)體驗(yàn)OSGi的動(dòng)態(tài)性:
我們現(xiàn)在想給應(yīng)用增加一個(gè)監(jiān)視內(nèi)存運(yùn)行狀態(tài)的功能,新建一個(gè)Eclipse plugin-in project,將其命名為com.systemmanagement.memorymonitor,這個(gè)Bundle的實(shí)現(xiàn)過(guò)程與com.systemmanagement.cpumonitor基本類似,最主要的不同是實(shí)現(xiàn)MonitorService服務(wù)的那個(gè)類,如以下代碼所示,其它代碼可參見(jiàn)本文所附的代碼清單。
代碼清單10:MemoryMonitor.java
| 1 2 3 4 5 6 7 8 | package com.systemmanagement.memorymonitor.impl; import com.systemmanagement.services.monitor.MonitorService; ? public class MemoryMonitor implements MonitorService { ??public String getMonitorMessage() { ????return "內(nèi)存--物理內(nèi)存總數(shù):1G,可用數(shù):300M"; ??} } |
同樣,將這個(gè)Bundle export成一個(gè)jar文件到e:\system_management\plugins目錄下,安裝以及啟動(dòng)這個(gè)Bundle,這時(shí)我們發(fā)現(xiàn)輸出的系統(tǒng)管理信息馬上改變了,如下圖所示:
圖7 安裝以及啟動(dòng)一個(gè)新的Bundle
再假定我們需要增強(qiáng)com.systemmanagement.cpumonitor這個(gè)Bundle的功能,讓其提供更多的CPU信息,我們可以修改其中的CpuMonitor.java類,如下所示:
代碼清單11:CpuMonitor.java
| 1 2 3 4 5 6 7 8 | package com.systemmanagement.cpumonitor.impl; import com.systemmanagement.services.monitor.MonitorService; ? public class CpuMonitor implements MonitorService { ??public String getMonitorMessage() { ????return "CPU--溫度:40度,電壓:1.4v,CPU占用率:20%"; ??} } |
再將這個(gè)Bundle export成一個(gè)jar文件,放到e:\system_management\plugins目錄下,并在OSGi控制臺(tái)中使用update命令更新這個(gè)Bundle,我們發(fā)現(xiàn)輸出的CPU監(jiān)視信息馬上改變了,如下圖所示:
圖8 更新Bundle
讀者還可以在OSGi控制臺(tái)中嘗試使用start,stop等命令啟動(dòng)和停止一些Bundle,觀察輸出信息的改變,由此來(lái)體驗(yàn)一下OSGi的動(dòng)態(tài)性。
由于基于OSGi的應(yīng)用程序具有高度的模塊化和動(dòng)態(tài)性的特點(diǎn),使得要對(duì)其進(jìn)行擴(kuò)展也變得非常的方便:一般來(lái)說(shuō),擴(kuò)展就是增加新的Bundle,對(duì)其它Bundle基本無(wú)影響,如上面的例子所示,我們很方便地為應(yīng)用程序增加了新的功能,更新了它已有的功能,而整個(gè)應(yīng)用程序甚至都不需要重啟。Equinox同時(shí)還借用了Eclipse中的擴(kuò)展點(diǎn)的機(jī)制,利用擴(kuò)展點(diǎn),可以方便的為已有的Bundle擴(kuò)展功能,但擴(kuò)展點(diǎn)這一套機(jī)制目前還不是OSGi規(guī)范中定義的特性,僅是Equinox這一實(shí)現(xiàn)平臺(tái)擴(kuò)展出來(lái)的功能,使用了擴(kuò)展點(diǎn)的Bundle將有可能不能在其它的OSGi實(shí)現(xiàn)框架中正常運(yùn)行,這需要開(kāi)發(fā)者權(quán)衡選擇。
七.發(fā)布應(yīng)用程序
在上一節(jié)中我們?cè)贠SGi控制臺(tái)中運(yùn)行我們的系統(tǒng)管理程序,其中還需要手工install, start各個(gè)Bundle,顯然這很麻煩,不太象一個(gè)真正的應(yīng)用程序,本節(jié)將介紹如何構(gòu)造出一個(gè)完整的基于OSGi的應(yīng)用程序。
首先,Equinox提供了在啟動(dòng)框架時(shí)自動(dòng)安裝Bundle以及啟動(dòng)Bundle的功能,這是通過(guò)定義config.ini文件來(lái)實(shí)現(xiàn)的,應(yīng)用程序的目錄結(jié)構(gòu)如下:
| 1 2 3 4 5 6 7 8 9 | E:\SYSMGT_APP1 │? run.bat │? org.eclipse.osgi_3.2.0.v20060601.jar ├─configuration │????? config.ini └─plugins ???????com.systemmanagement.console_1.0.0.jar ???????com.systemmanagement.cpumonitor_1.0.0.jar ???????com.systemmanagement.services_1.0.0.jar |
config.ini文件的內(nèi)容如下:
| 1 2 3 | osgi.bundles=plugins/com.systemmanagement.cpumonitor_1.0.0.jar@1:start, ?plugins/com.systemmanagement.console_1.0.0.jar@2:start, ?plugins/com.systemmanagement.services_1.0.0.jar |
其中的@1,@2用于指定Bundle的Start Level, start表示當(dāng)OSGi框架啟動(dòng)后即自動(dòng)啟動(dòng)此Bundle。而run.bat是一個(gè)批處理程序,其內(nèi)容如下:
java –jar org.eclipse.osgi_3.2.0.v20060601.jar -console
現(xiàn)在只需運(yùn)行run.bat即可運(yùn)行我們的系統(tǒng)管理應(yīng)用程序了。
Eclipse中還提供了兩個(gè)Bundle, org.eclipse.equinox.common和org.eclipse.update.configurator,可用于自動(dòng)發(fā)現(xiàn)和安裝指定目錄下新增加的Bundle。 我們同樣可以在Eclipse的plugins目錄中找到這兩個(gè)Bundle并將它們拷到E:\SYSMGT_APP1\plugins目錄下,并修改config.ini文件的內(nèi)容如下所示:
| 1 2 3 4 | osgi.bundles=plugins/org.eclipse.equinox.common_3.2.0.v20060603.jar@1:start, ?plugins/org.eclipse.update.configurator_3.2.0.v20060605.jar@2:start, ?plugins/com.systemmanagement.cpumonitor_1.0.0.jar@2:start, ?plugins/com.systemmanagement.console_1.0.0.jar@3:start |
這樣,當(dāng)org.eclipse.update.configurator Bundle啟動(dòng)時(shí),它會(huì)去自動(dòng)發(fā)現(xiàn)和安裝plugins目錄新增的Bundle,但需注意, 它并不能自動(dòng)啟動(dòng)這些Bundle,OSGi協(xié)議目前也沒(méi)有提供這樣的標(biāo)準(zhǔn)服務(wù)來(lái)自動(dòng)安裝,管理和啟動(dòng)Bundle, 我們可以使用如下的一些解決方案來(lái)更好地管理和分發(fā)Bundle:
- 利用Eclipse的Update Manager:Eclipse Update Manager提供了一批API用于管理,下載,升級(jí),安裝Feature,一個(gè)Feature是一批Bundle的集合, 是下載和安裝的最小單位。但Feature是Eclipse定義的,不是OSGi協(xié)議中定義的特性。
- 使用FileInstall Bundle,這個(gè)Bundle可以監(jiān)視某一個(gè)目錄,如果這個(gè)目錄中新增加了Bundle,它會(huì)自動(dòng)將其install,如果有Bundle被更新了, 它會(huì)自動(dòng)將其update,如果有Bundle從此目錄被移走,它會(huì)自動(dòng)將其uninstall。可到?http://www.aqute.biz/Code/FileInstall下載這個(gè)Bundle,它可以運(yùn)行于任何OSGi框架中。
- 在Equinox孵化器(incubator)中有一個(gè)org.eclipse.equinox.simpleconfigurator,可用于管理和控制已安裝的Bundle, 包括設(shè)置啟動(dòng)級(jí)別并自動(dòng)啟動(dòng)它們。可訪問(wèn)http://www.eclipse.org/equinox/incubator并到其CVS庫(kù)中下載
八. 小結(jié)
本文介紹了基于OSGi開(kāi)發(fā)一個(gè)應(yīng)用程序的完整流程,包括模塊劃分,Bundle的設(shè)計(jì)與開(kāi)發(fā),部署與測(cè)試,發(fā)布應(yīng)用程序等,并演示了基于OSGi編程所具有的模塊化,面向服務(wù),動(dòng)態(tài)性,易擴(kuò)展等優(yōu)點(diǎn)。基于組件或構(gòu)件編程是學(xué)術(shù)界提了多年的思想,筆者認(rèn)為OSGi是一個(gè)比較徹底地體現(xiàn)這種思想的編程模型,基于OSGi編程將帶來(lái)軟件設(shè)計(jì)以及開(kāi)發(fā)方式的改變并由此帶來(lái)軟件生產(chǎn)效率的極大提升。
申明:本文僅代表筆者個(gè)人的觀點(diǎn),不代表IBM公司的觀點(diǎn)。
下載資源
- 本文所有的示例源代碼?(osgi_samplecodes.zip | 27KB)
相關(guān)主題
- IBM developerworks中國(guó)網(wǎng)站上的文章?利用Eclipse開(kāi)發(fā)基于OSGi的Bundle應(yīng)用
- 閱讀Scott Delap撰寫(xiě)的?了解Eclipse插件如何使用OSGi
- 要了解Eclipse和OSGi,請(qǐng)閱讀?利用OSGi解決Eclipse插件難題
- 訪問(wèn)?OSGi Alliance Service Platform, 了解更多關(guān)于 OSGi的信息,包括OSGi Release 4規(guī)范等信息
- 獲得有關(guān)Eclipse和Equinox的更多詳細(xì)資料?Eclipse.org,?Equinox
- 了解其它OSGi實(shí)現(xiàn)框架:?Oscar,?Apache Felix,?Knopflerfish
- 要獲得關(guān)于Eclipse平臺(tái)的介紹性文章,請(qǐng)參閱?Eclipse 平臺(tái)入門(mén)
- EclipseCon?上有許多關(guān)于OSGi的資料
from:?https://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-osgi/index.html?
總結(jié)
以上是生活随笔為你收集整理的基于 OSGi 的面向服务的组件编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 探索 OSGi 框架的组件运行机制
- 下一篇: 以 OSGi 包的形式开发和部署 Web