OSGi是一個規范,最常見的實現可以算作Equinox , Apache Felix和Knoplerfish 。 在本文中,我將嘗試舉一個在Equinox中創建簡單OSGi捆綁包的示例。
OSGi結構
基本的OSGi結構可以在右側的圖中看到。 OSGi實現位于JVM的頂部,并提供用于模塊的服務管理,組件定義,執行,管理和生命周期控制的機制。 最基本的OSGi概念描述如下:
束
在OSGi系統中,用于構建結構的組件的名稱為“ Bundle ”。 在部署階段,每個OSGi捆綁包都是一個jar文件。 但是bundle jar文件與常規jar文件的主要區別可以算作OSGi特定的清單定義和某些OSGi特定的類。 我們將在即將到來的部分和示例中討論這些差異。
服務
服務提供了結構束之間的交互。 服務作為接口公開,并向執行該接口的實現注冊。 與SOA結構并行,通過OSGi服務進行訪問使得與基于常規jar的Java結構相比,基于OSGi的系統更加松散耦合。 這些結構還可以在運行時更改系統的更改組件。
OSGi為要注冊和訪問的服務實現服務目錄。 OSGi還提供了服務管理機制。
生命周期
OSGi提供了一個平臺,可以控制捆綁軟件的生命周期。 在這種結構中,每個捆綁軟件都有其自己的OSGi配置,主要是在依賴關系和暴露部分方面,并且系統由OSGi本身運行。 OSGi知道組成系統的捆綁包,該捆綁包帶有一個帶有順序的配置文件,并且生命周期管理以給定順序應用于每個組件。 生命周期管理的包端由“ Activator”類控制,該類實現了OSGi接口,該接口必須存在于每個“常規” OSGi包中。 (不適用于“片段”片段,但這已經超出了本文的討論范圍,請忽略這一點)
如上所述, b undle是一個jar文件,其中至少包含一個Activator類和一個MANIFEST文件,其中包含OSGi特定的標頭和信息。下面可以看到一個示例MANIFEST文件。 讓我們看一下定義中每個部分的含義。
Bundle-Name: Our Bundle
Bundle-SymbolicName: us.elron.bundles.ours
Bundle-Description: Very own bundle of ours
Bundle-ManifestVersion: 1
Bundle-Version: 1.0.0
Bundle-Activator: us.elron.bundles.ours.BundleActivator
Export-Package: us.elron.bundles.ours.exported; version = "1.0.0"
Import-Package: us.elron.bundles.yours.exported; version = "1.3.0"
- 捆綁包名稱 : 捆綁包的“吸引公眾”名稱。
- Bundle-SymbolicName:作為MANIFEST文件中唯一的強制性定義,符號名稱定義OSGi生態系統中捆綁軟件的唯一名稱。 由于此定義應該唯一,因此通常按照約定將其定義為捆綁軟件的基本包名稱。
- 捆綁包描述:有關捆綁包 “存在理由”的描述。
- Bundle-ManifestVersion:捆綁包的清單版本。
- 捆綁軟件版本: OSGi捆綁軟件版本。
- Bundle-Activator:此類用于控制包的生命周期。 OSGi調用此類以啟動或停止捆綁軟件。
- 導出包:本節中定義了希望由其他包使用的包。
- Import-Package:本節中定義了執行當前包所需的包。
OSGi結構提供了必要的機制來控制束的生命周期。 捆綁軟件受OSGi的控制,以根據給定的配置控制其生命周期。 此生命周期步驟將在下面詳細說明:
組件狀態 | 描述 |
---|---|
已安裝 | 此狀態表明安裝步驟已成功完成。 在這種情況下,既不進行依賴關系分析也不進行類加載。 僅執行必需的步驟,例如定義分析其清單文件的包屬性。 |
解決 | 當OSGi解析并滿足其所有依賴關系并進行類加載操作時,便會在此狀態下找到捆綁軟件。 這是啟動之前和停止之后的狀態。 |
開始 | 這是在調用捆綁軟件的激活器的“啟動”方法但尚未成功或未成功完成時找到捆綁軟件的狀態。 |
活性 | 該捆綁包已成功啟動并正在運行,這意味著Activator的“啟動”方法導致成功。 |
停止 | 這是在調用捆綁軟件的激活器的“停止”方法但尚未成功或未成功完成時找到捆綁軟件的狀態。 |
未安裝 | 這是從系統中刪除捆綁軟件時的狀態。 在這種情況下,不會過渡到另一個狀態。 必須再次安裝該組件。 |

