溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何分析OSGi服務(wù)

發(fā)布時(shí)間:2022-01-14 21:34:51 來(lái)源:億速云 閱讀:158 作者:柒染 欄目:編程語(yǔ)言

本篇文章給大家分享的是有關(guān)如何分析OSGi服務(wù),小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。

OSGi服務(wù)

前面我們提到,OSGi架構(gòu)非常適合我們實(shí)現(xiàn)面向服務(wù)的應(yīng)用(SOA)。它可以讓Bundles導(dǎo)出服務(wù),而其它的Bundles可以在不必了解源Bundles任何信息的情況下消費(fèi)這些導(dǎo)出的服務(wù)。由于OSGi具有隱藏真實(shí)的服務(wù)實(shí)現(xiàn)類(lèi)的能力,所以它為面向服務(wù)的應(yīng)用提供了良好的類(lèi)與接口的組合。

在OSGi框架中,源Bundle在OSGi容器中注冊(cè)POJO對(duì)象,該對(duì)象不必實(shí)現(xiàn)任何接口,也不用繼承任何超類(lèi),但它可以注冊(cè)在一個(gè)或多個(gè)接口下,并對(duì)外提供服務(wù)。目標(biāo)Bundle可以向OSGi容器請(qǐng)求注冊(cè)在某一接口下的服務(wù),一旦它發(fā)現(xiàn)該服務(wù),目標(biāo)Bundle就會(huì)將該服務(wù)綁定到這個(gè)接口,并能調(diào)用該接口中的方法。下面我們舉個(gè)例子,以便我們能更好理解與OSGi相關(guān)的這些概念。

5.1. 導(dǎo)出服務(wù)

在本小節(jié)中,我們將更新HelloService Bundle,以便它能把HelloServiceImpl類(lèi)的對(duì)象導(dǎo)出為服務(wù),具體步驟如下:

1) 修改com.javaworld.sample.HelloService Bundle中的MANIFEST.MF文件,讓它導(dǎo)入org.osgi.framework包(譯者注,這一步我們已經(jīng)完成);

2) 新建Java類(lèi)com.javaworld.sample.impl.HelloServiceActivator.java,其源代碼如清單7所示;

源代碼清單7. HelloServiceActivator.java

public class HelloServiceActivator implements BundleActivator {  ServiceRegistrationhelloServiceRegistration;  public void start(BundleContext context)throws Exception {  HelloService helloService = newHelloServiceImpl();  helloServiceRegistration=context.registerService(HelloService.class.getName(), helloService, null);  }  public void stop(BundleContext context)throws Exception {  helloServiceRegistration.unregister();  }  }

請(qǐng)注意,在源Bundle中,我們應(yīng)使用BundleContext.registerService()方法導(dǎo)出服務(wù),這個(gè)方法帶三個(gè)參數(shù):

a) 該方法***個(gè)參數(shù)為您要注冊(cè)的服務(wù)的接口名稱(chēng)。如果您想把您的服務(wù)注冊(cè)到多個(gè)接口下,您需要新建一個(gè)String數(shù)組存放這些接口名,然后把這個(gè)數(shù)組作為***個(gè)參數(shù)傳給registerService()方法。在示例代碼中,我們想把我們的服務(wù)導(dǎo)出到HelloServer接口名下;

b) 第二個(gè)參數(shù)是您要注冊(cè)的服務(wù)的實(shí)際Java對(duì)象。在示例代碼中,我們導(dǎo)出HelloServiceImpl類(lèi)的對(duì)象,并將其作為服務(wù);

c) 第三個(gè)參數(shù)為服務(wù)的屬性,它是一個(gè)Dictionary對(duì)象。如果多個(gè)Bundle導(dǎo)出服務(wù)的接口名相同,目標(biāo)Bundle就可以使用這些屬性對(duì)源Bundle進(jìn)行過(guò)濾,找到它感興趣的服務(wù)。

3) ***,請(qǐng)修改HelloServiceBundle中的MANIFEST.MF文件,將Bundle-Activator屬性頭的值改為com.javaworld.sample.service.impl.HelloServiceActivator。

