不可免俗,一律HelloWorld!
因為OSGI有三層,module,lifecycle,service,所以我們用三個helloworld來示範三個層。
1.Module Layer:
Module層沒有代碼要寫,只是將代碼打包到bundle。
比如,我們要將下邊這個類放到bundle裡。
package org.foo.hello;public class Greeting {final String m_name;public Greeting(String name) { m_name = name;}public void sayHello() { System.out.println("Hello, " + m_name + "!");}}
將這個類匯出到org.foo.hello.jar,並在這個jar的META-INF/MANIFEST.MF檔案裡添加
Bundle-ManifestVersion: 2
Bundle-Name: Greeting API
Bundle-SymbolicName: org.foo.hello
Bundle-Version: 1.0
Export-Package: org.foo.hello;version="1.0"
對於想要使用上邊建立的這個bundle的bundle,需要在它的jar包的META-INF/MANIFEST.MF裡添加
Bundle-ManifestVersion: 2
Bundle-Name: Greeting Client
Bundle-SymbolicName: org.foo.hello.client
Bundle-Version: 1.0
Import-Package: org.foo.hello;version="[1.0,2.0)"
可以看到一個是export,一個是import。
2.Lifecycle層
如果一個bundle需要做一些初始化工作,比如串連資料庫,這時lifecycle層就有用武之地了。Bundles可以頂一個 activator,這個可以讓我們介入到一個bundle的生命週期裡。這個後來會詳細再說,現在先看看這貨大概怎麼工作。下邊這個是一個單例模式的greeting類。
package org.foo.hello;public class Greeting {static Greeting instance;final String m_name;Greeting(String name) { m_name = name;}public static Greeting get() { return instance;}public void sayHello() { System.out.println("Hello, " + m_name + "!");}}
它在使用前需要調用建構函式來初始化name參數。我們看一下如何利用activator來初始化:
package org.foo.hello;import org.osgi.framework.BundleActivator;import org.osgi.framework.BundleContext;public class Activator implements BundleActivator {public void start(BundleContext ctx) { Greeting.instance = new Greeting("lifecycle");}public void stop(BundleContext ctx) { Greeting.instance = null;}}
start和stop都是介面BundleActivator的方法,還有方法的參數BundleContext,是一個重要的參數,後面會詳細講,這貨就是你的bundle和整個OSGI系統互動用的。
這個例子就是讓你知道一個bundle可以介入自己的lifecycle,而且可以和整個OSGI framework互動。
另外你需要在你的META-INF/MANIFEST.IM裡加上
Bundle-Activator: org.foo.hello.Activator
Import-Package: org.osgi.framework
這樣OSGI framework就知道你有了自己的activator了。
3.Service層
service層是基於介面的實現方式,比如
介面:
package org.foo.hello;public interface Greeting { void sayHello();}
OK,下邊是實現
package org.foo.hello.impl;import org.foo.hello.Greeting;public class GreetingImpl implements Greeting {final String m_name;GreetingImpl(String name) { m_name = name;}public void sayHello() { System.out.println("Hello, " + m_name + "!");}}
沒啥嘛,這個OSGI有個毛關係,別急,只要你平時就是面向介面編程的。改動不大,要做的就是如何註冊你的服務到OSGI,和怎樣從OSGI查詢已經註冊的服務。
所有的服務實現最終都被打包到一個bundle裡,這個bundle必須添加自己的lifecycle響應以有機會註冊自己的服務。就是說你必須實現自己的activator。LOOK:
package org.foo.hello.impl;import org.foo.hello.Greeting;import org.osgi.framework.BundleActivator;import org.osgi.framework.BundleContext;public class Activator implements BundleActivator {public void start(BundleContext ctx) { ctx.registerService(Greeting.class.getName(), new GreetingImpl("service"), null);}public void stop(BundleContext ctx) {}}
看看在start方法裡都幹了些什嗎?bunldecontext,註冊服務,第一個參數服務實現的介面名,接著是服務實現的執行個體,最後是service property。
stop的時候OSGI會幫你登出任何這個bundle註冊的服務。
這是註冊一個服務,那麼怎麼尋找一個服務呢?
package org.foo.hello.client;import org.foo.hello.Greeting;import org.osgi.framework.*;public class Client implements BundleActivator {public void start(BundleContext ctx) { ServiceReference ref = ctx.getServiceReference(Greeting.class.getName()); ((Greeting) ctx.getService(ref)).sayHello();}public void stop(BundleContext ctx) {}}
好了就這樣,這裡沒有考慮找不到服務的情況。
這裡我們可以看到得到一個service分兩步,第一步是擷取一個service的reference。用這個reference再去得服務。
這個是因為service可以隨時被登出,你直接引用阻止jvm的記憶體回收。