怎么执行OSGi模块化

这篇文章将为大家详细讲解有关怎么执行OSGi模块化,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

十载的老边网站建设经验,针对设计、前端、开发、售后、文案、推广等六对一服务,响应快,48小时及时工作处理。成都营销网站建设的优势是能够根据用户设备显示端的尺寸不同,自动调整老边建站的显示方式,使网站能够适用不同显示终端,在浏览器中调整网站的宽度,无论在任何一种浏览器上浏览网站,都能展现优雅布局与设计,从而大程度地提升浏览体验。创新互联公司从事“老边网站设计”,“老边网站推广”以来,每个客户项目都认真落实执行。

OSGi模块化 - 

Lars Vogel,Simon Scholz(c)2008,2017 vogella GmbH版本5.2,202.02.2017

目录

  • OSGi简介软件模块化

  • 1.2。OSGi规范和OSGi实现

    OSGi是一组规范,在其核心规范中定义了Java的组件和服务模型。OSGi的实际优点是每个软件组件可以通过一组导出的Java包来定义其API,并且每个组件可以指定其所需的依赖性。

    组件和服务可以被动态地安装,激活,去激活,更新和卸载。

    OSGi规范有几个实现,例如Eclipse Equinox,Knopflerfish OSGi或Apache Felix。

    Eclipse Equinox是基本OSGi规范的参考实现。它也是Eclipse应用程序所基于的运行时环境。

    1.4。命名约定:简单的插件

    一个插件可以通过Eclipse中通过生成文件  ? 新建  ? 其他...  ? 插件开发  ? 插件工程菜单项。相应的向导允许指定多个选项。此脚本调用使用以下选项生成的插件:简单插件简单包

    • 无激活剂

    • 对用户界面没有贡献

    • 不是一个富客户端应用程序

    • 生成时没有模板

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进行语义版本控制。

表1.清单文件中的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文件

2.3。使用OSGi的语义版本化

OSGi建议对 通过 字段标识符定义的版本号使用 。。模式 Bundle-Version。如果更改插件代码,请根据以下规则集增加版本。

  • 如果所有更改都向后兼容,则会增加。

  • 如果公共API已更改,但所有更改都向后兼容,则增加。

  • 如果更改不向后兼容,则会增加。

有关此版本方案的更多信息,请参阅 Eclipse版本编号Wiki。

2.5。插件的生命周期在OSGi

通过在OSGi运行时中安装插件,插件将保留在本地bundle缓存中。OSGi运行时然后尝试解析它的依赖关系。

如果解决了所有必需的依赖关系,则插件位于

RESOLVED 状态,否则它保持在 INSTALLED 状态。

在存在可以满足依赖性的几个插件的情况下,使用具有最高有效版本的插件。

如果版本相同,则使用具有最低唯一标识符(ID)的插件。每个插件都会在安装期间获取框架分配的此ID。

插件启动时,其状态为 STARTING。成功启动后,它将变为 ACTIVE

此生命周期如下图所示。

怎么执行OSGi模块化

3.插件的API定义

MANIFEST.MF文件中,插件还通过导出包标识符定义其API。未显式导出的所有软件包对其他插件不可见。

怎么执行OSGi模块化

所有这些限制都通过特定的OSGi实施classloader。每个插件都有自己的类加载器。不使用reflection.s不能访问受限类

不幸的是,OSGi不能阻止你使用Java反射来访问这些类。这是因为OSGi基于尚不支持模块化层的Java运行时。

通过x-internal标志,OSGi运行时可以将导出的包标记为临时。这允许其他插件使用相应的类,但表示这些类不被视为官方API。

以下屏幕截图显示如何x-internal在清单编辑器中设置包。

怎么执行OSGi模块化

这是相应的清单文件的外观。

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  ? 编译器  ? 错误/警告首选项设置。

怎么执行OSGi模块化

您可以定义一组插件可以访问临时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.1。OSGi控制台

OSGi控制台就像一个命令行shell。在此控制台中,您可以键入命令以执行OSGi操作。这可以用于分析应用程序的OSGi层上的问题。

例如,使用命令 ss 获取所有包的概述,它们的状态和bundle-id。下表是最重要的OSGi命令的参考。

表2. 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.3。Telnet