現(xiàn)在HelloService Bundle就可以導(dǎo)出HelloServiceImpl對(duì)象了。當(dāng)OSGi容器啟動(dòng)HelloServiceBundle時(shí),它會(huì)將控制權(quán)交給HelloServiceActivator.java類(lèi),HelloServiceActivator將HelloServiceImpl對(duì)象注冊(cè)為服務(wù)。下面,我們開(kāi)始創(chuàng)建該服務(wù)的消費(fèi)者。

5.2. 導(dǎo)入服務(wù)

在本小節(jié)中,我們將修改上面開(kāi)發(fā)的HelloWorld Bundle,以便讓它成為HelloService服務(wù)的消費(fèi)者。您主要需要修改HelloWorldBundle中的Activator.java代碼,修改后的代碼如源代碼清單8所示:

源代碼清單8. HelloWorld Bundle中的Activator.java

packagecom.javaworld.sample.helloworld;   importorg.osgi.framework.BundleActivator;  importorg.osgi.framework.BundleContext;  importorg.osgi.framework.ServiceReference;  importcom.javaworld.sample.service.HelloService;   publicclass Activator implements BundleActivator {  ServiceReference helloServiceReference;  public void start(BundleContext context)throws Exception {  System.out.println("HelloWorld!!");  helloServiceReference=context.getServiceReference(HelloService.class.getName());  HelloService helloService=(HelloService)context.getService(helloServiceReference);  System.out.println(helloService.sayHello());   }  public void stop(BundleContext context)throws Exception {  System.out.println("Goodbye World!!");  context.ungetService(helloServiceReference);  }  }

在上面的代碼中,BundleContext.getServiceReference()方法將為注冊(cè)在HelloService接口下的服務(wù)返回一個(gè)ServiceReference對(duì)象。如果存在多個(gè)HelloService服務(wù),該方法會(huì)返回排行***的服務(wù)(服務(wù)的排行是通過(guò)Constants.SERVICE_RANKING屬性指定的)。您一旦獲得ServiceReference對(duì)象,您就可以調(diào)用其BundleContext.getService()方法獲取真實(shí)的服務(wù)對(duì)象。

您可以參照運(yùn)行Bundle的方法運(yùn)行上面的示例應(yīng)用,請(qǐng)點(diǎn)擊“RunàRun…”菜單,并確保HelloWorld和HelloService這兩個(gè)Bundle被選中。當(dāng)您啟動(dòng)HelloServiceBundle時(shí),您會(huì)在控制臺(tái)上看到“InsideHelloServiceImple.sayHello()”,這個(gè)消息是由HelloServiceImpl.sayHello()方法打印出來(lái)的。

5.3. 創(chuàng)建服務(wù)工廠

在上節(jié)中,我們學(xué)會(huì)了如何使用OSGi框架新建一個(gè)Java對(duì)象,并把它注冊(cè)為一個(gè)服務(wù),然后讓其它的Bundle去消費(fèi)這個(gè)服務(wù)。如果您看一下HelloServiceActivator.start()方法,您會(huì)注意到我們?cè)趕tart()方法中新建了HelloServiceImpl類(lèi)對(duì)象,然后將它注冊(cè)到HelloService接口名下。這樣注冊(cè)后,任何其它的Bundle在請(qǐng)求HelloService服務(wù)時(shí),OSGi容器將返回同一對(duì)象。

在大多數(shù)情況下,這樣的實(shí)現(xiàn)方法沒(méi)有問(wèn)題。但是,比如說(shuō)我們要為每一個(gè)Bundle消費(fèi)者返回不同的HelloServiceImpl對(duì)象,再比如說(shuō),您的服務(wù)對(duì)象要提供的服務(wù)為打開(kāi)一個(gè)數(shù)據(jù)庫(kù)連接,但并不是馬上就打開(kāi)它,而是在真正需要的時(shí)候才打開(kāi)這個(gè)數(shù)據(jù)庫(kù)連接。

