今天主要講一下在osgi環境下的服務註冊、和服務引用。java
其實osgi只是一個java動態化、模塊化的一系列規範,根據不一樣廠商制定了不一樣的規範,如Felix和Equinox則分別是Apache和Eclipse開源社區給出的標準規範的實現!而osgi的魅力也在於動態化和模塊化,我我的認爲要實現動態化最簡單的就是經過classload動態加載。我我的理解而已,osgi只是在傳統開發的基礎上抽象了一個bundle組件的概念,每個bundle組件都有本身的生命週期,bundle實現動態化是基於bundle classloader實現的。理論性的東西我不想講太多,你們能夠去看一下osgi基礎方面的東西,如bundle生命週期,bundle classloader等內容。而服務的註冊,服務的引用等內容偏偏是bundle生命週期最好的詮釋!spring
先說一下osgi環境下的服務註冊,其實這部份內容在第二講的時候已經大概說過一點兒,此次咱們講解一下傳統的osgi服務註冊和使用框架的方式來註冊等。apache
一個bundle被部署到osgi容器裏有幾個最要的階段也能夠稱之爲bundle的生命週期,主要包括 INSTALLED(調用BundleContext.installBundle()後,會建立一個INSTALLED狀態的bundle)、RESOLVED(若是其所依賴的全部bundle都存在,即解析成功,轉到RESOLVED狀態)、STARTING(當開始執行BundleActivator.start(),則處於STARTING狀態)、ACTIVE(當執行BundleActivator.start()成功,則轉到ACTIVE狀態)、STOPPING(當開始執行BundleActivator.stop(),則處於STOPPING狀態)、UNINSTALLED(INSTALLED狀態的bundle能夠被卸載,轉到UNINSTALLED狀態)。框架
能夠看到一個bundle的整個生命週期都離不開BundleActivator和BundleContext 這兩個類。maven
BundleContext:Bundle上下文,主要功能是與OSGI容器交互,包括服務的註冊,監聽器的註冊,獲取osgi下全部發布的服務,服務的引用等功能。建議你們好好的看一下這個類。ide
BundleActivator:BundleActivator是osgi提供的一個獲取BundleContext的接口,同時提供bundle啓動和中止的處理方法。模塊化
知道這兩個類咱們就能夠實現BundleActivator 在bundle啓動的時候經過BundleContext註冊服務到osgi容器裏以供其它bundle調用了。測試
實現一個自定義的BundleActivator :ui
public class HelloServiceActivator implements BundleActivator { ServiceRegistration serviceRegistration; @Override public void start(BundleContext context) throws Exception { HelloService helloService = new HelloServiceImpl(); serviceRegistration = context.registerService(HelloService.class.getName(), helloService, null); } @Override public void stop(BundleContext context) throws Exception { serviceRegistration.unregister(); } }
在這個bundle啓動的時候咱們經過實現BundleActivator裏的start方法 實例化一個服務類並經過BundleContext的registerService註冊到osgi容器裏,分別傳入服務名稱,服務實例,服務別名(能夠理解爲這個的tag標籤),經過stop方法註銷到這個服務。插件
完成這一步後咱們還在MANIFEST.MF(Bundle元數據描述文件,定義此Bundle依賴的jar包,導入和導出的包等基礎元數據)定義Bundle-Activator爲咱們本身的Activator
Bundle-Activator:com.osmp.demo.HelloServiceActivator
這樣咱們在將此bundle部署到osgi容器的時候在bundle啓動的時候就會將HelloService註冊到osgi容器裏供別的bundle服務調用。再簡單的說一下bundle服務的引用。與發佈基本相同,在啓動的時候經過start方法獲取到bundle上下文,經過BundleContext獲取ServiceReference 服務引用,再經過此類獲取咱們須要的服務引用,代碼以下:
public class Activator implements BundleActivator { ServiceReference helloServiceReference; public void start(BundleContext context) throws Exception { System.out.println("Hello World!!"); helloServiceReference=context.getServiceReference(HelloService.class.getName()); HelloService helloService=(HelloService)context.getService(helloServiceReference); System.out.println(helloService.sayHello()); } public void stop(BundleContext context) throws Exception { System.out.println("Goodbye World!!"); context.ungetService(helloServiceReference); } }
以上部分寫到一大半的時候,想找兩個例子,結果發現 http://longdick.iteye.com/blog/457310 這篇文章講的很好,你們能夠看一下,我也就再也不專門講解了。
我就說一下在osmp裏是怎麼實現服務的註冊和服務的發現和服務路由的。
osmp裏服務的發佈咱們是經過spring-dm來發布的,代碼很簡單,
spring配置文件裏引入spring-osgi的schema,經過 <osgi:service>標籤來將服務發佈到osgi容器裏,配置文件以下:
<?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:context="http://www.springframework.org/schema/context" 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/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi-1.2.xsd"> <context:component-scan base-package="com.osmp.demo.service"> </context:component-scan> <bean id="jdbcDao" class="com.osmp.jdbc.support.JdbcDao"></bean> <bean id="osmp.demo.service" class="com.osmp.demo.service.TestServiceImpl" /> <osgi:service interface="com.osmp.intf.define.service.BaseDataService" ref="osmp.demo.service"> <osgi:service-properties> <entry key="name" value="osmp-demo" /> <entry key="mark" value="測試DEMO" /> </osgi:service-properties> </osgi:service> </beans>
pom.xml 裏依賴
<dependency> <groupId>org.springframework.osgi</groupId> <artifactId>spring-osgi-core</artifactId> </dependency> <dependency> <groupId>org.osgi</groupId> <artifactId>org.osgi.core</artifactId> </dependency>
pom.xml將工程打包爲bundle,須要使用到 maven-bundle-plugin 這個插件:
<build> <plugins> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <extensions>true</extensions> <configuration> <instructions> <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName> <Export-Package></Export-Package> <Import-Package> org.springframework.aop, org.springframework.aop.framework, org.springframework.cglib, org.springframework.cglib.proxy, org.springframework.cglib.core, org.springframework.cglib.reflect, org.aopalliance.aop, org.aopalliance.intercept, *;resolution:=optional </Import-Package> </instructions> </configuration> </plugin> </plugins> </build>
PS:
一、配置文件引入spring-osgi xmlns:osgi="http://www.springframework.org/schema/osgi" http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi-1.2.xsd
二、osgi:service-properties 標籤對應 上面講到的context.registerService()方法的第三個參數。個人理解是給這個服務打上tag標籤,以k/v鍵值對的形式。
三、maven-bundle-plugin打bundle時,我這裏使用的servicemix做爲osgi容器,已經集成了spring,此時須要將spring的包顯示的引入進來。這裏比較坑的是我本來覺得經過*;resolution:=optional能自動的將須要依賴的包給import進來,可是試過屢次發現,只有在代碼裏顯示的import的包纔會被自動的引進去,如配置文件裏依賴的包是不會自動的import進來的,並且只能一級一級的import進來。
四、spring-dm 服務引用經過<osgi:reference>這裏不做詳講。
上面的例子能夠查看osmp-demo源碼!!!!