OSGi与Eclipse Equinox。本教程概述了OSGi及其模块化层。对于本教程,使用Eclipse 4.5(Luna)。
OSGi简介软件模块化
1.1。什么是软件模块化?
应用程序由不同的部分组成,这些部分通常称为软件组件或软件模块。
这些组件通过应用程序编程接口(API)相互交互。API被定义为可以从其他组件使用的一组类和方法。组件还具有一组被认为是软件组件内部的类和方法。
如果组件使用来自另一个组件的API,则它对另一个组件具有依赖性,即,它需要另一个组件存在并正常工作。
由其他组件使用的组件应尽量保持其API稳定,以避免更改影响其他组件。但它应该能够自由地改变其内部实现。
Java在其当前版本(Java 8)中没有提供用于描述软件组件依赖性的结构化方法。Java只支持访问修饰符的使用,但每个公共类都可以从另一个软件组件调用。期望的是明确定义软件组件的API的方式。OSGi规范填补了这个缺口。
1.2。OSGi规范和OSGi实现
OSGi是一组规范,在其核心规范中定义了Java的组件和服务模型。OSGi的实际优点是每个软件组件可以通过一组导出的Java包来定义其API,并且每个组件可以指定其所需的依赖性。
组件和服务可以被动态地安装,激活,去激活,更新和卸载。
OSGi规范有几个实现,例如Eclipse Equinox,Knopflerfish OSGi或Apache Felix。
Eclipse Equinox是基本OSGi规范的参考实现。它也是Eclipse应用程序所基于的运行时环境。
1.3。插件或软件包作为软件组件
OSGi规范将束定义为模块化的最小单位,即在OSGi中软件组件是束。Eclipse编程模型通常调用它们 插件, 但这些术语是可互换的。有效的插件始终是有效的插件,有效的插件始终是有效的插件。在此脚本中 ,首选使用 插件,以与Eclipse插件开发的术语保持一致。
插件是一个内聚的,独立的单元,它明确地定义了它对其他组件和服务的依赖性。它还通过Java包定义其API。
1.4。命名约定:简单的插件
一个插件可以通过Eclipse中通过生成菜单项。相应的向导允许指定多个选项。此脚本调用使用以下选项生成的插件:简单插件或简单包。
-
无激活剂
-
对用户界面没有贡献
-
不是一个富客户端应用程序
-
生成时没有模板
2. OSGi元数据
2.1。清单文件(MANIFEST.MF)
技术上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 |
定义插件版本,如果发布了插件的新版本,则必须递增。 |
|
|
定义实现接口的可选激活器类BundleActivator。该类的实例在插件被激活时创建。无论何时启动或停止插件,都会调用它start()和stop()方法。OSGi激活器可用于在启动期间配置插件。激活程序的执行会增加应用程序的启动时间,因此应谨慎使用此功能。 |
|
Bundle-RequiredExecutionEnvironment(BREE) |
指定运行插件所需的Java版本。如果不满足此要求,则OSGi运行时不会加载插件。 |
|
Bundle-ActivationPolicy |
将此设置为 延迟 将告诉OSGi运行时,只有当其插件之一(即类和接口)被其他插件使用时,才会激活该插件。如果未设置,Equinox运行时不会激活插件,即,此插件提供的服务不可用。 |
|
Bundle-ClassPath |
Bundle-ClassPath指定从bundle加载类的位置。默认值为“。”。它允许从bundle的根加载类。您还可以向其中添加JAR文件,这些文件称为 嵌套JAR文件。 |
2.2。Bundle-符号名称和版本
每个插件都有一个通过Bundle-SymbolicName 属性定义的符号名称 。该名称以插件作者的反向域名开头,例如,如果您拥有“example.com”域,则该符号名称以“com.example”开头。
每个插件在Bundle-Version 属性中也有一个版本号 。
在 Bundle-Version 和 Bundle-SymbolicName 唯一标识一个插件。
2.3。使用OSGi的语义版本化
OSGi建议对 通过 字段标识符定义的版本号使用 。。模式 Bundle-Version。如果更改插件代码,请根据以下规则集增加版本。
-
如果所有更改都向后兼容,则会增加。
-
如果公共API已更改,但所有更改都向后兼容,则增加。
-
如果更改不向后兼容,则会增加。
有关此版本方案的更多信息,请参阅 Eclipse版本编号Wiki。
2.4。通过清单文件指定插件依赖关系
插件可以通过其清单文件定义对其他软件组件的依赖性。OSGi防止访问没有定义的依赖关系的类并抛出ClassNotFoundException。唯一的例外是来自Java运行时环境的包(基于插件的Bundle-RequiredExecutionEnvironment定义)。JRE包始终可用于插件,而没有显式定义的依赖关系。
如果您向清单文件添加依赖项,Eclipse IDE会自动将相应的JAR 文件添加 到您的项目类路径中。
您可以将依赖关系定义为插件依赖关系或包依赖关系。如果定义插件依赖关系,则插件可以访问此插件的所有导出包。如果指定包依赖关系,则可以访问此包。使用包依赖关系允许您交换稍后提供此包的插件。如果你需要这种灵活性,更喜欢使用包依赖。
插件可以定义它取决于另一个bundle的某个版本(或范围),例如插件A可以定义它依赖于版本2.0中的插件C,而插件B定义它取决于插件C的版本1.0。
OSGi运行时确保所有依赖关系在启动插件之前都存在。OSGi在安装期间读取插件的清单文件。它确保所有依赖的插件也被解析,并且如果需要,在插件启动之前激活它们。
2.5。插件的生命周期在OSGi
通过在OSGi运行时中安装插件,插件将保留在本地bundle缓存中。OSGi运行时然后尝试解析它的依赖关系。
如果解决了所有必需的依赖关系,则插件位于
RESOLVED 状态,否则它保持在 INSTALLED 状态。
在存在可以满足依赖性的几个插件的情况下,使用具有最高有效版本的插件。
如果版本相同,则使用具有最低唯一标识符(ID)的插件。每个插件都会在安装期间获取框架分配的此ID。
插件启动时,其状态为 STARTING。成功启动后,它将变为 ACTIVE。
此生命周期如下图所示。
2.6。动态导入包
由于遗留的原因,OSGi支持动态导入包。有关 详细信息,请参阅 OSGi Wiki中的动态导入。您不应该使用此功能,它是非模块化设计的症状。
3.插件的API定义
在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的喜好调整这个首选项设置。
您可以定义一组插件可以访问临时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设置中提到的所有插件都可以访问包,而不会收到错误或警告消息。
4.使用OSGi控制台
4.1。OSGi控制台
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)”命令。 |
4.2。必需的包
您必须将以下包添加到运行时配置中才能使用OSGi控制台。
-
org.eclipse.equinox.console
-
org.apache.felix.gogo.command
-
org.apache.felix.gogo.runtime
-
org.apache.felix.gogo.shell
4.3。Telnet
如果 在启动配置中指定 -console参数,Eclipse将允许您与OSGi控制台交互。默认情况下,使用Eclipse IDE创建的OSGi启动配置包含此参数。通过以下参数,您可以打开一个端口,您可以通过telnet协议连接到该端口。
-console 5555
如果打开到OSGi控制台的telnet会话,您可以使用tab完成和类似于 Linux下的Bash shell 的命令历史记录 。
4.4。访问Eclipse OSGi控制台
您还可以访问运行的Eclipse IDE的OSGi控制台。在 控制台视图中, 您可以使用工具提示打开控制台找到一个菜单项 。如果选择主机OSGi控制台,您将可以访问正在运行的OSGi实例。
请注意,通过OSGi控制台干扰您运行的Eclipse IDE可能会使Eclipse IDE处于错误状态。
5.下载Eclipse SDK
如果您计划向Eclipse平台添加功能,则应下载最新的Eclipse版本。官方版本具有稳定的API,因此是添加插件和功能的良好基础。
Eclipse IDE提供了不同的版本。虽然可以在任何Eclipse包中安装必要的工具,但通常更容易下载Eclipse Standard发行版,其中包含插件开发的所有必要工具。其他软件包增加了Eclipse插件开发不需要的更多工具。
浏览到Eclipse下载站点并下载Eclipse Standard软件包。
| Eclipse 4.5还提供了一个新的Eclipse安装程序安装程序。如果您要下载多种版本的Eclipse,安装程序将非常有用,因为它使用共享安装池用于常用插件。 |
6.练习:数据模型插件
在本练习中,您将为数据模型的定义创建一个插件。还可以将此数据模型用于其他插件。
6.1。为数据模型创建插件
以下屏幕截图描述了插件项目向导的第二页及其相应的设置。按此页上的完成按钮,以避免使用模板。
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字段出现错误。此错误在下一节中解决。 |
6.3。生成构造函数
选择成利用各个领域的构造函数。使用相同的方法仅使用id字段创建另一个构造函数。
| 确保您已创建两个构造函数,因为它们在以下练习中是必需的。 |
6.4。生成getter和setter方法
使用菜单来创建getter和setter方法为您的字段。
|
为什么id字段标记为final?
该ID是终局的,因此Eclipse将创建只有一个getter。这是正确和希望的。我们将使用此字段来生成equals和hashCode()方法,因此它不应该是可变的。更改这是在使用的字段equals和hashCode()方法可以创建错误,这些错误是难以确定的,即,一个对象包含在一个HashMap,但没有找到。 |
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()); } }
6.6。生成toString(),hashCode()和equals()方法
使用Eclipse 根据id 和 summary 字段toString() 为Todo类 生成一个 方法 。这可以通过Eclipse菜单来完成 。
还使用Eclipse生成 基于id 字段的方法hashCode() 和 equals()方法 。这可以通过Eclipse菜单来完成 。
6.7。编写一个copy()方法
将以下copy() 方法添加 到类中。
public Todo copy() { return new Todo(this.id, this.summary, this.description, this.done, getDueDate()); }
6.8。创建todo服务的接口
创建以下 ITodoService 界面。
package com.example.e4.rcp.todo.model; import java.util.List; import java.util.Optional; import java.util.function.Consumer; public interface ITodoService { void getTodos(Consumer<List> todosConsumer); boolean saveTodo(Todo todo); Optional getTodo(long id); boolean deleteTodo(long id); }
6.9。定义模型插件的API
导出com.example.e4.rcp.todo.model包以将其定义为API。
为此,请打开MANIFEST.MF文件并选择“ 运行时 ”选项卡。添加com.example.e4.rcp.todo.model到导出的包。
练习:创建服务包
在本练习中,您为服务实现创建一个插件,该插件提供对数据的访问。
此服务实现使用临时数据存储,即,数据不在应用程序重新启动之间持久化。要持久化数据,您可以扩展此类以将数据存储在数据库或文件系统中。由于此存储对于Eclipse RCP应用程序不是特殊的,因此不在此脚本中。
7.1。创建数据模型提供程序插件(服务插件)
创建一个名为com.example.e4.rcp.todo.services的新简单插件(请参阅命名约定:简单插件)项目。此插件在以下描述中称为待办服务插件。
|
MacOS的操作系统踹结尾的文件夹。服务特殊,因此我们使用。服务结束。 |
7.2。定义服务插件中的依赖关系
将com.example.e4.rcp.todo.model插件作为依赖项添加到服务插件。要实现这一点,请打开MANIFEST.MF文件。然后选择“ 依赖关系 ”选项卡,将com.example.e4.rcp.todo.model软件包添加到“ 导入的软件包”。
7.3。提供ITodoService接口的实现
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
7.4。更新产品配置(通过您的功能)
将新的.model 和 .services 插件添加 到您的 com.example.e4.rcp.todo.feature 功能。确保您使用 feature.xml 文件中的“插件 ”选项卡 。
| 每次创建一个新插件并在MANIFEST.MF文件中引用它时,都必须将其添加到产品配置文件中(通过特性项目)。 |
练习:创建服务包
8.1。创建工厂以访问服务实现
在[dataservice_plugin]中 创建两个插件。为了向消费者提供服务实现,最好的解决方案是使用 OSGi服务, 但为了保持这种描述,我们在本练习中简单使用一个工厂。
在 包中创建一个名为TodoServiceFactory的新类 com.example.e4.rcp.todo.services。为此,您可能需要以下提示。
| 在其默认配置中,Eclipse IDE会隐藏父包(如果它们不包含任何类)。在指定类期间,您可以定义正确的包。这在下面的屏幕截图中描述。 |
该类ITodoService 通过静态方法访问您的 实现。它可以被认为是一个 工厂 的 ITodoService 接口。工厂隐藏了某个接口的具体实例的创建。
package com.example.e4.rcp.todo.services; import com.example.e4.rcp.todo.model.ITodoService; import com.example.e4.rcp.todo.services.internal.MyTodoServiceImpl; /** * factory provides access to the todo service provider * */ public class TodoServiceFactory { private static ITodoService todoService = new MyTodoServiceImpl(); public static ITodoService getInstance() { return todoService; } }
8.2。导出服务插件中的包
com.example.e4.rcp.todo.services 通过“ 运行时 ”选项卡上的MANIFEST.MF 文件 导出 包 ,以便其他插件可用。
| 请注意,Eclipse工具不支持导出空包。您必须在包中至少创建一个类,然后才能将其导出。 |
9.教程:使用激活器并导出包
在本练习中,您创建另一个使用 Activator。您还在Eclipse中运行它在本章结尾,您还将导出您的包,以便稍后在独立的OSGi服务器中使用它。
9.1。创建新的捆绑包
通过创建一个新的简单的插件项目“com.vogella.osgi.firstbundle.internal” 。
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(); } }
9.3。跑
选择您的 MANIFEST.MF 文件,右键单击它并选择菜单:运行方式[运行配置]。创建OSGi Framework启动配置。取消选择除de.vogella.osgi.firstbundle之外的所有包。然后按 添加所需捆绑。这会将org.eclipse.osgi 包添加 到运行配置中。
运行此配置。每5秒钟一个新消息写入控制台。
| 如果你想知道OSGi开始在哪个文件夹中找到它在$ {workspace_loc} /。metadata / plugins / org.eclipse.pde.core / 。此文件夹通过文件“dev.properties”列出已安装的软件包,并通过osgi.bundles = reference \:file \ statement将Eclipse工作区设置为config.ini文件中的引用。这样,您可以在运行的OSGi环境中直接更新您的软件包,无需任何部署。 |
9.4。导出您的捆绑包
导出您的捆绑包。这将允许您将其安装到OSGi运行时。选择您的捆绑包,然后选择。
取消标记导出源的选项。
10.运行独立OSGi服务器
本章将介绍如何将Equinox作为OSGi独立运行时运行。在Eclipse安装目录中标识文件org.eclipse.osgi * .jar。此文件应位于plugin文件夹中。将此jar文件复制到新位置,例如c:\ temp \ osgi-server。将文件重命名为“org.eclipse.osgi.jar”。通过以下命令启动OSGi服务器。
java -jar org.eclipse.osgi.jar
但是单独运行osgi jar通常是不需要的。
因此,org.eclipse.osgi束需要由被配置的config.ini位于一个文件结构的文件夹。
为了从命令行传递命令到OSGi运行时,需要额外的bundle。
-
org.eclipse.equinox.console
-
org.apache.felix.gogo.command
-
org.apache.felix.gogo.runtime
-
org.apache.felix.gogo.shell
要使用org.eclipse.osgi包启动这些包,config.ini文件必须如下所示:
osgi.bundles=org.eclipse.equinox.console@start, org.apache.felix.gogo.command@start, org.apache.felix.gogo.shell@start, org.apache.felix.gogo.runtime@start osgi.noShutdown=true eclipse.ignoreApp=true
|
使用此配置,其他bundle必须位于org.eclipse.osgi包之外。
|
使用此设置,可以使用附加-console参数类似地启动OSGi运行时:
java -jar org.eclipse.osgi_3.11.2.v20161107-1947.jar -console
一旦这样开始,可以使用OSGi控制台,例如,通过使用命令ss来查看可用的软件包。
您还可以使用“安装URL”从某个URL安装捆绑包。例如,从c:\ temp \ bundles安装软件包 use:
install file:c:\temp\bundles\plugins\de.vogella.osgi.firstbundle_1.0.0.jar
|
您可能需要更正系统上的路径和包名称。 |
您可以使用start和id启动包。
|
您可以使用-clean参数删除所有已安装的软件包。 |
12. OSGi资源
12.1。vogella GmbH培训和咨询支持
| 训练 | 服务和支持 |
|---|---|
|
vogella公司提供 来自Eclipse RCP,Android,Git,Java,Gradle和Spring等领域专家的全面培训和教育服务。我们提供公共和内部培训。无论你决定采取什么样的课程,你都可以在参考之前体验到许多之前的“我参加的最好的IT类”。 |
vogella公司提供专家咨询服务,开发支持和辅导。我们的客户范围从财富100强公司到个人开发商。 |
附录A:版权和许可
版权所有©2012-2016 vogella GmbH。免费使用软件示例是根据EPL许可证的条款授予的。本教程是根据 Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Germany许可证发布的。