讓我們做一個簡單的例子來闡明上面提到的概念和步驟。 在我們的示例中,將有兩個捆綁包,其中一個捆綁包提供一個隨機數生成器服務以生成隨機數,另一個捆綁包將使用此服務每秒打印一個隨機數,并進行單獨的處理。 (沒有道理嗎?對我來說也一樣,但足以掌握概念 )
現在,讓我們使用Eclipse和Equinox一起開發此示例項目(最好)。
在Eclipse中,使用“新建插件項目”向導開發OSGi捆綁包,如下所示:

使用向導創建兩個項目( us.elron.osgi.random和us.elron.osgi.user ),按照所需的步驟進行操作 , 并按如下所示命名包和激活器( RandomActivator , UserActivator )。 該項目的最終結果也應該是這樣的:

下面給出了隨機數生成包( us.elron.osgi.random )的服務定義,實現和清單定義。
接口(IRandomGenerator):
package us.elron.osgi.random;public interface IRandomGenerator {int generate ();int generate(int upperBound);}
服務(RandomGenerator):
package us.elron.osgi.random.generator;import java.util.Random;import us.elron.osgi.random.IRandomGenerator;public class RandomGenerator implements IRandomGenerator {private final Random random;public RandomGenerator () {this.random = new Random();}@ Overridepublic int generate () {return this.random.nextInt();}@ Overridepublic int generate (final int upperBound) {return this.random.nextInt (upperBound);}}
激活器(RandomActivator) :
package us.elron.osgi.random;import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;import us.elron.osgi.random.generator.RandomGenerator;public class RandomActivator implements BundleActivator {public void start(final BundleContext context) throws Exception {System.out.println("[Random] Let's 'Random'!");RandomGenerator randomGenerator = new RandomGenerator();context.registerService(IRandomGenerator.class.getName (), randomGenerator, null);System.out.println("[Random] Random services were registered.");}public void stop(final BundleContext context) throws Exception {System.out.println("[Random] Bundle is being stopped !");}}
組件的MANIFEST.MF說明如下。 捆綁軟件至少應導出具有其服務接口的軟件包,以便其他捆綁軟件使用它們。 因為松散耦合是SOA和OSGi系統的最重要目標之一,所以僅應從任何捆綁包中導出最少的必需類集。
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Random
Bundle-SymbolicName: us.elron.osgi.random
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: us.elron.osgi.random.RandomActivator
Bundle-Vendor: ELRON.US
Require-Bundle: org.eclipse.core.runtime
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
Export-Package: us.elron.osgi.random
可以看出,服務是注冊為OSGi服務的Java接口的實現。 激活程序類是捆綁軟件的OSGi訪問點。 OSGi使用捆綁軟件的Activator類來管理其生命周期。 在此過程中,OSGi將“ org.osgi.framework.BundleContext ”接口的實現發送到分發包。 該接口使捆綁軟件可以與OSGi層進行交互,并且可以在代碼中看到,從而進行諸如注冊和獲取OSGi服務之類的操作。
現在讓我們看一下用戶包類:
這是打印由隨機生成器服務生成的隨機數的類。
package us.elron.osgi.user;import us.elron.osgi.random.IRandomGenerator;public class RandomPrinter extends Thread {private final IRandomGenerator random;private volatile boolean run = true;public RandomPrinter (final IRandomGenerator random) {this.random = random;}@ Overridepublic void run () {while (this.run) {System.out.println ("[User] new random number: " + this.random.generate (300));try {Thread.sleep (1000);} catch (final InterruptedException e) {break;}}System.out.println ("[User] The process was terminated.");}public void close () {this.run = false;}}
這是Activator的實現:
package us.elron.osgi.user;import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;import us.elron.osgi.random.IRandomGenerator;public class UserActivator implements BundleActivator {private RandomPrinter randomPrinter;public void start (final BundleContext context) throws Exception {System.out.println ("[User] Here we go ..");ServiceReference randSrvRef = context.getServiceReference (IRandomGenerator.class.getName ());IRandomGenerator randService = (IRandomGenerator) context.getService (randSrvRef);if (randService == null) {throw new Exception ("[User] Error! Random service could not be found!");}this.randomPrinter = new RandomPrinter(randService);this.randomPrinter.start();}public void stop (final BundleContext bundleContext) throws Exception {System.out.println ("[User] finish ..");this.randomPrinter.close ();}}
“用戶”捆綁包的MANIFEST.MF描述如下。 我們應該使用隨機服務接口所在的隨機生成器束的“ us.elron.osgi.random”包定義依賴項。 可以在包或包級別定義依賴關系,但是,為了減少包之間的依賴關系,最好盡可能地選擇包級別的依賴關系。
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: User
Bundle-SymbolicName: us.elron.osgi.user
Bundle-Version: 1.0.0.qualifier
Bundle-Activator: us.elron.osgi.user.UserActivator
Bundle-Vendor: ELRON.US
Require-Bundle: org.eclipse.core.runtime
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
Import-Package: us.elron.osgi.random
要使用Eclipse在OSGi上運行這些項目,應定義運行配置,如下所示。 在OSGi Framework下的“ 運行 (或調試 ) 配置 ”步驟中,應創建一個新配置(右鍵單擊),并在此配置中選擇我們的新捆綁包。 要為選定的包提供所需的依賴關系,我們可以使用“添加所需的包” ”按鈕。 通過這種方式,Eclipse將解決依賴關系層次結構,并為選定的依賴關系添加所需的包。 我們還應該定義捆綁包的開始順序。 應根據捆綁包的依賴關系定義此順序。 依賴束應在它們依賴的束之后開始。 因此,在我們的示例中,我們將“ us.elron.osgi.random”的級別設置為1 ,同時將“ us.elron.osgi.user ”的級別設置為2 。

