您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關怎么執行OSGi模塊化,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
版本5.2,202.02.2017
目錄
OSGi簡介軟件模塊化
OSGi是一組規范,在其核心規范中定義了Java的組件和服務模型。OSGi的實際優點是每個軟件組件可以通過一組導出的Java包來定義其API,并且每個組件可以指定其所需的依賴性。
組件和服務可以被動態地安裝,激活,去激活,更新和卸載。
OSGi規范有幾個實現,例如Eclipse Equinox,Knopflerfish OSGi或Apache Felix。
Eclipse Equinox是基本OSGi規范的參考實現。它也是Eclipse應用程序所基于的運行時環境。
一個插件可以通過Eclipse中通過生成文件 ? 新建 ? 其他... ? 插件開發 ? 插件工程菜單項。相應的向導允許指定多個選項。此腳本調用使用以下選項生成的插件:簡單插件或簡單包。
無激活劑
對用戶界面沒有貢獻
不是一個富客戶端應用程序
生成時沒有模板
技術上OSGi插件是 帶有附加元信息的.jar文件。此元信息存儲在 META-INF / MANIFEST.MF 文件中。此文件稱為 清單 文件,是標準Java規范的一部分,OSGi向其中添加了額外的元數據。根據Java規范,任何Java運行時必須忽略未知的元數據。因此,在其他Java環境中可以無限制地使用插件。
以下列表是清單文件的示例。
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Popup Plug-in Bundle-SymbolicName: com.example.myosgi; singleton:=true Bundle-Version: 1.0.0 Bundle-Activator: com.example.myosgi.Activator Require-Bundle: org.eclipse.ui, org.eclipse.core.runtime Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: JavaSE-1.6
下表說明了清單文件中的標識符。有關OSGi中通常使用的版本模式的信息,請參閱使用OSGi進行語義版本控制。
標識符 | 描述 |
---|---|
軟件包名稱 | 插件的簡短描述。 |
Bundle-SymbolicName | 插件的唯一標識符。如果此插件使用Eclipse的擴展點功能,則必須將其標記為Singleton。您可以通過在Bundle-SymbolicName標識符之后添加以下語句來實現: ; singleton:=true |
Bundle-Version | 定義插件版本,如果發布了插件的新版本,則必須遞增。 |
Bundle-Activator | 定義實現接口的可選激活器類BundleActivator。該類的實例在插件被激活時創建。無論何時啟動或停止插件,都會調用它start()和stop()方法。OSGi激活器可用于在啟動期間配置插件。激活程序的執行會增加應用程序的啟動時間,因此應謹慎使用此功能。 |
Bundle-RequiredExecutionEnvironment(BREE) | 指定運行插件所需的Java版本。如果不滿足此要求,則OSGi運行時不會加載插件。 |
Bundle-ActivationPolicy | 將此設置為 延遲 將告訴OSGi運行時,只有當其插件之一(即類和接口)被其他插件使用時,才會激活該插件。如果未設置,Equinox運行時不會激活插件,即,此插件提供的服務不可用。 |
Bundle-ClassPath | Bundle-ClassPath指定從bundle加載類的位置。默認值為“。”。它允許從bundle的根加載類。您還可以向其中添加JAR文件,這些文件稱為 嵌套JAR文件。 |
OSGi建議對 通過 字段標識符定義的版本號使用 。。模式 Bundle-Version。如果更改插件代碼,請根據以下規則集增加版本。
如果所有更改都向后兼容,則會增加。
如果公共API已更改,但所有更改都向后兼容,則增加。
如果更改不向后兼容,則會增加。
有關此版本方案的更多信息,請參閱 Eclipse版本編號Wiki。
通過在OSGi運行時中安裝插件,插件將保留在本地bundle緩存中。OSGi運行時然后嘗試解析它的依賴關系。
如果解決了所有必需的依賴關系,則插件位于
RESOLVED 狀態,否則它保持在 INSTALLED 狀態。
在存在可以滿足依賴性的幾個插件的情況下,使用具有最高有效版本的插件。
如果版本相同,則使用具有最低唯一標識符(ID)的插件。每個插件都會在安裝期間獲取框架分配的此ID。
插件啟動時,其狀態為 STARTING。成功啟動后,它將變為 ACTIVE。
此生命周期如下圖所示。
在MANIFEST.MF文件中,插件還通過導出包標識符定義其API。未顯式導出的所有軟件包對其他插件不可見。
所有這些限制都通過特定的OSGi實施classloader。每個插件都有自己的類加載器。不使用reflection.s不能訪問受限類
不幸的是,OSGi不能阻止你使用Java反射來訪問這些類。這是因為OSGi基于尚不支持模塊化層的Java運行時。
通過x-internal標志,OSGi運行時可以將導出的包標記為臨時。這允許其他插件使用相應的類,但表示這些類不被視為官方API。
以下屏幕截圖顯示如何x-internal在清單編輯器中設置包。
這是相應的清單文件的外觀。
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Provider Bundle-SymbolicName: de.vogella.osgi.xinternal.provider Bundle-Version: 1.0.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Export-Package: de.vogella.osgi.xinternal.provider;x-internal:=true
您可以配置Eclipse Java編輯器如何顯示臨時API的使用。這種訪問可以被配置為顯示為,錯誤,警告或者如果這種訪問應當不導致附加消息。
默認值為顯示警告消息。您可以通過Eclipse的喜好調整這個窗口 ? 首選項 ? 的Java ? 編譯器 ? 錯誤/警告首選項設置。
您可以定義一組插件可以訪問臨時API,而不會出現警告或錯誤消息。這可以通過x-friends指令完成。如果您在清單編輯器的“ 運行時 ”選項卡上的“ 包可見性”部分添加插件,則會添加此標志。
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Provider Bundle-SymbolicName: de.vogella.osgi.xinternal.provider Bundle-Version: 1.0.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Export-Package: de.vogella.osgi.xinternal.provider;x-friends:="another.bundle"
該x-friends設置具有相同的效果,x-internal但是x-friends設置中提到的所有插件都可以訪問包,而不會收到錯誤或警告消息。
OSGi控制臺就像一個命令行shell。在此控制臺中,您可以鍵入命令以執行OSGi操作。這可以用于分析應用程序的OSGi層上的問題。
例如,使用命令 ss 獲取所有包的概述,它們的狀態和bundle-id。下表是最重要的OSGi命令的參考。
命令 | 描述 |
---|---|
help | 列出可用的命令。 |
ss | 列出安裝的軟件包及其狀態。 |
ss vogella | 列出捆綁包及其在其名稱中包含vogella的狀態。 |
start | 使用 ID 啟動包。 |
stop | 使用 ID 停止捆綁。 |
diag | 診斷特定包。它列出所有缺失的依賴項。 |
install URL | 從URL安裝包。 |
uninstall | 使用 ID 卸載捆綁軟件。 |
bundle | 顯示具有 ID的捆綁包的信息,包括已注冊和已使用的服務。 |
headers | 顯示包的MANIFST.MF信息。 |
services filter | 顯示所有可用的服務及其消費者。過濾器是一個可選的LDAP過濾器,例如,查看提供ManagedService實現的所有服務使用“services(objectclass = * ManagedService)”命令。 |
如果 在啟動配置中指定 -console參數,Eclipse將允許您與OSGi控制臺交互。默認情況下,使用Eclipse IDE創建的OSGi啟動配置包含此參數。通過以下參數,您可以打開一個端口,您可以通過telnet協議連接到該端口。
-console 5555
如果打開到OSGi控制臺的telnet會話,您可以使用tab完成和類似于 Linux下的Bash shell 的命令歷史記錄 。
如果您計劃向Eclipse平臺添加功能,則應下載最新的Eclipse版本。官方版本具有穩定的API,因此是添加插件和功能的良好基礎。
Eclipse IDE提供了不同的版本。雖然可以在任何Eclipse包中安裝必要的工具,但通常更容易下載Eclipse Standard發行版,其中包含插件開發的所有必要工具。其他軟件包增加了Eclipse插件開發不需要的更多工具。
瀏覽到Eclipse下載站點并下載Eclipse Standard軟件包。
Eclipse 4.5還提供了一個新的Eclipse安裝程序安裝程序。如果您要下載多種版本的Eclipse,安裝程序將非常有用,因為它使用共享安裝池用于常用插件。 |
創建一個名為com.example.e4.rcp.todo.model的簡單插件項目(請參閱命名約定:簡單插件)。
以下屏幕截圖描述了插件項目向導的第二頁及其相應的設置。按此頁上的完成按鈕,以避免使用模板。
<h4 id="create-the-base-class" font-weight:300;color:#ba3925;text-rendering:optimizelegibility;line-height:1.2;font-size:1.6875em;word-spacing:-0.05em;"="">6.2。創建基類
創建com.example.e4.rcp.todo.model包和以下模型類。
package com.example.e4.rcp.todo.model; import java.util.Date; public class Todo { private final long id; private String summary = ""; private String description = ""; private boolean done = false; private Date dueDate = new Date(); }
您的最終ID字段出現錯誤。此錯誤在下一節中解決。 |
使用來源 ? 生成getter和setter ...菜單來創建getter和setter方法為您的字段。
為什么id字段標記為final? 該ID是終局的,因此Eclipse將創建只有一個getter。這是正確和希望的。我們將使用此字段來生成equals和hashCode()方法,因此它不應該是可變的。更改這是在使用的字段equals和hashCode()方法可以創建錯誤,這些錯誤是難以確定的,即,一個對象包含在一個HashMap,但沒有找到。 |
<h4 id="adjust-the-generated-getter-and-setter-methods" font-weight:300;color:#ba3925;text-rendering:optimizelegibility;line-height:1.2;font-size:1.6875em;word-spacing:-0.05em;"="">6.5。調整生成的getter和setter方法
調整生成的getter和setter dueDate()字段以進行防御性復制。該Date班是不是一成不變的,我們要避免這種情況的一個實例Todo可以從外部改變,而相應的setter。
public Date getDueDate() { return new Date(dueDate.getTime()); } public void setDueDate(Date dueDate) { this.dueDate = new Date(dueDate.getTime()); }
生成的類應該類似于以下列表。
package com.example.e4.rcp.todo.model; import java.util.Date; public class Todo { private final long id; private String summary = ""; private String description = ""; private boolean done = false; private Date dueDate = new Date(); public Todo(long id) { this.id = id; } public Todo(long id, String summary, String description, boolean done, Date dueDate) { this.id = id; this.summary = summary; this.description = description; this.done = done; setDueDate(dueDate); } public long getId() { return id; } public String getSummary() { return summary; } public void setSummary(String summary) { this.summary = summary; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public boolean isDone() { return done; } public void setDone(boolean done) { this.done = done; } public Date getDueDate() { return new Date(dueDate.getTime()); } public void setDueDate(Date dueDate) { this.dueDate = new Date(dueDate.getTime()); } }
將以下copy() 方法添加 到類中。
public Todo copy() { return new Todo(this.id, this.summary, this.description, this.done, getDueDate()); }
導出com.example.e4.rcp.todo.model包以將其定義為API。
為此,請打開MANIFEST.MF文件并選擇“ 運行時 ”選項卡。添加com.example.e4.rcp.todo.model到導出的包。
創建一個名為com.example.e4.rcp.todo.services的新簡單插件(請參閱命名約定:簡單插件)項目。此插件在以下描述中稱為待辦服務插件。
MacOS的操作系統踹結尾的文件夾。服務特殊,因此我們使用。服務結束。 |
com.example.e4.rcp.todo.services.internal 在服務插件中創建 包并創建以下類。
package com.example.e4.rcp.todo.services.internal; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.stream.Collectors; import com.example.e4.rcp.todo.model.ITodoService; import com.example.e4.rcp.todo.model.Tag; import com.example.e4.rcp.todo.model.Todo; public class MyTodoServiceImpl implements ITodoService { private static AtomicInteger current = new AtomicInteger(1); private List todos; private Tag<tag> rootTag; public MyTodoServiceImpl() { todos = createInitialModel(); createRootTag(todos); } @Override public void getTodos(Consumer<List> todosConsumer) { // always pass a new copy of the data todosConsumer.accept(todos.stream().map(t -> t.copy()).collect(Collectors.toList())); } protected List getTodosInternal() { return todos; } // create or update an existing instance of Todo @Override public synchronized boolean saveTodo(Todo newTodo) { // hold the Optional object as reference to determine, if the Todo is // newly created or not Optional todoOptional = findById(newTodo.getId()); // get the actual todo or create a new one Todo todo = todoOptional.orElse(new Todo(current.getAndIncrement())); todo.setSummary(newTodo.getSummary()); todo.setDescription(newTodo.getDescription()); todo.setDone(newTodo.isDone()); todo.setDueDate(newTodo.getDueDate()); if (!todoOptional.isPresent()) { todos.add(todo); } return true; } @Override public Optional getTodo(long id) { return findById(id).map(todo -> todo.copy()); } @Override public boolean deleteTodo(long id) { Optional deleteTodo = findById(id); deleteTodo.ifPresent(todo -> { todos.remove(todo); }); return deleteTodo.isPresent(); } // Example data, change if you like private List createInitialModel() { List list = new ArrayList<>(); list.add(createTodo("Application model", "Flexible and extensible")); list.add(createTodo("DI", "@Inject as programming mode")); list.add(createTodo("OSGi", "Services")); list.add(createTodo("SWT", "Widgets")); list.add(createTodo("JFace", "Especially Viewers!")); list.add(createTodo("CSS Styling", "Style your application")); list.add(createTodo("Eclipse services", "Selection, model, Part")); list.add(createTodo("Renderer", "Different UI toolkit")); list.add(createTodo("Compatibility Layer", "Run Eclipse 3.x")); return list; } private Todo createTodo(String summary, String description) { return new Todo(current.getAndIncrement(), summary, description, false, new Date()); } private Optional findById(long id) { return getTodosInternal().stream().filter(t -> t.getId() == id).findAny(); } }</tag
com.example.e4.rcp.todo.services 通過“ 運行時 ”選項卡上的MANIFEST.MF 文件 導出 包 ,以便其他插件可用。
請注意,Eclipse工具不支持導出空包。您必須在包中至少創建一個類,然后才能將其導出。 |
通過創建一個新的簡單的插件項目“com.vogella.osgi.firstbundle.internal” 文件 ? 新建 ? 其他... ? 插件開發 ? 插件項目。
<h4 id="coding" font-weight:300;color:#ba3925;text-rendering:optimizelegibility;line-height:1.2;font-size:1.6875em;word-spacing:-0.05em;"="">9.2。編碼
創建以下線程類。
package com.vogella.osgi.firstbundle.internal; public class MyThread extends Thread { private volatile boolean active = true; public void run() { while (active) { System.out.println("Hello OSGi console"); try { Thread.sleep(5000); } catch (Exception e) { System.out.println("Thread interrupted " + e.getMessage()); } } } public void stopThread() { active = false; } }
將Activator.java類更改為以下類。
package com.vogella.osgi.firstbundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import de.vogella.osgi.firstbundle.internal.MyThread; public class Activator implements BundleActivator { private MyThread myThread; public void start(BundleContext context) throws Exception { System.out.println("Starting com.vogella.osgi.firstbundle"); myThread = new MyThread(); myThread.start(); } public void stop(BundleContext context) throws Exception { System.out.println("Stopping com.vogella.osgi.firstbundle"); myThread.stopThread(); myThread.join(); } }
導出您的捆綁包。這將允許您將其安裝到OSGi運行時。選擇您的捆綁包,然后選擇文件 ? 導出 ? 插件開發 ?可部署的插件和碎片。
取消標記導出源的選項。
訓練 | 服務和支持 |
---|---|
vogella公司提供 來自Eclipse RCP,Android,Git,Java,Gradle和Spring等領域專家的全面培訓和教育服務。我們提供公共和內部培訓。無論你決定采取什么樣的課程,你都可以在參考之前體驗到許多之前的“我參加的最好的IT類”。 | vogella公司提供專家咨詢服務,開發支持和輔導。我們的客戶范圍從財富100強公司到個人開發商。 |
<h3 id="copyright-and-license" font-weight:300;color:#ba3925;text-rendering:optimizelegibility;line-height:1.2;font-size:2.3125em;word-spacing:-0.05em;letter-spacing:-0.01em;"="">附錄A:版權和許可
版權所有©2012-2016 vogella GmbH。免費使用軟件示例是根據EPL許可證的條款授予的。本教程是根據 Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Germany許可證發布的。
關于怎么執行OSGi模塊化就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。