文章目录
  1. 1. 1.OSGI 概述
    1. 1.1. 1.1. 什么是OSGI
    2. 1.2. 1.2. Bundle与插件
    3. 1.3. 1.3. 实现
    4. 1.4. 1.4. Eclipse的Equinox
  2. 2. 2. OSGI Bundle和依赖管理
    1. 2.1. 2.1. OSGI Bundle
    2. 2.2. 2.2. Bundle-标志名称 和 版本
    3. 2.3. 2.3. OSGI版本号的语义
    4. 2.4. 2.4. MANIFEST.MF中的标识符
    5. 2.5. 2.5. bundle的依赖关系和公共的API
    6. 2.6. 2.6. 临时的API和友好的API
    7. 2.7. 2.7. 动态导入包
    8. 2.8. 2.8. 依赖关系管理
    9. 2.9. 2.9. bundle的生命周期
  3. 3. 3. 确定类的插件查找
  4. 4. 4. OSGI控制台
    1. 4.1. 4.1 OSGI控制台
    2. 4.2. 4.2 必需的bundle
    3. 4.3. 4.3. Telnet
    4. 4.4. 4.4. 进入Eclipse OSGi控制台
  5. 5. 5.下载Eclipse标准版
  6. 6. 6. 数据模型和服务bundle
    1. 6.1. 6.1. 练习的目标
    2. 6.2. 6.2. 命名约定:简单的插件/bundle
    3. 6.3. 6.3. 创建插件
    4. 6.4. 6.4. 创建基础类
    5. 6.5. 6.4. 生成构造函数
    6. 6.6. 6.5. 创建 setter和getter方法
    7. 6.7. 6.7. 验证
    8. 6.8. 6.8. 生成toString, hashCode 以及 equals 方法
    9. 6.9. 6.9. 编写一个copy方法
    10. 6.10. 6.10. 创建模型的接口
    11. 6.11. 6.11. 导出模型
    12. 6.12. 6.12. 创建数据模型提供者插件(服务插件)
    13. 6.13. 6.12. 准备服务插件
    14. 6.14. 6.14.1. 创建工厂和导出包
  7. 7. 7. 教程:使用Activator以及导出你的bundle
    1. 7.1. 7.1. 创建一个新的bundle
    2. 7.2. 7.2. 编写代码
    3. 7.3. 7.3. 运行
    4. 7.4. 7.4. 导出你的bundle
  8. 8. 8.在独立的OSGI Server中运行
  9. 9. 9. 原文链接

1.OSGI 概述

1.1. 什么是OSGI

OGSI是一种规范,OSGi 规范的核心定义 Java 组件和服务模型,组件和服务可以动态地安装、 激活、 取消激活、 更新以及卸载。软件中的每个组件在OSGI中称为Bundle

OSGi 的一个非常实用的优点是每一个Bundle都必须定义其导出的 Java 包和所需的依赖项。通过这种方式可以有效地控制提供的 API 和插件的依赖项。

1.2. Bundle与插件

插件是Eclipse中的最小模块单元,Bundle与插件几乎是可以互换的,一个插件也是一个OSGI Bundle,反之亦然。

1.3. 实现

OSGI已经有很多实现,例如Equinox, Knopflerfish OSGi or Apache Felix.

1.4. Eclipse的Equinox

Eclipse的Equinox是基于OSGI规范的实现,也这是Eclipse程序的运行时环境,Eclipse的扩展点是基于OSGI的BundleService的概念来进行的。

2. OSGI Bundle和依赖管理

2.1. OSGI Bundle

OSGI规范定义了OSGI Bundle为模块化的单元。
一个Bundle是一个紧密结合的、自包含的单元,它明确定义了对其他模块的依赖关系和服务,同时还定义了对外开放的API。

从技术上讲Bundle是一个带有额外元数据的.jar文件,这个元数据存储在META-INF/MANIFEST.MF中,META-INF/MANIFEST.MF文件是Java规范的一部分,任何非 OSGi 得运行时将忽略 OSGi 的元数据。因此 OSGi Bundle可以不受限制的在非 OSGi Java 环境中使用。

2.2. Bundle-标志名称 和 版本

