OSGI中的service依賴關係管理

beifengwang發表於2014-08-27

眾所周知,對於高動態高可擴充套件的應用,OSGI是一個非常好的平臺。但是,也因此增加了複雜性,開發中對service的依賴變得複雜。這也是service的關係管理成為OSGI中一個非常重要的部分,我們來看看OSGI中service依賴關係管理的方式。篇幅原因,只關注發展歷程,不具體介紹每個方式的詳細實現細節。

概括的說,目前在OSGI中主要有以下幾種service依賴關係管理的方法:

1. Service listener
2. Service binder
3. Dependency Manager
4. Declarative Services
5. iPOJO
6. blueprint

1) Service Listener

這是OSGI中原生的service依賴管理機制,是最簡單直接的方式,其基本原理非常簡單,標準的註冊/查詢:

1. 被依賴的bundle透過BundleContext.registerService()方法註冊服務到系統中
2. 使用依賴的bundle在start時透過BundleContext的getServiceReferences()/getService()來查詢依賴的service
3. 使用依賴bundle透過BundleContext.addServiceListener()來分別註冊ServiceListener
4. 在被依賴的bundle/service狀態發生變化時, 使用依賴bundle透過ServiceListener的serviceChanged()得到通知並作出調整。

在這種方法中,使用依賴的Service必須進行大量的編碼工作來完成對依賴的service的關係管理,需要處理瑣碎細節如各個Service的執行時狀態變化。為了減少工作量,OSGI設計了ServiceTracker來簡化對依賴service的編碼工作,即ServiceTracker將負責處理上述步驟中的2/3/4。

經過ServiceTracker最佳化後的Service Listener機制,還是存在一些缺點:

1. 編碼量還是不小,尤其對於依賴較多的場景

2. Activator 還是太複雜了,儘管已經很努力的試圖簡化
對於一些業務邏輯簡單的service,如果依賴的service比較多,那麼Activator的邏輯和程式碼實現遠比service本身的邏輯和實現要複雜,這違背了我們使用框架簡化開發的初衷。

3. Activator對測試不利
這個是Activator的複雜性造成的,由於Activator中存在大量的依賴處理邏輯,理所當然的會增加測試的複雜性。

總結說,Service Listener 機制下,管理service依賴對於開發者來說完全是個重體力活: 很重要,經常要做,容易出現錯誤, 出錯時不容易測試。而且,這些工作都不是service 業務邏輯的組成部分,不能帶來直接收益。簡言之,吃力不討好,一不小心就搬石頭砸自己的腳。

更重要的,從分工的角度上將,開發人員應該將更多的精力投入與應用的邏輯,而不是OSGI的底層實現機制。因此,從2000之後,就陸續有人開始考慮對此改進。

2) Service binder

Service binder OSGI針對這個問題的一個嘗試,基本出發點非常明確:希望找到一個通用的方法來簡化OSGI下的動態service依賴管理.

最初開始這個工作的是兩位大牛,Richard S. Hall和Humberto,大概在2002年的時候開發完成。

看我們看Service binder是怎麼做的,基本步驟為:

1. 提供一個org.apache.felix.servicebinder.GenericActivator;
現在bundle的Activator只要簡單的繼承GenericActivator就可以了,所有的程式碼實現在GenericActivator提供,減少程式碼的目標順利達成。這個可以說足夠簡單到沒有辦法再簡單了。
2. 透過metadata.xml 來實現service的依賴注入

3. 具體的service的實現類基本就是一個乾淨的POJO了
當然還是需要實現bind-method/unbind-method 兩個方法,好在這個是透過metadata.xml來做對映,不是另外提供介面定義,因此勉強避開了"侵入"的問題。

Service binder 機制在減少Activator方面成效顯著,但是引入的metadata.xml檔案似乎又帶來了新的問題,xml配置檔案的可維護性個人感覺值得懷疑。用過EJB的同學都明白,EJB的部署檔案有多令人煩惱。

當然Service binder 的思路非常的正確:透過引入了自動化的service依賴關係管理,簡化開發,允許開發人員可以集中精力在service的實現上,而不是疲於處理依賴關係管理。

Service binder的實現似乎並沒有被推廣開,因為很快OSGI就在2004年的OSGI R4規範中引入了Declarative Services。因此Felix也就終止了對Service binder的後續支援。

3) Dependency Manager

繼Service binder之後,Felix又提供了名為Dependency Manager 的service依賴管理方式,對比Service binder,個人感覺這個Dependency Manager 只是針對Service binder的一個改進:將metadata.xml 檔案取消,由新引入的DependencyManager來實現metadata.xml 檔案的功能。原來在metadata.xml 檔案中的配置轉變為在Activator中透過程式碼呼叫DependencyManager來實現.

Dependency Manager其實現的方式為:

1. 提供org.apache.felix.dependencymanager.DependencyActivatorBase
bundle的Activator需要繼承DependencyActivatorBase,並實現DependencyActivatorBase要求的init()/destroy()方法
2. 在init()中,可以透過DependencyManager 物件來註冊服務,並註明依賴。

3. 具體的Service類可以是POJO,DependencyManager 透過反射來注入依賴的service。

Felix 官方給出了一個Dependency Manager的使用示例

從示例上看,對service的依賴管理已經簡化了許多。

這裡還有一個05年的介紹Dependency Manager的 presentation:

4) Declarative Services

2004年釋出的OSGi的4.0版本中,加入了Declarative Services,據說是從Service Binder進化而來。

Declarative Services的實現方式和Service Binder的確非常相似:

1. 同樣是需要一個xml檔案來配置
在 bundle manifest中增加Service-Component 的header
提供的功能和Service Binder很類似,配置方法也很接近。

2. 同樣的提供bind/unbind 方法的配置
對於每個依賴的service,都可以在配置檔案中透過指定bind/unbind 方法來處理依賴的狀態變化。

此外,Declarative Services 提供兩個特殊的lifecircle方法:
protected void activate(ComponentContext context)
protected void deactivate(ComponentContext context)
如果service實現類提供了這兩個方法,則Declarative Services 會自動識別並呼叫這兩個方法。注意這兩個方法沒有介面定義進行強約束,只是一個約定而已,估計是為了避免OSGI對service的侵入。

Declarative Services 是OSGI規範的一部分,因此Declarative Services的支援自然是各個OSGI實現都提供的。

從功能上將,Declarative Services 基本已經不錯了,但是大牛們的腳步並未就此停住。

5) iPOJO

2005年,Richard 開始考慮使用位元組碼生成技術來進行建立組合服務的改進,另外一個牛人Peter Kriens也同樣的工作並實現了一個原型。
2006年,Clement Escoffier 和 Richard 開始開發iPOJO,合併了Peter Kriens之前的工作內容,這就是iPOJO的由來。

對於iPOJO的定義,Felix的iPOJO頁面有如下說明:iPOJO是一個伺服器元件執行時,目標在於簡化OSGI應用開發。原生支援所有的OSGI活力。給予POJO的概念,應用邏輯開發簡單。非功能性的屬性在執行時被注入到元件中。

同樣看看Felix對iPOJO優點的說明:

1. 元件被作為POJO開發,不需要其他任何東西
2. 元件模組是可擴充套件的,因此可以自由的適應需要
3. 標準元件模型管理service 供應和service 依賴,所以可以要求其他任何OSGI服務來建立組合服務,
4. iPOJO管理元件例項的生命週期和環境動態
5. iPOJO提供一個強力的組合系統來建立高度動態的應用
6. iPOJO支援註解,xml或者基於Java的API來定義元件

可以看到iPOJO的功能遠比之前的幾個解決方案要強大,除了支援Declarative Services已經實現的功能外,還提供了強大的註解支援,而且實現了組合系統,這些對於開發大型的複雜應用時非常有用的。

Richard 在他的presentation談到iPOJO 的設計思路:

1. Make things simple / 讓事情簡單
2. Follow POJO philosophy / 遵循POJO的哲學
3. Employ byte code manipulation techniques / 使用位元組碼操縱技術
4. Be as lazy as possible / 儘可能的偷懶

目前的iPOJO還在繼續發展中,最新的一個版本iPOJO 1.6.0在2010-04-25釋出。
6) blueprint

blueprint 是OSGI為了解決上述問題的最新嘗試,在去年剛釋出的OSGI v4.2 規範中新加入了 Blueprint Container 的規範內容。

提到blueprint 就不能不提到spring Dynamic Modules,blueprint 可以認為是Spring Dynamic Modules版本的改進和標準化。SpringDM 1.x版本實現了Spring Dynamic Modules for OSGi,在Spring Dynamic Modules被標準化為Blueprint Container 規範後,新的SpringDM 2.x 則成為Blueprint的參考實現。

blueprint 的使用實行非常類似標準的spring IOC容器,比如同樣的使用xml配置檔案,只是從ioc 的applictionContext xml變成了Blueprint XML。而Blueprint XML的配置方式和spring 有驚人的相似。
舉例,最簡單的bean:

基本就是照搬spring IOC的方式,對於熟悉spring的開發人員來說無疑是個好訊息,起碼學習曲線平緩了。

由於是OSGI的標準規範,blueprint 目前的支援還是不錯的,除了上面說的SpringDM外,還有Geronimo Blueprint Container 和 Apache Felix Karaf 都提供了對blueprint的支援。

總結,從上述的發展歷程上看,OSGI中的service依賴關係管理方式,經歷了從簡單原始到逐漸成熟強大的過程,前後經歷了大概10年的時間.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29212814/viewspace-1258935/,如需轉載,請註明出處,否則將追究法律責任。

相關文章