OSGi的CM就是Configuration Admin Service,是用于管理Bundle屬性、并在屬性發(fā)生變更時通知相應(yīng)的Service,可以看出,這是保持OSGi動態(tài)性的很關(guān)鍵的一個服務(wù),畢竟配置屬性的修改是會發(fā)生的,象修改了Http的端口呀等,但又不希望修改這些屬性后需要重啟才能生效,那么CM是一個不錯的選擇,使用CM時無需關(guān)心屬性具體怎么存儲這些問題,而在屬性修改后CM也會自動通知相關(guān)的service。
通常在系統(tǒng)的屬性管理上,我們的需求通常是在一個統(tǒng)一的界面上對系統(tǒng)的相關(guān)屬性進行統(tǒng)一的配置,保存后則希望能通知相應(yīng)的服務(wù),這里面的屬性自然有些是公用的,有些是某些模塊專用的,既然基于CM來實現(xiàn)這樣的需求,首先來看看基于CM需要怎么去做,這是基于CM的統(tǒng)一管理系統(tǒng)屬性的典型的序列圖:

其中ConfigurationAdminService、ManagedService均為CM中定義的規(guī)范的服務(wù)接口,而ConfigManageAction就是用于實現(xiàn)統(tǒng)一管理屬性配置的web響應(yīng)接口了,根據(jù)上圖可以看出,通過調(diào)用ConfigurationAdminService的getConfiguration方法可以獲取到Configuration對象,通過這個對象可以獲取到配置的屬性集合,而通過Configuration對象的update方法就可以更新屬性了,ConfigurationAdminService在更新屬性時將異步的調(diào)用系統(tǒng)中對外提供了ManagedService的服務(wù)的update方法,該方法的參數(shù)即為更新的屬性的集合。
首先要說明下CM對于屬性是怎么進行存儲的,CM對于屬性的存儲是根據(jù)服務(wù)注冊時提供的service.pid的值(必須是唯一的)以及Bundle Location(Bundle的地址)構(gòu)成key來存儲其屬性的,按照這樣的過程,在維護屬性時自然也要以這個為Key來進行操作,同樣的,在通知屬性更新時CM也是根據(jù)這個key的值來決定的,但實現(xiàn)ManagedService的服務(wù)只能傳入service.pid這個值,Bundle Location的值CM將自動的獲取該服務(wù)所屬的Bundle的Location,這看似設(shè)計的很好,但同時在應(yīng)用層面則帶來了一個問題,后面將會講到。
假設(shè)我們的需求是這樣的:
1、A Bundle中的PortService的port屬性需要管理,BookService的bookcount屬性需要配置;
2、B Bundle中的PortConfigService的port屬性需要管理,MenuService中的menucount屬性需要配置;
3、其中A Bundle中的PortService所需的port和B Bundle中的PortConfigService所需的port屬性是相同的;
4、屬性統(tǒng)一在C Bundle中通過提供web界面的管理方式來實現(xiàn),在屬性發(fā)生變化時要通知相應(yīng)Bundle的Service。
那么根據(jù)上面對于CM的講解我們來實現(xiàn)這個需求:
1、PortService、BookService、PortConfigService、MenuService均需實現(xiàn)ManagedService接口,ManagedService接口中只有一個方法update(Dictionary props),當(dāng)service關(guān)注的屬性被更新時CM將會自動的通知,然后服務(wù)根據(jù)屬性自行的做出相應(yīng)的處理;
2、PortService、BookService、PortConfigService、MenuService對外提供ManagedService接口,在注冊時提供service.pid屬性的值,這個值必須是唯一的,假設(shè)分別為a.port、a.bookservice、b.port、b.menuservice;
3、實現(xiàn)ConfigManageAction,配置頁面上自然是只有port、bookcount和menucount三個屬性需要配置的了,由于CM是采用service.pid加上Bundle的Location來構(gòu)成key的,而在通知屬性更新上也是根據(jù)這個key來決定,那么這其實也就已經(jīng)意味著ConfigManageAction在管理這幾個屬性時必須帶上相應(yīng)的Bundle的Location了,這是不太合理的地方,首先要獲取Bundle的Location是比較麻煩的事,其次是這樣也就意味著ConfigManageAction是必須知道當(dāng)屬性變更時需要通知到哪些Bundle的,如果將來增加一個Bundle的服務(wù)需要監(jiān)聽某已經(jīng)存在的屬性的話,就必須要修改ConfigManageAction的代碼,當(dāng)然,這和注冊的服務(wù)監(jiān)聽的server.pid的屬性必須唯一也有關(guān),也就是說CM其實只是一個基于Event的一對一的訂閱/發(fā)布模型,這就導(dǎo)致了在維護一個port這樣的公共屬性的時候竟然要在A Bundle的PortService和B Bundle的PortConfigService中各存一份,OSGi聯(lián)盟對于此的解釋是出于安全問題的考慮,所以在CM的設(shè)計上采取了加上Bundle Location做為Key的原因。
在這樣的情況下,也就導(dǎo)致了ConfigManageAction變得復(fù)雜了......
CM在這塊設(shè)計上欠缺對于應(yīng)用級屬性(共享配置屬性)上的考慮絕對是有待商討的,現(xiàn)在只能是在各個Bundle中各自維護一套,同時在各自Bundle中提供一個ConfigManageService這樣的服務(wù)來更新當(dāng)前Bundle中的屬性,這樣才能解決Bundle Location的那個問題,在目前的情況下就沒法構(gòu)成共有屬性的維護方式了,如果是公有屬性變化的話也就只有在ConfigManageAction中調(diào)用相關(guān)的多個Bundle的ConfigManageService來完成屬性的修改了,這樣的話存儲和動態(tài)的通知仍然交由CM去完成了。
關(guān)于模塊的耦合上只有個小小的想法討論下,就是做為設(shè)計師你能否很快的告訴別人搭建你其中的一個模塊的工程需要哪幾個模塊的支撐,或者最好就是運行檢驗?zāi)闫渲械囊粋€模塊的功能需要哪幾個模塊來支撐,當(dāng)然,這個在基于OSGi的系統(tǒng)更容易來做到,不過這個確實是設(shè)計時很關(guān)鍵的一個地方,這既反映了系統(tǒng)中模塊的耦合性,更體現(xiàn)了系統(tǒng)的擴展性以及系統(tǒng)的組裝耦合上是否合理。