每个Bundle通过Bundle-SymbolicName来定义它的标志名称属性,名称一般以Bundle作者的反向域名来定义,如果你有一个名为”example.com”的域名,那么标志名称将一般以”com.example”作为开头。

每个Bundle通过Bundle-Version都有一个版本号。

Bundle-SymbolicNameBundle-Version可以唯一标识在OSGI中的一个Bundle,这两个属性都是在META-INF/MANIFEST.MF中定义的。

2.3. OSGI版本号的语义

OSGI推荐使用<major>.<minor>.<patch>语法来定义你的版本号。

  • 当所有改变都是向后兼容,增加<patch>
  • 当公共 API 已经更改,但所有改变都是向后兼容。,增加<minor>
  • 当更改不是向后兼容,增加<major>

2.4. MANIFEST.MF中的标识符

下面是一个MANIFEST.MF文件的样例:

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 

下面的表格是MANIFEST.MF文件中各个标识符的解释:



































标识符 描述
Bundle-Name Bundle的简短描述
Bundle-SymbolicName Bundle的唯一标识符,如果这个Bundle使用了Eclipse中的扩展点功能,则必需将其标志为单例,你只需在Bundle-SymbolicName后面添加singleton:=true即可。
Bundle-Version 定义bundle的版本号,如果发布了一个新的版本则这个版本号必须增加。
Bundle-Activator 定义实现BundleActivator接口的一个activator类[可选]。bundle在激活时,将会创建一个activator类的实例,每当启动或者停止bundle时都会调用该实例的start()stop()方法,一个OSGI的activator是配置bundle启动期间典型的使用(译者:这句不知道怎么翻译了-_-,你懂就好了)
Bundle-RequiredExecutionEnvironment (BREE) 指定运行包所需的 Java 版本。如果不满足这一要求,OSGi 运行时将不会加载bundle。
Bundle-ActivationPolicy 将它设置为lazy,OSGI运行时将会延迟加载这个bundle,当它只有被用到时才会开始加载(译者:原文描述的不好翻译啊,就按自己的理解来了-_-)。如果没有设置这个值,OSGI将会使用它的规范使用默认的方式进行加载。在Equinox中如果没有设置则根据config.ini来决定这个bundle是否自动启动。
Bundle-ClassPath bundle加载的类路径,默认是”.”,从bundle所在的根目录进行加载,你也可以自己添加jar文件,这些jar文件称为嵌入的的jar文件。

2.5. bundle的依赖关系和公共的API

通过MANIFEST.MF文件包可以定义其他包或包及其依赖项。OSGI在试图访问一个类的时候并没有定义对他的依赖则会抛出一个ClassNotFoundException 的异常,它抛出的异常都是标准java虚拟机中定义的包,这些包往往都是可用的,这些可用的类都是可以在Java虚拟机中通过Jre配置文件进行配置,但是这些配置并不在本文档的讲解范围之内。

bundleMANIFEST.MF 文件中通过Export-Package来定义它的API,如果包不进行显式导出则对其他bundle均为不可见。

这些所有的限制都是通过OSGI规范中的classloader进行强制执行的,每个bundle都有它自己的加载强,访问受限制的类是不允许的。

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

一个bundle可以定义依赖其他包的具体一个版本或者一个范围的版本,例如,bundle A中定义它依赖于bundle C的2.0版本,而bundle B定义它依赖于bundle C的1.0版本

2.6. 临时的API和友好的API

Equinox支持通过x-internal标志来导出一个临时性的包,下面的截屏展示了x-internalMANIFEST.MF编辑器中的设置。


MANIFEST.MF文件中的结果如下:

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 

使用这个API在Eclipse中会显示错误、警告或者忽略将会取决于如下的设置:Window → Preferences → Java → Compiler → Errors/Warnings


你还可以通过x-friends来导出一个特定bundle使用的包,这个标志也可以在MANIFEST.MF编辑器中对Package Visibility添加一个插件来增加。

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使用 API 时不会得到警告。

警告:在可能的情况下尽量不要使用x-friends,因为它被认为是一个不好的实践在你创建你的模块层的特殊情况时。

2.7. 动态导入包

由于遗留原因 OSGi 还支持动态导入的软件包。详细信息,请参阅动态导入的OSGi

