1、說明
本文主要介紹如何創建一個最簡單的 bundle?如何在 bundle 中監控服務的狀態變化?如何配置 MANIFEST.MF 文件?如何編譯、安裝、運行我們打包好的 bundle,這並不一定需要是第一個例子,但是可以很好的幫助我們理解如何使用最簡單的方式構建一個 bundle。
這個例子會詳細的說明如何構建一個最簡單的 bundle?如何編寫相應的 manifest.mf 信息?如何編譯、打包、安裝?
2、第一個例子
每一個 bundle 可以通過全局唯一的 BundleContext 實例和 OSGI 框架交互,那我們應該如何在一個 bundle 中獲取該實例呢?答案是我們的 Bundle 必須要實現 BundleActivator 接口,該接口包含 void start(BundleContext context) 和 void stop(BundleContext context) 兩個方法,在 bundle 被安裝,並且啓動的時候,start 方法會被調用,此時 BundleContext 實例會以參數的形式傳遞進來,同樣當框架被停止的時候,stop 方法會被調用,此時 BundleContext 實例會以參數的形式傳遞給用戶,除了實現了 BundleActicator 接口,下面的例子中還實現了 ServiceListener 接口,目的是將 Bundle 作爲訂閱者,監聽自身的狀態的改變,具體實現如下:
/*
* Apache Felix OSGi tutorial.
**/
package tutorial.example1;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceEvent;
/**
* 這裏我們實現了 OSGI 的服務事件監聽機制,即實現了 ServiceListener,
* 在事件回調函數(ServiceChange)中,簡單的輸出了該事件的詳細信息。
**/
public class Activator implements BundleActivator, ServiceListener
{
/**
* Implements BundleActivator.start(). Prints
* a message and adds itself to the bundle context as a service
* listener.
* @param context the framework context for the bundle.
**/
public void start(BundleContext context)
{
System.out.println("Starting to listen for service events.");
context.addServiceListener(this);
}
/**
* Implements BundleActivator.stop(). Prints
* a message and removes itself from the bundle context as a
* service listener.
* @param context the framework context for the bundle.
**/
public void stop(BundleContext context)
{
context.removeServiceListener(this);
System.out.println("Stopped listening for service events.");
// Note: It is not required that we remove the listener here,
// since the framework will do it automatically anyway.
}
/**
* Implements ServiceListener.serviceChanged().
* Prints the details of any service event from the framework.
* @param event the fired service event.
**/
public void serviceChanged(ServiceEvent event)
{
String[] objectClass = (String[])
event.getServiceReference().getProperty("objectClass");
if (event.getType() == ServiceEvent.REGISTERED)
{
System.out.println(
"Ex1: Service of type " + objectClass[0] + " registered.");
}
else if (event.getType() == ServiceEvent.UNREGISTERING)
{
System.out.println(
"Ex1: Service of type " + objectClass[0] + " unregistered.");
}
else if (event.getType() == ServiceEvent.MODIFIED)
{
System.out.println(
"Ex1: Service of type " + objectClass[0] + " modified.");
}
}
}
以上類編寫完成之後,我們還需要編寫一個 manifest.mf 文件,這個文件的作用是聲明 bundle 的一些列元信息,包括此 bundle 的名稱、版本(重要)、創建者、啓動入口(重要)、依賴的包(重要)、對外暴露的包(重要),具體如下:
Bundle-Name: Service listener example
Bundle-Description: A bundle that displays messages at startup and when service events occur
Bundle-Vendor: Apache Felix
Bundle-Version: 1.0.0
Bundle-Activator: tutorial.example1.Activator
Import-Package: org.osgi.framework // 必須以換行符結束(回車),否則此行將會被忽略。
Bundle-Name: Bundle 名稱。
Bundle-Description: Bundle 的描述信息。
Bundle-Vendor: Bundle 的廠商信息,可能比較彆扭,也就是這個 Bundle 是作者信息。
Bundle-Version: Bundle 的版本信息。
Bundle-Acticator: Bundle 的啓動入口,當 Bundle 被安裝之後,並且使用 Start 命令啓動 Bundle 的時候,其指定的類會被自動構建,並且調用其實現的 BundleActivator 的 start 方法。
Import-Package: 聲明此 Bundle 依賴的包,jre 標準提供的不需要聲明。
Export-Package: 聲明此 Bundle 中哪些包是對外暴露的,即允許其他 Bundle 使用。
接下來就是編譯 Activator 類了,編譯的時候,必須要保證 felix.jar 文件在類路徑下,上述的文檔中出現了中文,則需要在編譯的時候指定源文件對應的編碼格式,否則會編譯出錯,具體如下:
PS D:\devInstall\apache\felix-framework-6.0.0\examples\demo01\src> javac -cp ..\..\..\bin\felix.jar -encoding UTF-8 -d ../target .\tutorial\example1\*.java
上述的的命令如果看不明白的話,可以在命令行直接輸入 javac,查看 javac 命令的使用幫助,這裏我就不詳細講解了。
編譯好 bundle 類之後,我們需要將編譯好的類和 manifest.mf 一起打包爲一個 jar 包,如下:
PS D:\devInstall\apache\felix-framework-6.0.0\examples\demo01\src> cd ../target
PS D:\devInstall\apache\felix-framework-6.0.0\examples\demo01\target> cp ../src/manifest.mf ./
PS D:\devInstall\apache\felix-framework-6.0.0\examples\demo01\target> jar cvfm example1.jar .\manifest.mf -C . .
已添加清單
正在添加: manifest.mf(輸入 = 268) (輸出 = 182)(壓縮了 32%)
正在添加: tutorial/(輸入 = 0) (輸出 = 0)(存儲了 0%)
正在添加: tutorial/example1/(輸入 = 0) (輸出 = 0)(存儲了 0%)
正在添加: tutorial/example1/Activator.class(輸入 = 1718) (輸出 = 876)(壓縮了 49%)
上述的的命令如果看不明白的話,可以在命令行直接輸入 jar,查看 jar 命令的使用幫助,這裏我就不詳細講解了。
打包完成之後我們將會得到一個名字爲 example1.jar 的文件,然後再 felix 框架下安裝此 bundle,具體命令如下:
Welcome to Apache Felix Gogo
g! install file:./examples/demo01/target/example1.jar
Bundle ID: 7
g! lb
START LEVEL 1
ID|State |Level|Name
0|Active | 0|System Bundle (6.0.0)|6.0.0
1|Active | 1|jansi (1.17.1)|1.17.1
2|Active | 1|JLine Bundle (3.7.0)|3.7.0
3|Active | 1|Apache Felix Bundle Repository (2.0.10)|2.0.10
4|Active | 1|Apache Felix Gogo Command (1.0.2)|1.0.2
5|Active | 1|Apache Felix Gogo JLine Shell (1.1.0)|1.1.0
6|Active | 1|Apache Felix Gogo Runtime (1.1.0)|1.1.0
7|Installed | 1|Service listener example (1.0.0)|1.0.0
g! start 7
Starting to listen for service events. // bundle 啓動輸出信息
當上面的 bundle 被安裝啓動之後,框架中所有的服務註冊、註銷、更改事件都會被此 bundle 檢測到,並且會打印出相應的事件信息,再後面的例子中我們將會講解 OSGI 框架中服務如何構建、註冊、使用。