以這種形狀運行項目會生成如下輸出:
OSGi> [Random] Let's 'Random'!
[Random] Random services were registered.
[User] Here we go ..
[User] new random number: 38
[User] new random number: 250
[User] new random number: 94
[User] new random number: 150
[User] new random number: 215
[User] new random number: 124
[User] new random number: 195
[User] new random number: 260
[User] new random number: 276
[User] new random number: 129
OSGi運行時提供了一個控制臺界面供我們與自己進行交互。 運行控制臺應用程序窗口時,我們看到一個“ osgi>”腳本,表示可以訪問控制臺。 提到您可以在控制臺中執行的一些重要命令之后,我將讓您一個人呆在控制臺上,讓您發現可以從“幫助”命令開始的操作。
“ ss”命令,顯示所有注冊到OSGi的組件及其ID , 狀態和捆綁包名稱值以及版本部件。 id值表示OSGi給每個捆綁軟件的唯一標識符。 即使重新安裝并安裝了捆綁軟件(發現一件事),該數字在JVM執行中也保持不變,但是可以在新的執行中進行更改。 狀態值指示捆綁軟件的狀態(在上表中詳細說明), 名稱和版本值指示其名稱對我們的影響。 對于當前系統, “ ss”命令的輸出如下:
OSGi> ssFramework is launched.id State Bundle
0 ACTIVE org.eclipse.osgi_3.6.0.v20100517Fragments = 4
2 ACTIVE org.eclipse.core.jobs_3.5.0.v20100515
3 ACTIVE javax.servlet_2.5.0.v200910301333Resolved javax.transaction_1.1.1.v201006150915 4Master = 0
5 ACTIVE org.eclipse.core.runtime_3.6.0.v20100505
6 ACTIVE org.eclipse.equinox.preferences_3.3.0.v20100503
7 ACTIVE org.eclipse.osgi.services_3.2.100.v20100503
8 ACTIVE org.eclipse.core.runtime.compatibility.auth_3.2.200.v20100517
9 ACTIVE us.elron.osgi.random_1.0.0.qualifierResolved org.eclipse.core.runtime.compatibility.registry_3.3.0.v20100520 10Master = 11
11 ACTIVE org.eclipse.equinox.registry_3.5.0.v20100503Fragments = 10
12 ACTIVE org.eclipse.equinox.app_1.3.0.v20100512
13 ACTIVE org.eclipse.equinox.common_3.6.0.v20100503
14 ACTIVE org.eclipse.core.contenttype_3.4.100.v20100505 14-1235
15 ACTIVE us.elron.osgi.user_1.0.0.qualifier
OSGi>
假設我們要關閉用戶捆綁包。 在這種情況下,我們需要使用要停止的分發包的ID(在這種情況下為15)執行“停止”命令。
[User] a new random number is: 48
[User] a new random number is: 49
OSGi> stop 15
[User] finish ..
[User] The process was terminated.
當我們再次查看“ ss”命令的輸出時,
Framework is launched.id State Bundle
0 ACTIVE org.eclipse.osgi_3.6.0.v20100517Fragments = 4
2 ACTIVE org.eclipse.core.jobs_3.5.0.v20100515
3 ACTIVE javax.servlet_2.5.0.v200910301333Resolved javax.transaction_1.1.1.v201006150915 4Master = 0
5 ACTIVE org.eclipse.core.runtime_3.6.0.v20100505
6 ACTIVE org.eclipse.equinox.preferences_3.3.0.v20100503
7 ACTIVE org.eclipse.osgi.services_3.2.100.v20100503
8 ACTIVE org.eclipse.core.runtime.compatibility.auth_3.2.200.v20100517
9 ACTIVE us.elron.osgi.random_1.0.0.qualifierResolved org.eclipse.core.runtime.compatibility.registry_3.3.0.v20100520 10Master = 11
11 ACTIVE org.eclipse.equinox.registry_3.5.0.v20100503 Fragments = 10
12 ACTIVE org.eclipse.equinox.app_1.3.0.v20100512
13 ACTIVE org.eclipse.equinox.common_3.6.0.v20100503
14 ACTIVE org.eclipse.core.contenttype_3.4.100.v20100505-1235
15 RESOLVED us.elron.osgi.user_1.0.0.qualifier
我們看到ID為15的User bundle的狀態已解決 (請參見生命周期部分)。 同樣,我們可以執行啟動命令(啟動15)來啟動捆綁軟件并觀察該過程再次開始工作,或者執行“ s ”命令查看注冊到OSGi的所有服務,或者使用uninstall命令從OSGi刪除捆綁軟件。 您可以自由發現!
在本文中,我試圖簡單地解釋一下OSGi是什么,它如何工作以及可以用它做什么。 希望你喜歡它。 您可以在此處下載資源。
隨時通過elron [at] elron.us發表評論或聯系。 我很高興收到您的來信。
參考: OSGi:我們的JCG合作伙伴 Elron在Ender Ayd?n Orak博客上的介紹。
相關文章 :
- OSGi將Maven與Equinox結合使用
- OSGI和Spring動態模塊–簡單的Hello World
- OSGi –帶有服務的簡單Hello World
- Java EE6 CDI,命名組件和限定符
翻譯自: https://www.javacodegeeks.com/2012/01/osgi-introduction.html