警告:你不应该使用此功能,它是一个非模块化的设计。

2.8. 依赖关系管理

OSGI是负责bundles之间的依赖管理,OSGI将会在安装期间读取MANIFEST.MF文件,确保在bundle激活之前他所有的依赖bundles都被解析或者激活。

如果依赖没有得到满足,那么这个bundle将不会被激活。

2.9. bundle的生命周期

bundle的安装时将会将它持续化到一个本地的bundle缓存,在OSGI运行时将会尝试解析它所有依赖的bundle

如果所有的依赖都被解析,那么这个bundle将会进入RESOLVED,否则为INSTALLED状态。

如果存在被依赖的bundle同时存在多个bundles,则会使用最高的bundle版本,如果这几个版本都一样,则会使用最低的bundle id(在框架安装过程中bundle将会得到一个唯一的标识号,即bundle id),如果一个bundle被启动了,则他会经历STARTING状态,然而进入ACTIVE状态。

生命周期的描述如下图:

3. 确定类的插件查找

你可能频繁的去查找一个给定类的插件/bundle,Eclipse编辑器对于确定类的插件查找非常简单,在preferences中开启Include all plug-ins from target into Java Search之后(译者:我怎么没找到-_-,但是还是可以用Ctrl+Shift+t),使用Ctrl+Shift+t就可以弹出对话框进行查找查找,显示在对话框中的jar文件就是通过输入jar文件的前缀得到的。




4. OSGI控制台

4.1 OSGI控制台

OSGi 控制台就像命令行的 shell。在此控制台,你可以输入命令来执行 OSGi 某些操作。这个功能在你应用程序的OSGI层上进行问题分析会非常有用。

最有用的命令是ss可以得到所有bundle的状态和bundleId,下面的表是OSGI中最长用命令的几个参考:


















































命令 描述
help 列出所有可用的命令
ss 列出所有已安装的bundle和它的状态
ss vogella 列出所有已安装的、并且名字中带vogellabundle和它的状态
start id 启动对应idbundle
stop id 停止对应idbundle
diag <bundle-id> 诊断一个bundle,列出它所有缺失的依赖
install URL 从一个URL安装一个bundle
uninstall <bundle-id> 将指定的<bundle-id>进行卸载
bundle <bundle-id> 显示<bundle-id>的bundle的详细信息,包括他的注册和服务
bundle <bundle-id> 显示<bundle-id>的bundleMANIFST.MF文件信息
services filter 显示所有可用的服务和他们的消费者,过滤器是一个可选的LDAP ,例如:为了查看ManagedService 的实现的服务可以用”services (objectclass=*ManagedService)”明令。

4.2 必需的bundle

你不得不将下面的bundle添加到你的运行时配置,以便于使用控制台:

  • org.eclipse.equinox.console
  • org.apache.felix.gogo.command
  • org.apache.felix.gogo.runtime
  • org.apache.felix.gogo.shell

Equinox也包含一个简单的内置控制台可,通过-Dosgi.console.enable.builtin=true参数来激活。

4.3. Telnet

如果你在运行的Eclipse环境中指定-console参数,就可以使用交互的OSGI控制台,一般情况下载OSGI运行配置创建时Eclipse IDE会自动添加上这个参数。通过-console 5555你可以打开一个用于Telnet连接的端口,如果你远程连接到OSGI控制台你就可以使用类似Bash Linux中的tab快捷键和历史功能。

4.4. 进入Eclipse OSGi控制台

你也可以通过正在运行的Eclipse进入OSGI控制台,进入plug-in Development开发环境,然后通过Window->show view->console来打开控制台,在控制台上选择HOST OSGI Console即可打开OSGI控制台。(译者:这段我是按照我自己在Eclipse上的操作来的,应该和原作者的意图是一样的,但是可能表述上不同而已-|-)

请注意你如果通过OSGI控制台来干扰Eclipse的运行,可能会损坏Eelipse的环境。

5.下载Eclipse标准版

Eclipse提供了许多不同的版本,你可以安装所需要的工具在任何的版本中,但是在Eclipse的标准中可以更加简单的安装所需要的工具。

