<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆 - 19, 文章 - 1, 評論 - 21, 引用 - 0
    數(shù)據(jù)加載中……

    OSGi中獲取Service的幾種方式

    在OSGi中,Service是動態(tài)管理的,OSGi容器提供的好幾種獲取和使用Service的方式,那么這幾種方式各有什么優(yōu)、缺點呢,下面我們就以org.osgi.service.log.LogService為例來分別講一講。


    一。最原始的方式:
     1         // 獲取Service引用
     2         ServiceReference ref = context.getServiceReference(LogService.class.getName());
     3         if (ref != null) {
     4             // 獲取Service實例
     5             LogService service = (LogService) context.getService(ref);
     6             if (service != null) {
     7                 // 調(diào)用Service方法
     8                 service.log(LogService.LOG_INFO, "ok");
     9                 // 釋放Service,在此之后不應該再繼續(xù)使用Service實例
    10                 context.ungetService(ref);
    11             }
    12         }
    優(yōu)點:很難說有什么優(yōu)點,硬要說幾句的話,那就是邏輯夠簡單,調(diào)用最少,適合一次性操作。
    缺點:需要判斷返回值是否為null,需要手動申請和釋放service,由于OSGi的動態(tài)性,請在獲取ref后盡快使用,無法保證ref長期有效。每次訪問都會有service獲取和釋放的開銷。
    用途:適合于不頻繁的調(diào)用service,且在service不可用時也能繼續(xù)執(zhí)行后續(xù)操作的場景。

    二。使用ServiceListener:
    在Service注冊時訪問:
     1         context.addServiceListener(new ServiceListener() {
     2             public void serviceChanged(ServiceEvent event) {
     3                 switch (event.getType()) {
     4                 case ServiceEvent.REGISTERED:
     5                     // 獲取Service引用
     6                     ServiceReference ref = event.getServiceReference();
     7                     // 獲取Service實例
     8                     LogService service = (LogService) context.getService(ref);
     9                     if (service != null) {
    10                         // 調(diào)用Service方法
    11                         service.log(LogService.LOG_INFO, "ok");
    12                         // 釋放Service,在此之后不應該再繼續(xù)使用Service實例
    13                         context.ungetService(ref);
    14                     }
    15                     break;
    16                 case ServiceEvent.UNREGISTERING:
    17 
    18                     break;
    19                 }
    20 
    21             }
    22         }, "(objectclass=org.osgi.service.log.LogService)");
    獨立于ServiceListener的訪問:類似于方式一,在Listener中獲取service并且保存到成員變量中,以供后續(xù)訪問:
     1         context.addServiceListener(new ServiceListener() {
     2             public void serviceChanged(ServiceEvent event) {
     3                 switch (event.getType()) {
     4                 case ServiceEvent.REGISTERED:
     5                     if (ref == null) {
     6                         ref = event.getServiceReference();
     7                         service = (LogService) context.getService(ref);//保存實例以備后續(xù)訪問
     8                     }
     9                     break;
    10                 case ServiceEvent.UNREGISTERING:
    11                     if (ref == event.getServiceReference()) {
    12                         context.ungetService(ref);//釋放實例
    13                         service = null;
    14                         ref = null;
    15                     }
    16                     break;
    17                 }
    18 
    19             }
    20         }, "(objectclass=org.osgi.service.log.LogService)");
    訪問Service:
    1         if (service != null) service.log(LogService.LOG_INFO, "ok");
    優(yōu)點:只在Service變更時產(chǎn)生一次service獲取開銷,動態(tài)感知service的注冊和注銷。
    缺點:在ServiceListener注冊之前已經(jīng)存在的Service無法監(jiān)聽到。需要自己維護service的獲取和釋放。在需要監(jiān)聽多個Service實例時,使用并不方便。

    三、使用ServiceTracker
    ServiceTracker其實是對ServiceListener實現(xiàn)方式的封裝,使得對service的獲取更加簡潔,同時也解決了不能監(jiān)聽到已經(jīng)存在的Service的問題(其實就是在增加ServiceListener的同時調(diào)用BundleContext.getAllServiceReferences方法以獲取現(xiàn)有的Service引用)。
    使用ServiceTracker使得獲取Service的代碼更加簡潔和一致,不必再考慮Service是否存在的問題,并且ServiceTracker也提供了更加有效的監(jiān)聽Service的方式。
    一次性訪問:
    1         ServiceTracker tracker = new ServiceTracker(context, LogService.class.getName(), null);
    2         tracker.open();
    3         LogService service = (LogService) tracker.getService();
    4         if (service != null) service.log(LogService.LOG_INFO, "ok");
    5         // 獲取多個Service
    6         Object[] services = tracker.getServices();
    7         // 獲取Service的數(shù)量
    8         int count = tracker.getTrackingCount();
    9         tracker.close();
    在Service注冊和注銷時訪問:
     1         ServiceTracker tracker = new ServiceTracker(context, LogService.class.getName(), null) {
     2             @Override
     3             public Object addingService(ServiceReference reference) {
     4                 LogService service = (LogService) super.addingService(reference);
     5                 if (service != null) service.log(LogService.LOG_INFO, "ok");
     6                 return service;
     7             }
     8 
     9             @Override
    10             public void removedService(ServiceReference reference, Object service) {
    11                 ((LogService) service).log(LogService.LOG_INFO, "removedService");
    12                 super.removedService(reference, service);
    13             }
    14         };
    15         tracker.open();
    16 
    17         // 在自身lifecycle結(jié)束時關(guān)閉tracker
    18         tracker.close();
    有一點需要注意的是,tracker需要調(diào)用open方法才能監(jiān)聽到Service,另外,在bundle stop以后,bundle內(nèi)open的ServiceTracker不會自動關(guān)閉,所以一定不要忘記在bundle結(jié)束之前,關(guān)閉所有在bundle中open的ServiceTracker。

    四、使用Declarative Services
    在OSGi 4以后的規(guī)范中,增加了Declarative Services方式。Declarative Services 是一個面向服務的組件模型,它制訂的目的是更方便地在 OSGi 服務平臺上發(fā)布、查找、綁定服務,對服務進行動態(tài)管理,如監(jiān)控服務狀態(tài)以及解決服務之間的復雜的依賴關(guān)系等問題。Declarative Services 采用服務組件的延遲加載以及組件生命周期管理的方式來控制對于內(nèi)存的占用以及啟動的快速,很好的解決了傳統(tǒng)的 OSGi 服務模型在開發(fā)和部署比較復雜應用時內(nèi)存占用大、啟動慢等問題,并且對服務組件的描述采用XML來實現(xiàn),十分便于用戶理解和使用。
    在equinox-SDK-3.6M5開發(fā)包中,包含了一個DS的實現(xiàn):org.eclipse.equinox.ds_1.2.0.v20100125.jar,將這個jar和一個依賴的jar:org.eclipse.equinox.util_1.0.100.v20090520-1800.jar部署到OSGi容器中,就可以使用DS服務了。equinox中DS服務的實現(xiàn),是綜合使用了BundleListener,ServiceListener等相關(guān)OSGi API,將大量繁雜和冗長的代碼細節(jié)藏在了實現(xiàn)背后,開發(fā)者只需要了解簡單的xml語法和配置方式即可方便的使用。
    要使用DS,一般有以下幾個步驟:
    1.定義Component實現(xiàn)類:
     1 package org.dbstar.osgi.dstest;
     2 
     3 import org.osgi.service.component.ComponentContext;
     4 import org.osgi.service.log.LogService;
     5 
     6 public class TestComponent {
     7     public void activate(ComponentContext context) {
     8         System.out.println("activate(" + context + ")");
     9     }
    10 
    11     public void deactivate(ComponentContext context) {
    12         System.out.println("deactivate(" + context + ")");
    13     }
    14 
    15     public void modified(ComponentContext context) {
    16         System.out.println("modified(" + context + ")");
    17     }
    18 
    19     public void bind(LogService service) {
    20         service.log(LogService.LOG_INFO, "bind");
    21     }
    22 
    23     public void unbind(LogService service) {
    24         service.log(LogService.LOG_INFO, "unbind");
    25     }
    26 }
    2.編寫component.xml:
    1 <?xml version="1.0" encoding="UTF-8"?>
    2 <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
    3     activate="activate" deactivate="deactivate" modified="modified" name="test"
    4     xsi:schemaLocation="http://www.osgi.org/xmlns/scr/v1.1.0 http://www.osgi.org/xmlns/scr/v1.1.0">
    5     <implementation class="org.dbstar.osgi.dstest.TestComponent" />
    6     <reference bind="bind" cardinality="1..1"
    7         interface="org.osgi.service.log.LogService" name="LogService"
    8         policy="dynamic" unbind="unbind" />
    9 </scr:component>
    以上是有namespace的xml寫法,在equinox中也支持沒有namespace的寫法,Eclipse中有相應的插件來提供圖形化的界面來維護component xml。以下是沒有namespace的xml寫法:
    1 <?xml version="1.0" encoding="UTF-8"?>
    2 <component name="test">
    5     <implementation class="org.dbstar.osgi.dstest.TestComponent" />
    6     <reference bind="bind" cardinality="1..1"
    7         interface="org.osgi.service.log.LogService" name="LogService"
    8         policy="dynamic" unbind="unbind" />
    9 </component>
    3.將寫好的xml放置到bundle根目錄下的OSGI-INF下面
    4.在bundle的描述文件META-INF/MANIFEST.MF中增加component相關(guān)的header:
    1 Service-Component: OSGI-INF/component.xml
    注意xml的文件名不是絕對的,放置的目錄也不是絕對的,只要在Service-Component中包含正確的路徑就可以了。
    一個bundle可以注冊多個component,只要編寫多個xml文件即可,在Service-Component中以逗號分隔。
    Component的注冊并不依賴Activator,所以bundle的Activator不是必須的。
    另外在我的使用過程中,發(fā)現(xiàn)一個問題,如果xml中沒有使用namespace,那么component節(jié)點上的幾個callback類屬性都不能定義,例如activate屬性。如果使用了namespace,那么這些屬性都是可以正常使用的,不知道這算不算是bug。
    關(guān)于DS規(guī)范的詳細內(nèi)容,可以參見:OSGi 中的 Declarative Services 規(guī)范簡介

    最后總結(jié)一下,綜上所述的四種獲取service的方法,使得service的獲取越來越簡單,開發(fā)者只需關(guān)注自己的邏輯,而不必糾纏于OSGi繁瑣的Service Lookup中去,同時還提供了更加方便使用的API,大家可以根據(jù)自己的需要,選擇最合適的使用方式。

    posted on 2010-03-26 18:09 dbstar 閱讀(13297) 評論(0)  編輯  收藏 所屬分類: OSGi

    主站蜘蛛池模板: 国内精品一级毛片免费看| 粉色视频成年免费人15次| 日韩视频在线观看免费| 亚洲日本中文字幕天堂网| 特级无码毛片免费视频| 亚洲第一黄色网址| 成年大片免费高清在线看黄| 亚洲精品国产精品乱码不卡| 天堂亚洲免费视频| 在线观看亚洲av每日更新| 两个人日本免费完整版在线观看1| 亚洲一级Av无码毛片久久精品| 丁香六月婷婷精品免费观看| 区久久AAA片69亚洲| 免费播放在线日本感人片| 亚洲大尺度无码无码专区| 久久国产乱子伦免费精品| 亚洲成aⅴ人在线观看| 成人无遮挡毛片免费看| 黄色免费网址在线观看| 亚洲人精品午夜射精日韩 | a在线观看免费视频| 亚洲福利在线视频| 大学生一级毛片免费看| 美女裸免费观看网站| 亚洲一区无码中文字幕| 99xxoo视频在线永久免费观看| 激情五月亚洲色图| 亚洲?v无码国产在丝袜线观看| 日本免费久久久久久久网站| 亚洲伊人久久大香线蕉在观| 免费国产高清视频| 永久免费A∨片在线观看| 亚洲一本到无码av中文字幕| 亚洲区小说区图片区| 91大神在线免费观看| 麻豆一区二区三区蜜桃免费| 亚洲av永久无码精品网站 | 亚洲精品无码专区在线播放| 国产av无码专区亚洲国产精品| 久久免费观看国产99精品|