隨筆-1  評論-9  文章-7  trackbacks-0

                  在讀本文之前,您應該對基于Equinox的開發有一定的了解,如果您還不太清楚,請參考基于Equinox開發HelloWorld一文。
                  
                  本文講到的例子是仿照網上甚為流行的一個例子,但苦于一直未找到源碼,網上貼的都是一些轉帖,代碼片段,估計初學者很難將其還原并調通!我最開始弄這個咚咚的時候,其過程之痛苦,難以言喻,所以想著仿照該例子的設計,給予實現,文后貼出源碼,希望能幫到大家。
                  該例子是一個關于計算器的實例,osgi.example.compute bundle(下文簡稱compute bundle)提供了統一的計算接口:Compute,另外兩個bundle分別為osgi.example.compute.add(下文簡稱add bundle)和osgi.example.compute.multiply(下文簡稱multiply bundle),在這兩個bundle中,各自對compute bundle進行不同的實現,一個實現加法,一個實現乘法。另外還有一個服務消費者osgi.example.compute.consumer bundle(下文簡稱consumer bundle),consumer bundle負責消費add bundle和multiply bundle提供的服務。上述4個bundle之間的關系如下圖所示:

                  創建4個bundle之后的工程目錄如下圖所示:


                通過該示例,將演示如何利用Spring DM發布和調用OSGi服務,同時還將演示OSGi的動態服務調用能力。

          1.   bundle osgi.example.compute 
                compute bundle只提供一個接口——Compute,因此無需依賴更多的bundle,只需最基本的osgi即可。因為不涉及注冊資源之類的,所以也無需Activator入口類。
          Computer接口源代碼如下所示:

          package osgi.example.compute;   
            
          public interface Compute {   
              
          public String computeNums(int x, int y);   
          }
            

          2.    bundle osgi.example.compute.add

                  add bundle是對compute bundle的具體服務實現,在MANIFEST.MF文件需要引入osgi.example.compute包;當然也可以通過添加依賴bundle的形式,即不引入包,而直接在Required Plug-ins中添加compute bundle。如下圖所示:


          注意:OSGi官方指出,當需要用到其他bundle的類型時,不提倡依賴bundle,應該盡可能采用Import-package的方式引入包,因為依賴bundle可能在加載bundle的時候發生問題。


          add bundle的工程結構如下圖所示:

           

                 通過引入osgi.example.compute包,osgi.example.compute  bundle被加到了add bundl的classpath當中,解決了開發時期的類型識別問題。
          這樣一來,在add bundle中就能使用compute bundle中的接口了,Computer接口的實現如下:

          package osgi.example.compute.add;   
            
          import osgi.example.compute.Compute;   
            
          public class Add implements Compute {   
            
              
          public String computeNums(int x, int y) {   
                  
          int s = x + y;   
                  String result 
          = "The Sum is---" + String.valueOf(s);   
                  
          return result;   
              }
             
          }
            

                  Compute的實現已經實現了,那么如何將其發布出去呢?這個是由Spring DM負責,Spring DM利用OSGi命名空間下的<service>元素將bean導出為OSGi服務。最簡單的形式為:

          <beans:bean id="beanToPublish" class="com.xyz.imp.MessageServiceImp"/>   
          <service ref="beanToPublish" interface="com.xyz.MessageService"/> 

                  從示例中可以看出,beanToPublish被service元素聲明導出。
          另外,service結點還有一些高級屬性,如depends-on、context-class-loader、ranking等待,詳情請看spring dm reference。
                  首先,需要在add bundle的工程根目錄下的”META-INF”的文件夾下創建一個文件夾,取名”spring”,Spring DM能夠自動解析該文件夾下所有的spring配置文件。spring配置文件的具體內容如下所示:

          <?xml version="1.0" encoding="UTF-8"?>   
          <beans xmlns="http://www.springframework.org/schema/beans"  
              xmlns:xsi
          ="http://www.w3.org/2001/XMLSchema-instance"    
              xmlns:osgi
          ="http://www.springframework.org/schema/osgi"  
              xsi:schemaLocation
          ="http://www.springframework.org/schema/beans                         http://www.springframework.org/schema/beans/spring-beans.xsd   
                                  http://www.springframework.org/schema/osgi                          http://www.springframework.org/schema/osgi/spring-osgi.xsd">   
              <bean id="addOsgiService" class="osgi.example.compute.add.Add">   
              
          </bean>   
              
          <osgi:service id="addService" ref="addOsgiService"  
                  
          interface="osgi.example.compute.Compute">   
              
          </osgi:service>   
          </beans>  
                  如此一來,其他bundle就能通過spring dm引入接口類型為osgi.example.compute.Compute的服務了,spring dm將通過一定的服務查找策略,返回匹配的服務。

          3.    bundle osgi.example.compute.multiply

          該bundle和add bundle相似,在這就不贅述了。
          4.    bundle osgi.example.compute.client

                  顧名思義,該bundle將作為add 、multiply兩個bundle的客戶bundle,演示如何導入服務。
                  OSGi的測試工作比較麻煩,這方面還沒研究,在這里利用spring實例化bean的時期,從構造函數入手,對服務進行測試。Client類的實現很簡單,如下所示:

          package osgi.example.client;   
            
          import osgi.example.compute.Compute;   
            
          public class Client {   
              
          /**  
               * 為了方便測試,采用Spring的構造注入方式,直接在構造函數中調用Compute服務  
               * 
          @param compute  
               
          */
            
              
          public Client(Compute compute){   
                  System.out.println(compute.computeNums(
          56));   
              }
             
          }
            

                另外,因為client用到了其他幾個bundle的類型,所以需要導入相應的包,步驟在上面已有講到。
                spring dm靠<reference>元素來引入服務,最簡單的形式如下所示:

          <reference id="beanToPublish" interface="com.xyz.MessageService"/>  

                如果需要用到該服務,如某個bean包含一個com.xyz.MessageService屬性,則配置該bean如下所示:

          <bean id="referenceBean" class="com.nci.ReferenceBean">   
              
          <property name="messageService" ref="beanToPublish"/>   
          </bean>  
                reference元素還有一些高級屬性,詳情請見spring dm reference。
               看一下client的spring配置文件:
          <?xml version="1.0" encoding="UTF-8"?>   
          <beans xmlns="http://www.springframework.org/schema/beans"  
              xmlns:xsi
          ="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi"  
              xsi:schemaLocation
          ="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd   
                                http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd">   
            
              
          <bean id="OSGiClient" class="osgi.example.client.Client">   
                  
          <constructor-arg ref="ComputeService">   
                  
          </constructor-arg>   
                          
          </bean>   
                          
          <osgi:reference id="ComputeService" interface="osgi.example.compute.Compute" cardinality="1..1">   
                          
          </osgi:reference>   
          </beans>   
                 從上面的示例,我們可以發現,服務的導出的時候都是基于接口的,服務的引用也是基于接口的,不過spring dm支持基于類的導出、導入,但是還是建議盡量基于接口,應該記住面向接口編程的思想,以應對將來有可能發生的改變。

          5.    運行
                由于add和multiply都是基于Compute接口對外導出服務,那么Client到底導入的是哪個服務呢?默認情況下,會導入啟動較早的bundle服務(OSGi在bundle啟動時,會為其分配一個ID值,啟動越早,該值越小)。
                運行之前,我們需要做這么一件事,在window->preferences->plug-in development->Target Platform面板中,將Target指定為Spring DM…,如下圖所示:

                  之后就可以配置運行了,隨便在一個bundle工程上右鍵,Run As->Run Configurations,新建一個OSGi Platform運行項(右鍵OSGi Platform即可),如下圖所示:

                 需要勾選中spring bundle版(2.5.6),spring dm的幾個核心包:core、extender、io再點validate bundles按鈕,校驗是否已全部選中其依賴的bundle。然后即可點擊運行了。
                 運行之后,我們發現控制臺輸出結果:
          The Sum is---11
          通過ss命令,如下:
          5 ACTIVE      osgi.example.compute.multiply_1.0.0
          6 ACTIVE      osgi.example.compute.add_1.0.0
          7 ACTIVE      osgi.example.compute.client_1.0.0
          將6停掉:stop 6
          然后再refresh 7,控制臺輸出如下結果:
          The Multiply is---30
          通過 ss 命令,如下:
          5 ACTIVE      osgi.example.compute.multiply_1.0.0
          6 RESOLVED    osgi.example.compute.add_1.0.0
          7 ACTIVE      osgi.example.compute.client_1.0.0
          現在multiply處于運行狀態,而add已經被停止,所以client導入的服務實際是由multiply提供的。

          6. 總結 

                 通過該文檔,我們已經清楚了,如何使用Spring DM導出、導入服務。Spring DM的一些高級特性請查閱spring dm reference。


          附件:osgi.example.compute.rar

          posted on 2010-03-28 17:36 Dreava 閱讀(12096) 評論(9)  編輯  收藏 所屬分類: OSGi

          評論:
          # re: Spring DM的開發示例 2011-02-21 10:50 | sgwood
          有些受啟發,謝謝!  回復  更多評論
            
          # re: Spring DM的開發示例[未登錄] 2011-05-10 13:26 | peter
          期待有web開發的例子
          QQ:404089478  回復  更多評論
            
          # re: Spring DM的開發示例 2011-06-29 11:49 | 小鄭
          剛接觸,我怎樣用DM開發一個WEB項目呢?QQ:99134194  回復  更多評論
            
          # re: Spring DM的開發示例 2011-12-14 15:51 | qchen
          感謝分享  回復  更多評論
            
          # re: Spring DM的開發示例 2012-10-29 17:33 | 南云
          spring的bean聲明配置文件和osgi發布文件應該分別放在兩個文件中。。


          分別是 模塊-spring.xml 和 模塊-spring-osgi.xml  回復  更多評論
            
          # re: Spring DM的開發示例 2012-11-23 11:05 | laidianren
          很不錯,辛苦了。  回復  更多評論
            
          # re: Spring DM的開發示例[未登錄] 2013-01-23 22:11 | fly
          不錯啊 很好,跑成功了。  回復  更多評論
            
          # re: Spring DM的開發示例[未登錄] 2013-10-06 13:58 | xxx
          中間配置<service>還是不懂。沒看會。  回復  更多評論
            
          # re: Spring DM的開發示例 2013-10-14 14:49 | Jaken.Cooper
          運行前:
          在window->preferences->plug-in development->Target Platform面板中
          設置的根本不是那張圖顯示的,沒有選擇Pre-defined Targets的地方,
          我的Target Platform里面只有 Running Platform(Active)這個列表
          所以在OSGI Framework里面也選不了spring的組件

          請問下,這種情況怎么解決啊?謝謝了

          PS:我的PDE版本是3.7的  回復  更多評論
            

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 革吉县| 平阳县| 资溪县| 威信县| 宁陕县| 民权县| 永吉县| 瑞丽市| 台南县| 曲沃县| 连州市| 隆安县| 广河县| 阿图什市| 焦作市| 云阳县| 舞阳县| 威海市| 镇江市| 白城市| 隆林| 夹江县| 吉安市| 建平县| 娱乐| 峡江县| 祁连县| 仁化县| 右玉县| 兴文县| 丰镇市| 永城市| 旬邑县| 昌图县| 东安县| 漾濞| 鄂尔多斯市| 泽库县| 丰宁| 密山市| 松原市|