浏览Eclipse download site进行标准版的下载。


自己用软件包将他们解压缩

注意,在Eclipse中的安装路径中避免出现任何的特殊字符和空格。

6. 数据模型和服务bundle

6.1. 练习的目标

在章节的练习中,你将会为你的数据模型创建一个bundle(相等于插件),你也可以将这个数据模型开放给其他插件。

6.2. 命名约定:简单的插件/bundle

一个插件/bundle可以在Eclipse中通过new plug-in general向导来进行创建,如果你按如下配置创建插件,本文中将称此为简单的插件或者简单的bundle。

  • 没有Activator
  • 没有提供其他用户接口
  • 没有一个3.x版本的富客户端程序
  • 没有使用模板生成

在插件创建的向导中如下图(直接按Finish按钮可以避免使用模板):


(现在界面好像稍微有点区别了,不过大致相同)

6.3. 创建插件

创建一个简单的插件项目叫做com.example.e4.rcp.todo.model

6.4. 创建基础类

创建名称为com.example.e4.rcp.todo.model的包,同时添加下面的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.example.e4.rcp.todo.model;

import java.util.Date;

public class Todo {

private long id;
private String summary = "";
private String description = "";
private boolean done = false;
private Date dueDate;

}

6.4. 生成构造函数

通过Source → Generate Constructor using Fields来创建带所有字段的构造函数,使用相同的方法创建一个只带id字段的构造函数以及一个不带任何字段你的构造器。

确保你已经创建了这三个构造函数因为他们在下面的练习中都要用到。

6.5. 创建 setter和getter方法

使用Source → Generate Getter and Setter来创建所有字段的settergetter方法,除了idsetter方法,因为这个id字段在被创建之后最好不要再被改变。


最后的文件代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package com.example.e4.rcp.todo.model;

import java.util.Date;

public class Todo {

private long id;
private String summary = "";
private String description = "";
private boolean done = false;
private Date dueDate;

public Todo() {
}

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;
this.dueDate = 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 dueDate;
}

public void setDueDate(Date dueDate) {
this.dueDate = dueDate;
}

}

注意,因为id字段在之后练习的equalshashCode方法中使用,因此它应该是不可变的。

6.7. 验证

警告:确保你已经生成了这是三个构造函数,并且没有生成idsetter方法。

6.8. 生成toString, hashCode 以及 equals 方法

你可以在Eclipse中通过Source → Generate toString()来生成基于idsummary字段的toString方法。

你还可以通过Source → Generate hashCode() and equals()来生成基于id字段的hashCodeequals方法。

6.9. 编写一个copy方法

你可以在那个类中添加如下内容的copy()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.example.e4.rcp.todo.model;

import java.util.List;

public interface ITodoService {

Todo getTodo(long id);

boolean saveTodo(Todo todo);

boolean deleteTodo(long id);

List<Todo> getTodos();
}

6.10. 创建模型的接口

按照下面创建模型的接口ITodoService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.example.e4.rcp.todo.model;

import java.util.List;

public interface ITodoService {

Todo getTodo(long id);

boolean saveTodo(Todo todo);

boolean deleteTodo(long id);

List<Todo> getTodos();
}

6.11. 导出模型

导出com.example.e4.rcp.todo.model包。打开MANIFEST.MF文件,选择Runtime选项卡,添加com.example.e4.rcp.todo.model到exported packages。

6.12. 创建数据模型提供者插件(服务插件)

创建一个新的简单的plug-in project项目叫做com.example.e4.rcp.todo.service。这个插件叫做todo service服务插件。

技巧:Mac OS系统用户应该使用一个不同于.service的名称(.service在Mac OS会被特殊对待)

6.12. 准备服务插件

在你的服务插件中添加对com.example.e4.rcp.todo.model插件的依赖,打开MANIFEST.MF文件,选择Dependencies选项卡,在中Imported Packages添加com.example.e4.rcp.todo.model

在你的服务插件中新建com.example.e4.rcp.todo.service.internal包以及添加如下内容的类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package com.example.e4.rcp.todo.service.internal;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.example.e4.rcp.todo.model.ITodoService;
import com.example.e4.rcp.todo.model.Todo;

