欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
OSGi入門(mén)篇:服務(wù)層

OSGi入門(mén)篇:服務(wù)層

前言

到現在為止,我們已經(jīng)了解了OSGi框架的下面兩層,而作為OSGi框架中最上面的一層,服務(wù)層帶給了我們更多的動(dòng)態(tài)性,并且使用了大家或多或少都曾了解過(guò)的面向服務(wù)編程模型,其好處是顯而易見(jiàn)的。

這里我們依然會(huì )講解什么是服務(wù)層和服務(wù)層對于OSGi框架的意義,此外,還將告訴大家什么時(shí)候應該使用服務(wù),什么時(shí)候不應該使用。最后將會(huì )是OSGi服務(wù)層的一些基礎,包括如何定義、注冊和發(fā)現服務(wù)。

1 什么是服務(wù)

簡(jiǎn)單的說(shuō),服務(wù)就是“為別人所做的工作”,比如兩個(gè)對象互相調用方法,那么被調用者就是在為調用者做工作。 也許有的人會(huì )覺(jué)得服務(wù)是從網(wǎng)絡(luò )上獲取的,但是經(jīng)典的看法其實(shí)并沒(méi)有這個(gè)限制,有時(shí)候即使是完全本地的應用,也能從面向服務(wù)的編程中得到好處。

那么如何將服務(wù)和一次普通的方法調用區別開(kāi)來(lái)呢?其實(shí)一個(gè)服務(wù)可以看作是在服務(wù)的提供者和使用者之間的一個(gè)契約。使用者一般不關(guān)心其實(shí)現的細節,甚至連誰(shuí)提供的都不想知道,只要滿(mǎn)足這個(gè)契約(服務(wù)應該提供什么功能,滿(mǎn)足什么格式)就好了。使用服務(wù)的過(guò)程也包含了發(fā)現服務(wù)和達成協(xié)議的形式,也就是說(shuō)我們需要通過(guò)服務(wù)的標志性特征來(lái)找到對應的服務(wù)。

其實(shí),Java的接口可以說(shuō)提供了一種契約的提供方式,我們能通過(guò)修改classpath來(lái)替換接口的不同的具體實(shí)現。但是OSGi能夠為找到服務(wù)提供更加高層的抽象并且在應用的執行時(shí)動(dòng)態(tài)替換服務(wù)的實(shí)現,這些特性在稍后將會(huì )提到。

2 為什么要使用服務(wù)

服務(wù)(更準確的說(shuō)是面向服務(wù)的編程模型)給予了我們一種即插即用的軟件開(kāi)發(fā)方法,意味著(zhù)更強的靈活性。這種靈活性是如何體現的呢?

  • 低耦合,利于組件復用:通過(guò)服務(wù)我們能夠清晰的定義組件的邊界,從而將服務(wù)的使用者和提供者之間的耦合度降到很低。
  • 更加強調接口而不是在具體的實(shí)現:Java的interface提供了一種形式的契約,在OSGi的服務(wù)層中充分利用了接口特性的優(yōu)勢,這樣使得無(wú)論有多少個(gè)類(lèi)實(shí)現了這個(gè)接口,只要滿(mǎn)足對這個(gè)接口的功能需要,就可以被使用者使用。
  • 對于依賴(lài)有比較清晰地描述:?jiǎn)问墙涌诒旧碇话?wù)的名稱(chēng)和參數類(lèi)型,并不足以清楚的描述服務(wù)的所有特征,而面向服務(wù)的編程模型中要求了更加清晰的描述使得這些特征能夠唯一標識一個(gè)服務(wù)。
  • 支持對多個(gè)競爭實(shí)現(多個(gè)實(shí)現同一個(gè)接口的類(lèi))的篩選:服務(wù)框架會(huì )幫助你記錄服務(wù)的元數據,可以據此幫助使用者查詢(xún)和篩選服務(wù),使用者更加的主動(dòng),這一點(diǎn)和傳統的依賴(lài)注入框架不同。

    3 什么時(shí)候使用/不使用服務(wù)

  • 可以考慮使用的時(shí)候:
    當你常常想要對主要的組件進(jìn)行替換和升級而不想重寫(xiě)應用的其他部分,或者當你在程序中想要查找和選擇不同的接口實(shí)現的時(shí)候。

  • 不應該使用的時(shí)候:
    服務(wù)的加入和維護往往持續的增加框架的開(kāi)銷(xiāo),所以當你開(kāi)發(fā)的代碼對性能需求敏感的時(shí)候,不要使用服務(wù)。
    顯然它也不應該出現在兩段經(jīng)常一起開(kāi)發(fā)和更新的緊耦合代碼之間,除非你真的需要在自己寫(xiě)的代碼中得到“一個(gè)接口多個(gè)實(shí)現”的選擇權。