如果 在启动配置中指定 -console参数,Eclipse将允许您与OSGi控制台交互。默认情况下,使用Eclipse IDE创建的OSGi启动配置包含此参数。通过以下参数,您可以打开一个端口,您可以通过telnet协议连接到该端口。

-console 5555

如果打开到OSGi控制台的telnet会话,您可以使用tab完成和类似于 Linux下的Bash shell 的命令历史记录 。

5.下载Eclipse SDK

如果您计划向Eclipse平台添加功能,则应下载最新的Eclipse版本。官方版本具有稳定的API,因此是添加插件和功能的良好基础。

Eclipse IDE提供了不同的版本。虽然可以在任何Eclipse包中安装必要的工具,但通常更容易下载Eclipse Standard发行版,其中包含插件开发的所有必要工具。其他软件包增加了Eclipse插件开发不需要的更多工具。

浏览到Eclipse下载站点并下载Eclipse Standard软件包。

Eclipse 4.5还提供了一个新的Eclipse安装程序安装程序。如果您要下载多种版本的Eclipse,安装程序将非常有用,因为它使用共享安装池用于常用插件。

6.1。为数据模型创建插件

创建一个名为com.example.e4.rcp.todo.model的简单插件项目(请参阅命名约定:简单插件)。

以下屏幕截图描述了插件项目向导的第二页及其相应的设置。按此页上的完成按钮,以避免使用模板。

怎么执行OSGi模块化

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.4。生成getter和setter方法

使用来源  ? 生成getter和setter ...菜单来创建getter和setter方法为您的字段。

为什么id字段标记为final?

ID是终局的,因此Eclipse将创建只有一个getter。这是正确和希望的。我们将使用此字段来生成equals和hashCode()方法,因此它不应该是可变的。更改这是在使用的字段equals和hashCode()方法可以创建错误,这些错误是难以确定的,即,一个对象包含在一个HashMap,但没有找到。

怎么执行OSGi模块化

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.7。编写一个copy()方法

将以下copy() 方法添加 到类中。

public Todo copy() { return new Todo(this.id, this.summary, this.description, this.done, getDueDate()); }

6.9。定义模型插件的API

导出com.example.e4.rcp.todo.model包以将其定义为API。

为此,请打开MANIFEST.MF文件并选择“ 运行时 ”选项卡。添加com.example.e4.rcp.todo.model到导出的包。

怎么执行OSGi模块化

7.1。创建数据模型提供程序插件(服务插件)

创建一个名为com.example.e4.rcp.todo.services的新简单插件(请参阅命名约定:简单插件)项目。此插件在以下描述中称为待办服务插件。

MacOS的操作系统踹结尾的文件夹。服务特殊,因此我们使用。服务结束。

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 rootTag;  public MyTodoServiceImpl() { todos = createInitialModel(); createRootTag(todos); }  @Override public void getTodos(Consumer 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(); }  }

练习:创建服务包

8.2。导出服务插件中的包

com.example.e4.rcp.todo.services 通过“ 运行时 ”选项卡上的MANIFEST.MF 文件 导出 包 ,以便其他插件可用。

请注意,Eclipse工具不支持导出空包。您必须在包中至少创建一个类,然后才能将其导出。

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.4。导出您的捆绑包

导出您的捆绑包。这将允许您将其安装到OSGi运行时。选择您的捆绑包,然后选择文件  ? 导出  ? 插件开发  ?可部署的插件和碎片。

怎么执行OSGi模块化

怎么执行OSGi模块化

取消标记导出源的选项。

怎么执行OSGi模块化

11.关于本网站

支持免费内容

怎么执行OSGi模块化

问题和讨论

怎么执行OSGi模块化

教程和代码许可证

怎么执行OSGi模块化

获取源代码

怎么执行OSGi模块化

12.1。vogella GmbH培训和咨询支持
训练服务和支持

vogella公司提供 来自Eclipse RCP,Android,Git,Java,Gradle和Spring等领域专家的全面培训和教育服务。我们提供公共和内部培训。无论你决定采取什么样的课程,你都可以在参考之前体验到许多之前的“我参加的最好的IT类”。

vogella公司提供专家咨询服务,开发支持和辅导。我们的客户范围从财富100强公司到个人开发商。

其他资讯