/**
* Example service impl, data is not persisted
* between application restarts
*
*/



public class MyTodoServiceImpl implements ITodoService {

private static int current = 1;
private List<Todo> todos;

public MyTodoServiceImpl() {
todos = createInitialModel();
}

// always return a new copy of the data
@Override
public List<Todo> getTodos() {
List<Todo> list = new ArrayList<Todo>();
for (Todo todo : todos) {
list.add(todo.copy());
}
return list;
}

// create new or update existing Todo object
@Override
public synchronized boolean saveTodo(Todo newTodo) {
Todo updateTodo = findById(newTodo.getId());
if (updateTodo == null) {
updateTodo= new Todo(current++);
todos.add(updateTodo);
}
updateTodo.setSummary(newTodo.getSummary());
updateTodo.setDescription(newTodo.getDescription());
updateTodo.setDone(newTodo.isDone());
updateTodo.setDueDate(newTodo.getDueDate());

return true;
}

@Override
public Todo getTodo(long id) {
Todo todo = findById(id);

if (todo != null) {
return todo.copy();
}
return null;
}

@Override
public boolean deleteTodo(long id) {
Todo deleteTodo = findById(id);

if (deleteTodo != null) {
todos.remove(deleteTodo);
return true;
}
return false;
}

// example data, change if you like
private List<Todo> createInitialModel() {
List<Todo> list = new ArrayList<Todo>();
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++, summary, description, false, new Date());
}

private Todo findById(long id) {
for (Todo todo : todos) {
if (id == todo.getId()) {
return todo;
}
}
return null;
}

}

注意:这个接口使用易变的类存储,数据在应用程序启动时并没有进行持久化,如果你想持久化这个类的数据可以将他们放入数据库或者文件系统。因为这些存储并不是专门针对Eclipse富客户端程序的,所以本书也没有覆盖这些内容。

6.14.1. 创建工厂和导出包

你现在将会在com.example.e4.rcp.todo.service中创建一个类,针对此你可以参照如下技巧:

技巧:在Eclipse中如果父级包没有类文件,则这些包将会被隐藏。在你创建这些类的时候就你定义这些包,这些描述可以在下面的图片中展示出来:

com.example.e4.rcp.todo.service包中创建如下类文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.example.e4.rcp.todo.service;

import com.example.e4.rcp.todo.model.ITodoService;
import com.example.e4.rcp.todo.service.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;
}

}

这个TodoServiceFactory可以产生访问服务的提供者的ITodoService接口,这个类可以被当做ITodoService的一个工厂,一个工厂隐藏创建一个接口的具体实例。
导出com.example.e4.rcp.todo.service这个包以开放给其他插件。

注意:Eclipse工具不支持导出空包,你必须在你导出包之前创建一个类。

7. 教程:使用Activator以及导出你的bundle

本章节的练习是创建另一个bundle来使用Activator,在本章节的末尾的代码你可以在Eclipse中运行,你也可以将其导出在单独的OSGI Server中运行。

7.1. 创建一个新的bundle

通过 File → New → Other… → Plug-in Development → Plug-in Project来创建一个新的简单的插件com.vogella.osgi.firstbundle.internal

7.2. 编写代码

创建如下的线程类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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;
}
}

按如下的方式修改Activation(译者:这里的Activation应该在创建项目时候就创建该类):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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();
}

}

译者:上面原文件中的import de.vogella.osgi.firstbundle.internal.MyThread应该更改为import com.vogella.osgi.firstbundle.internal.MyThread

7.3. 运行

选择MANIFEST.MF文件,右击并选择Run As → Run Configuration,创建一个OSGI框架的运行环境,除了你的decom.vogella.osgi.firstbundle包其他都取消选择。之后在将org.eclipse.osgi添加到你的运行配置中。



译者:现在貌似只有org.eclipse.osgi这个bundle会报缺少依赖的异常,现在贴出我的实验配置图,希望对大家有帮助:


运行这个配置,每隔5秒钟就会有消息输出到控制台。


7.4. 导出你的bundle

这将允许你将导出的bundle在OSGI的运行时进行安装,选中你的bundle然后选择
File -> Export -> Plug-in Development -> “Deployable plug-ins and fragment”