對(duì)這兩種情況,我們的解決方法是,新建一個(gè)類(lèi)實(shí)現(xiàn)ServiceFactory接口,并把該類(lèi)的對(duì)象注冊(cè)為服務(wù),但并不是注冊(cè)實(shí)際的服務(wù)對(duì)象。一旦您完成這一步,其它Bundle在請(qǐng)求該服務(wù)時(shí),您的ServiceFactory實(shí)現(xiàn)類(lèi)將接管該請(qǐng)求,ServiceFactory會(huì)為每個(gè)Bundle新建一個(gè)服務(wù)對(duì)象,并將真實(shí)服務(wù)的創(chuàng)建時(shí)間延遲到有人真正需要該服務(wù)的時(shí)候。

下面我們將使用ServiceFactory更新我們上面開(kāi)發(fā)的com.javaworld.sample.HelloServiceBundle,具體步驟如下:

1) 新建工廠 類(lèi)HelloServiceFactory.java,源代碼如清單9所示。

源代碼清單9 . HelloServiceFactory.java

public class HelloServiceFactory implements ServiceFactory{  private int usageCounter = 0;  public Object getService(Bundle bundle,ServiceRegistration registration) {  System.out.println("Create objectof HelloService for " + bundle.getSymbolicName());  usageCounter++;  System.out.println("Number ofbundles using service " + usageCounter);  HelloService helloService = newHelloServiceImpl();  return helloService;  }  public void ungetService(Bundle bundle,ServiceRegistration registration, Object service) {  System.out.println("Release objectof HelloService for " + bundle.getSymbolicName());  usageCounter--;  System.out.println("Number ofbundles using service " + usageCounter);  }  }

從上面的代碼中,我們可以看到,ServiceFactory接口定義了兩個(gè)方法:

a) getService()方法:當(dāng)某個(gè)Bundle***次使用BundleContext.getService(ServiceReference)方法請(qǐng)求一個(gè)服務(wù)對(duì)象時(shí),OSGi框架會(huì)調(diào)用該方法。在源代碼清單9中,我們用這個(gè)方法為每個(gè)Bundle新建并返回不同的HelloServiceImpl對(duì)象,如果這個(gè)對(duì)象不是null,OSGi框架會(huì)緩存這個(gè)對(duì)象。如果同一個(gè)Bundle再次調(diào)用BundleContext.getService(ServiceReference)方法,OSGi將返回同一個(gè)服務(wù)對(duì)象。

b) ungetService()方法:當(dāng)Bundle釋放服務(wù)時(shí),OSGi容器可以調(diào)用該方法銷(xiāo)毀服務(wù)對(duì)象。在源代碼清單9中,我們使用usageCounter變量來(lái)跟蹤服務(wù)的使用數(shù)目,并打印出該服務(wù)的客戶端數(shù)量。

2) 修改HelloService Bundle中的HelloServiceActivator.java的start()方法,讓它注冊(cè)到ServiceFactory接口名下,而不是注冊(cè)到HelloService接口。詳細(xì)代碼如清單10所示:

源代碼清單10. 修改后的HelloServiceBundle中的HelloServiceActivator.java

package com.javaworld.sample.service.impl;  importorg.osgi.framework.BundleActivator;  importorg.osgi.framework.BundleContext;  importorg.osgi.framework.ServiceRegistration;   importcom.javaworld.sample.helloservice.HelloServiceFactory;  importcom.javaworld.sample.service.HelloService;   publicclass HelloServiceActivator implements BundleActivator {  ServiceRegistrationhelloServiceRegistration;  public void start(BundleContext context)throws Exception {  HelloServiceFactory helloServiceFactory= new HelloServiceFactory();  helloServiceRegistration=context.registerService(HelloService.class.getName(), helloServiceFactory,null);  }  public void stop(BundleContext context)throws Exception {  helloServiceRegistration.unregister();  }  }

現(xiàn)在,您可以試運(yùn)行示例代碼。您會(huì)注意到,當(dāng)HelloWorld Bundle啟動(dòng)時(shí),服務(wù)計(jì)數(shù)器變?yōu)?;當(dāng)HelloWorldBundle停止時(shí),服務(wù)計(jì)數(shù)器的數(shù)目將變?yōu)?。