最后,如果不確定是否應該使用服務(wù),可以先用面向接口的方式實(shí)現,這至少是和使用服務(wù)很接近了,并且它也能簡(jiǎn)化你的開(kāi)發(fā)。如果哪天你下定決心想把他們移植到服務(wù)層了,在面向接口的基礎上這個(gè)一直工作也會(huì )變得非常容易。

4 OSGi服務(wù)層基礎

首先,需要說(shuō)明的是,OSGi的服務(wù)層除開(kāi)前面提到的面向服務(wù)的編程模型,還有一個(gè)區別于其他很多類(lèi)似模型的特性,那就是服務(wù)的完全動(dòng)態(tài)性。也就是說(shuō),當一個(gè)bundle發(fā)現并開(kāi)始使用OSGi中的一個(gè)服務(wù)了以后,這個(gè)服務(wù)可能在任何的時(shí)候改變或者是消失。這方面的內容將在以后更加深入的講解。
OSGi框架有一個(gè)中心化的注冊表,這個(gè)注冊表遵從publish-find-bind模型:

一個(gè)提供服務(wù)的bundle可以發(fā)布POJO作為服務(wù)的實(shí)體;一個(gè)使用服務(wù)的bundle可以通過(guò)這個(gè)注冊表找到和綁定服務(wù)。
我們可以通過(guò)BundleContext接口來(lái)完成上述的工作,下面就是含有這方面功能的接口列表:

public interface BundleContext {  ...  void addServiceListener(ServiceListener listener, String filter) throws InvalidSyntaxException;  void addServiceListener(ServiceListener listener);  void removeServiceListener(ServiceListener listener);  ServiceRegistration registerService(String[] clazzes, Object service, Dictionary properties);   ServiceRegistration registerService(String clazz, Object service, Dictionary properties);  ServiceRegistration[] getServiceReferences(String clazz, String filter) throws InvalidSyntaxException;  ServiceRegistration[] getAllServiceReferences(String clazz, String filter) throws InvalidSyntaxException;  ServiceReference getServiceReference(String clazz);  Object getService(ServiceReference reference);  boolean ungetService(ServiceReference reference);  ...  }

4.1 發(fā)布服務(wù)

為了讓別的bundle能發(fā)現這個(gè)服務(wù),你必須在發(fā)布它之前對其進(jìn)行特征描述。這些特征包括接口的名字(可以是名字的數組),接口的實(shí)現,和一個(gè)可選的java.util.Dictionary類(lèi)型的元數據信息。下面是一個(gè)例子:

String[] interfaces =  new String[]{StockListing.class.getName(), StockChart.class.getname()};  Dictionary metadata =  new Properties();  metadata.setProperty(“name”, LSE”);  metadata.setProperty(“currency”, Currency.getInstance(“GBP”));  metadata.setProperty(“country”, GB”);  ServiceRegistration registration = bundleContext.registerService(interfaces, new LSE(), metadata);  

在上面的代碼中,我們得到了ServiceRegistration對象,我們可以用這個(gè)對象來(lái)更新服務(wù)的元數據:
registration.setProperties(newMetadata);

也可以直接就把這個(gè)服務(wù)移除:
registration.unregister();

需要注意的是這個(gè)對象不能和其他Bundles共享,因為它和發(fā)布服務(wù)的bundle的生命周期相互依存,也就是說(shuō),如果這個(gè)bundle已經(jīng)不在框架執行環(huán)境中存在,那么這個(gè)對象也不應該存在了,“皮之不存毛將焉附”就是這個(gè)道理。

試想如果這個(gè)ServiceRegistration共享給了其他的bundle(具體的說(shuō)就是其他bundle中存在對這個(gè)對象的引用),那么發(fā)布服務(wù)的那個(gè)bundle即使被移除了,由于其他bundle中的引用依然存在,那么垃圾處理機制不會(huì )抹去這個(gè)對象,這樣不但于理不合,而且實(shí)際上這個(gè)對象也是不可用的,因為這個(gè)對象所依存的bundle已經(jīng)不在了。

代碼中的參數new LSE()是一個(gè)POJO,這個(gè)對象不需要實(shí)現任何OSGi類(lèi)型或者使用標注,只要滿(mǎn)足服務(wù)約定(這里就是接口)就可以了。

此外,如果在刪除發(fā)布的服務(wù)之前bundle停止了,框架會(huì )幫助你刪除這些服務(wù)。

4.2 發(fā)現和綁定服務(wù)

上一小節我們說(shuō)明了如何描述和發(fā)布一個(gè)服務(wù),那么現在我們可以根據服務(wù)約定從注冊表中找到正確的服務(wù)。
下面是發(fā)現服務(wù)并獲得其引用的接口:

ServiceReference reference =  bundleContext.getServiceReference(StockListing.class.getName());   

這是根據實(shí)現的接口名稱(chēng)獲得的服務(wù),也是最簡(jiǎn)單的方法。

注意這里的reference是服務(wù)對象的間接引用,可是為什么要用間接引用而不直接返回那個(gè)實(shí)際的服務(wù)對象呢?實(shí)際上是為了將服務(wù)的使用和服務(wù)的實(shí)現進(jìn)行解耦,將服務(wù)注冊表作為兩者的中間人,達到跟蹤和控制服務(wù)的目的,同時(shí)還可以在服務(wù)消失了以后通知使用者。

這個(gè)方法的返回類(lèi)型是ServiceReference,它可以在bundle之間互享,因為它和使用服務(wù)的bundle的生命周期無(wú)關(guān)。

4.2.1 選擇最適合你的服務(wù)

在getServiceReference這個(gè)方法中,選擇service的默認優(yōu)先級是先選擇service.rank最高的,在rank相等的情況下選擇最早在框架中注冊的。除了這個(gè)默認的規則,我們還可以在 getServiceReferences中通過(guò)添加過(guò)濾參數(作為調用該方法的第二個(gè)參數)來(lái)做一些篩選。

ServiceReference[] references = bundleContext.getServiceReferences(StockListing.class.getName(), “(&(currency=GBP)(objectClass=org.example.StockChart))”);    

在這里的匹配參數是一個(gè)字符串,這個(gè)字符串的格式屬于LDAP查詢(xún)格式,在RFC 1960標準中有完整的描述。

上面的字符串中等號左邊的內容就是前面提到的元數據(Dictionary)中的左值,通過(guò)這個(gè)左值對應的右值來(lái)與服務(wù)所帶有的元數據進(jìn)行匹配。一些簡(jiǎn)單的匹配示例如下:
屬性匹配:
(name=John Smith)
(age>=20)
(age<=65)
模糊匹配:
(name~=johnsmith)
通配符匹配:
(name=Jo*n*Smith*)
判斷某個(gè)屬性是否存在:
(name=)
條件與:
(&(name=John Smith)(occupation=doctor))
條件或:
(|(name~=John Smith)(name~=Smith John))
*
條件非: **
(!(name=John Smith))

4.2.2 綁定和使用服務(wù)

在你發(fā)現了服務(wù)之后,使用服務(wù)之前,你必須從注冊表中綁定實(shí)現的服務(wù)。

StockListing listing = (StockListing) bundleContext.getService(reference);

這個(gè)方法返回的POJO實(shí)例和之前在注冊表中注冊的實(shí)例是同一個(gè)。

每次使用getService方法的時(shí)候,注冊表會(huì )將對應服務(wù)的使用次數加1,同時(shí)會(huì )記錄誰(shuí)在使用這個(gè)服務(wù)。所以當你不在想使用這服務(wù)的時(shí)候,最好告訴注冊表一聲。

bundleContext.ungetService(reference);  listing = null;    

給出第二條語(yǔ)句的目的并不是為了通知注冊表,而是為了讓java的垃圾處理機制安全運作。因為這里我們用了一個(gè)局部變量listing來(lái)作為服務(wù)對象的一個(gè)引用,(不妨假設listing是最后一個(gè)引用這個(gè)對象的變量),如果我們不設為null,那么在這個(gè)listing消亡之前,那個(gè)服務(wù)對象有可能不會(huì )被垃圾處理掉(即使在程序邏輯上這個(gè)服務(wù)對象已經(jīng)是“垃圾”了),這可能會(huì )引發(fā)一些問(wèn)題。

不過(guò),這種用局部變量引用服務(wù)對象的方式本來(lái)就不對。一般來(lái)說(shuō),還是應該在每次需要使用的時(shí)候臨時(shí)從ServiceReference獲得,并且要考慮到這個(gè)服務(wù)在任何時(shí)候都有可能消亡。

5 總結

至此,三個(gè)層次的基礎性講解已經(jīng)全部結束了。三篇入門(mén)級文檔以后,相信讀者對OSGi框架已經(jīng)有了一個(gè)大致的了解,接下來(lái)建議大家配合《OSGi開(kāi)發(fā)環(huán)境的建立和HelloWorld》這篇文檔自己實(shí)際操作一下之前講到的一些內容,鞏固一下這個(gè)系列的知識,為接下來(lái)的進(jìn)階篇內容做好準備。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
spring+osgi 動(dòng)態(tài)模型三:服務(wù)注冊表(The Service Registry)續
ChrisRc
基于 OSGi 服務(wù)模型實(shí)現組件之間松耦合通信
osgi框架基礎原理與實(shí)例一
OSGi: Eclipse的根基
OSGI Equinox 環(huán)境搭建
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久