取消选项中的export the source标记

8.在独立的OSGI Server中运行

这章节将展示如何将Equinox作为独立的OSGI运行时进行运行。

在你的Eclipse安装目录中将org.eclipse.osgi.jar进行标记,这个jar文件一般你plugin目录中,拷贝这个文件到一个新的位置,例如:c:\temp\osgi-server*,将这个文件重命名为org.eclipse.osgi.jar

通过下面的命令启动的OSGI服务器:

java -jar org.eclipse.osgi.jar -console 

你可以通过”install URL”的方式根据确定的URL进行bundle的安装,例如你在安装”c:\temp\bundles”这个bundle的用法为:

install file:c:\temp\bundles\plugins\de.vogella.osgi.firstbundle_1.0.0.jar 

技巧:你可能需要正确的路径和bundle名称

你可以使用start <bundle-id>进行启动


译者:我按这种方式尝试了好久都没成功,因为启动OSGI需要4.2中的依赖,最后在Eclipse中才能正常运行,各位如果将这种独立的方式运行成功,请在评论中进行指导

9. 原文链接

参考的原文为OSGi Modularity - Tutorial

其实这里在原文中本来是版权协议的,我当然是没必要翻译了-_-!,
关于本文表格,原本是在markdownpad上排版好了,哪知在hexo渲染之后会多加好多换行符,各位就忍着点看吧,下次有空把表格改好-_-!,


本作品采用[知识共享署名-非商业性使用-相同方式共享 2.5]中国大陆许可协议进行许可,我的博客欢迎复制共享,但在同时,希望保留我的署名权kubiCode,并且,不得用于商业用途。如您有任何疑问或者授权方面的协商,请给我留言

文章目录
  1. 1. 1.OSGI 概述
    1. 1.1. 1.1. 什么是OSGI
    2. 1.2. 1.2. Bundle与插件
    3. 1.3. 1.3. 实现
    4. 1.4. 1.4. Eclipse的Equinox
  2. 2. 2. OSGI Bundle和依赖管理
    1. 2.1. 2.1. OSGI Bundle
    2. 2.2. 2.2. Bundle-标志名称 和 版本
    3. 2.3. 2.3. OSGI版本号的语义
    4. 2.4. 2.4. MANIFEST.MF中的标识符
    5. 2.5. 2.5. bundle的依赖关系和公共的API
    6. 2.6. 2.6. 临时的API和友好的API
    7. 2.7. 2.7. 动态导入包
    8. 2.8. 2.8. 依赖关系管理
    9. 2.9. 2.9. bundle的生命周期
  3. 3. 3. 确定类的插件查找
  4. 4. 4. OSGI控制台
    1. 4.1. 4.1 OSGI控制台
    2. 4.2. 4.2 必需的bundle
    3. 4.3. 4.3. Telnet
    4. 4.4. 4.4. 进入Eclipse OSGi控制台
  5. 5. 5.下载Eclipse标准版
  6. 6. 6. 数据模型和服务bundle
    1. 6.1. 6.1. 练习的目标
    2. 6.2. 6.2. 命名约定:简单的插件/bundle
    3. 6.3. 6.3. 创建插件
    4. 6.4. 6.4. 创建基础类
    5. 6.5. 6.4. 生成构造函数
    6. 6.6. 6.5. 创建 setter和getter方法
    7. 6.7. 6.7. 验证
    8. 6.8. 6.8. 生成toString, hashCode 以及 equals 方法
    9. 6.9. 6.9. 编写一个copy方法
    10. 6.10. 6.10. 创建模型的接口
    11. 6.11. 6.11. 导出模型
    12. 6.12. 6.12. 创建数据模型提供者插件(服务插件)
    13. 6.13. 6.12. 准备服务插件
    14. 6.14. 6.14.1. 创建工厂和导出包
  7. 7. 7. 教程:使用Activator以及导出你的bundle
    1. 7.1. 7.1. 创建一个新的bundle
    2. 7.2. 7.2. 编写代码
    3. 7.3. 7.3. 运行
    4. 7.4. 7.4. 导出你的bundle
  8. 8. 8.在独立的OSGI Server中运行
  9. 9. 9. 原文链接