5.4. 跟蹤服務(wù)

在“OSGi服務(wù)”小節(jié),您學(xué)會(huì)了如何使用服務(wù)的接口名搜索服務(wù)。但如果有多個(gè)Bundle使用同一接口名注冊(cè)服務(wù),那會(huì)發(fā)生什么呢?這時(shí),OSGi容器將返回排行***的服務(wù),即,返回注冊(cè)時(shí)那個(gè)SERVICE_RANKING屬性值***的服務(wù)。如果有多個(gè)服務(wù)的排行值相等,那么OSGi容器將返回PID值最小的那個(gè)服務(wù)。

但是,如果您的服務(wù)消費(fèi)者需要了解某一接口下的服務(wù)對(duì)象何時(shí)注冊(cè)、何時(shí)取消注冊(cè),這時(shí),您應(yīng)使用ServiceTracker類(lèi)。下面,我們看看如何使用服務(wù)跟蹤器來(lái)修改我們的示例代碼,具體步驟如下。

1) 修改HelloWorldBundle的MANIFEST.MF文件,讓它導(dǎo)入org.osgi.util.tracker包;

2) 新建類(lèi)HelloServiceTracker.java,

源代碼清單11.HelloServiceTracker.java

public class HelloServiceTracker extends ServiceTracker {       public HelloServiceTracker(BundleContext context) {           super(context, HelloService.class.getName(),null);       }       public Object addingService(ServiceReference reference) {           System.out.println("Inside HelloServiceTracker.addingService " + reference.getBundle());           return super.addingService(reference);       }       public void removedService(ServiceReference reference, Object service) {           System.out.println("Inside HelloServiceTracker.removedService " + reference.getBundle());           super.removedService(reference, service);       }   }

在上面的HelloSerivceTracker類(lèi)的構(gòu)造函數(shù)中,您可以看到,我們把HelloService接口名傳入其父類(lèi)中,這相當(dāng)于說(shuō),HelloServiceTracker應(yīng)跟蹤注冊(cè)到HelloService接口名下的所有服務(wù),HelloServiceTracker繼承自ServiceTracker類(lèi),實(shí)現(xiàn)了下面兩個(gè)方法:

a) addingService()方法:當(dāng)Bundle使用接口名注冊(cè)服務(wù)時(shí),該方法將會(huì)被調(diào)用;

b)removedService()方法:當(dāng)Bundle取消注冊(cè)某個(gè)接口名下的服務(wù)時(shí),該方法將會(huì)被調(diào)用。

3) 用HelloServiceTracker類(lèi)更新我們的Activator.java類(lèi),以便讓它來(lái)管理服務(wù),而不是直接去查找它們,源代碼請(qǐng)參見(jiàn)清單12。

源代碼清單12. 使用了HelloServiceTracker的Activator.java

public class Activator implements BundleActivator {       HelloServiceTracker helloServiceTracker;       public void start(BundleContext context) throws Exception {           System.out.println("Hello World!!");           helloServiceTracker= new HelloServiceTracker(context);           helloServiceTracker.open();           HelloService helloService = (HelloService)helloServiceTracker.getService();           System.out.println(helloService.sayHello());           }       public void stop(BundleContext context) throws Exception {           System.out.println("Goodbye World!!");           helloServiceTracker.close();       }   }

我們看到,在初始的start()方法中,我們首先新建一個(gè)HelloServiceTracker對(duì)象,然后要求這個(gè)對(duì)象跟蹤HelloService接口下的服務(wù)。這時(shí),我們可以調(diào)用getService()方法獲得HelloService對(duì)象。

如果您試運(yùn)行上面的示例代碼,您會(huì)注意到,在啟動(dòng)或停止HelloSerivceBundle時(shí),OSGi容器都會(huì)調(diào)用HelloServiceTracker對(duì)象的addingService()方法或removedService()方法。

以上就是如何分析OSGi服務(wù),小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI