OSGi(Open Service Gateway initiative)是一个用于模块化 Java 应用程序的动态组件模型标准。旨在解决 Java 平台在模块化、动态性和服务管理方面的不足。

OSGi

OSGi是一种面向服务的模块化框架,它将应用程序划分为多个独立的、可重用的模块,每个模块被称为一个bundle。每个bundle都有自己的生命周期、类加载器和依赖管理机制。

OSGi框架提供了动态部署、服务导向、类加载隔离和生命周期管理等关键特性,使得应用程序更具灵活性和可维护性。

OSGi 的核心思想是将应用程序划分为多个模块(称为 Bundle),这些模块可以在运行时动态安装、启动、停止、更新和卸载,同时支持服务的发布与发现机制。

特点

  1. 模块化(Modularity)
    OSGi 将应用程序划分为多个称为 Bundle(包)的模块。每个 Bundle 是一个 JAR 文件,包含代码、资源以及一个特殊的清单文件(MANIFEST.MF),用于声明模块的元数据,如:

    • Bundle 名称、版本
    • 导出的包(Export-Package)
    • 依赖的包(Import-Package)
    • 所需的服务等

    这种机制实现了清晰的模块边界和依赖管理,避免了传统 Java 应用中“类路径地狱”(classpath hell)的问题。

  2. 动态性(Dynamism)
    OSGi 支持在运行时动态安装、启动、停止、更新和卸载 Bundle,而无需重启整个应用。这使得系统具备高度的灵活性和可维护性,特别适用于需要长期运行、持续更新的系统(如嵌入式设备、企业服务器等)。

  3. 面向服务的架构(Service-Oriented Architecture)
    OSGi 提供了一个轻量级的服务注册与发现机制。Bundle 可以:

    • 注册服务(通过接口暴露功能)
    • 查找和绑定其他 Bundle 提供的服务
    • 监听服务的动态变化(如服务上线/下线)

    服务以 Java 接口形式定义,实现了解耦和动态绑定。

  4. 生命周期管理
    每个 Bundle 都有明确的生命周期状态(如 INSTALLED、RESOLVED、STARTING、ACTIVE、STOPPING、UNINSTALLED),并可通过 BundleActivator 或声明式服务(Declarative Services)等方式参与生命周期控制。

组成

OSGi 的组成可概括为三大核心层,通过这些机制,OSGi 实现了高度模块化、松耦合、可动态演进的 Java 应用架构。

模块层(Module Layer)

这是 OSGi 的基础,用于定义模块化单元。

  • Bundle(模块):OSGi 中的基本部署单元,本质上是一个带有特殊元数据(MANIFEST.MF 文件)的 JAR 文件。

  • 元数据(Manifest):通过 MANIFEST.MF 中的 OSGi 特定头(如 Bundle-SymbolicNameExport-PackageImport-Package 等)声明模块的依赖和导出内容。

  • 包级别的可见性控制:Bundle 可以精确控制哪些 Java 包对外可见(导出),哪些包仅内部使用(私有),从而实现强封装。

Bundle其实就是个jar包, 是OSGi特定描述的一个jar包,具体位置在META-INF/MANIFEST.MF文件,Bundle有很多中状态。很好的隔离了外部类和内部类,一个个的Bundle组成了基于OSGi的应用,Bundle是组件和服务的载体;

SOCM(Service-Oriented Component Model)是面向服务的组件模型(Component),任何一个普通的java对象都可以通过配置文件中的定义来得到,Component其实就是服务的载体,既可以提供对外使用的服务也可以使用外部服务;

img

服务层(Service Layer)

OSGi 的核心优势之一,支持面向服务的编程模型。

  • 服务(Service):普通 Java 对象(POJO),通过接口注册到 OSGi 服务注册表中。

  • 服务注册与发现:

    • Bundle 可通过 BundleContext.registerService() 发布服务。
    • 其他 Bundle 可通过 BundleContext.getServiceReference() 或使用服务追踪器(ServiceTracker)或声明式服务(Declarative Services)来消费服务。
  • 动态绑定:服务可以随时注册或注销,消费者能动态响应服务的变化(如服务上线/下线)。

一个OSGi Service就是一个注册到OSGi框架中的java对象,在注册的时候可以设置Service的属性,在获取Service的时候也可以根据属性进行过滤,具体交互过程如图:

img

Declarative Service 简称DS,DS可以让我们在Bundle中定义Component,通过配置的方式发布服务和获取服务;

生命周期层

提供对 Bundle 的动态管理能力。

  • BundleContext:每个 Bundle 在启动时获得一个 BundleContext 对象,用于与 OSGi 框架交互(如安装/卸载其他 Bundle、注册/查找服务等)。

  • 生命周期状态:Bundle 有明确的状态(INSTALLED、RESOLVED、STARTING、ACTIVE、STOPPING、UNINSTALLED)。

  • 动态性:支持在运行时安装、启动、停止、更新、卸载 Bundle,无需重启整个应用。

架构

OSGi就如同操作系统一样,为应用程序的运行提供运行环境,我们并不能直接感受到操作系统,但是他一直为我们服务,同样,OSGi我们感知不到他的存在,但是我们却每时每刻都在享受他带给我们的便利;

OSGi一共分三层,就如同网络分层结构一样,层次分明同时逐层依赖,顺序是万万不能颠倒的;

img
  • 模块层:定义了OSGi的概念,称之为bundle,包含元数据、类文件和 相关资源的jar包,Bundle可以声明哪些包可以对外可见,以及声明可以依赖哪些外部包,也就是哪些包是可以导入的;

  • 生命周期层: 生命周期层一个是在应用程序的外部定义了Bundle生命周期的操作(安装、卸载等),另一个就是在应用程序的内部定义了Bundle如何访问他们的执行环境;

  • 服务层:工作原理与面向服务相似。实现的时候先定义一个接口再实现,用Bundle激活器完成服务注册和服务发现

框架

运行OSGi应用程序,我们需要OSGi容器,常见的OSGi容器有如下几种,都是基于OSGi标准实现的

Apache Felix(推荐)

Apache旗下的一个OSGi框架,项目本身非常成熟,提供的服务也是最全的,几乎涵盖了全部的OSGi 4.2的标准

使用方法

  1. 下载,解压

  2. 启动 java -jar bin/felix.jar <cache-path>,此命令会安装bundle目录所有的bundles。默认的,bundle目录含有shell相关的用户界面来与框架交互。安装到框架的bundle会复制一份到缓存目录(felix-cache)。不指定目录就是本目录下

  3. IDEA 安装OSGI插件,加入felix

  4. 新建一个OSGI项目:JBoss -> OSGI

  5. src 同级别下,创建目录和文件 META-INF/manifest.mf

    1
    2
    3
    4
    5
    6
    Bundle-Name: Service listener example
    Bundle-Description: A bundle that displays messages at startup and when service events occur
    Bundle-Vendor: Apache Felix
    Bundle-Version: 1.0.0
    Bundle-Activator: com.demo.osgi.felix.Activator
    Import-Package: org.osgi.framework
  6. 创建 Bundle-Activator 示例

    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
    package com.demo.osgi.felix;

    import org.osgi.framework.BundleActivator;
    import org.osgi.framework.BundleContext;
    import org.osgi.framework.ServiceEvent;
    import org.osgi.framework.ServiceListener;

    /**
    * This class implements a simple bundle that utilizes the OSGi
    * framework's event mechanism to listen for service events. Upon
    * receiving a service event, it prints out the event's details.
    来自官网的案例:事件监听
    **/
    public class Activator implements BundleActivator, ServiceListener {

    public void start(BundleContext context) {
    System.out.println("Starting to listen for service events.");
    context.addServiceListener(this);
    }

    public void stop(BundleContext context) {
    context.removeServiceListener(this);
    System.out.println("Stopped listening for service events.");
    }

    public void serviceChanged(ServiceEvent event) {
    String[] objectClass = (String[])
    event.getServiceReference().getProperty("objectClass");

    if (event.getType() == ServiceEvent.REGISTERED) {
    System.out.println(
    "Ex1: Service of type " + objectClass[0] + " registered.");
    } else if (event.getType() == ServiceEvent.UNREGISTERING) {
    System.out.println(
    "Ex1: Service of type " + objectClass[0] + " unregistered.");
    } else if (event.getType() == ServiceEvent.MODIFIED) {
    System.out.println(
    "Ex1: Service of type " + objectClass[0] + " modified.");
    }
    }
    }
  7. IDEA 配置运行

    1. 运行配置,选择osgi bundle 选择合适的osgi框架,并将当前module添加进来
    2. 右键项目,open module settings,在mainfest generation 中 添加 bundle
  8. 将项目打成jar,安装在Apache Felix中,使用以下命令来安装和启动bundle

    1
    2
    install file:/path/to/demo.jar
    start <bundle-id>

Eclipse Equinox

Eclipse旗下的OSGi框架,是Eclipse注明的PDE开发环境的底层,和Eclipse结合紧密,只要你安装了PDE,你就已经有了Equinox,可以方便的在Eclipse里设置你开发的Bundle,启动、部署等操作也异常简单

如果是基于Eclipse开发,Equinox无疑是好的选择

Spring DM

Spring旗下的OSGi框架

除非有基于Spring项目的移植需求,否则不推荐其他情况下使用Spring DM。

Knopflerfish

是OSGi的先行者,它本身是一个相当标准OSGi框架,提供了绝大多数标准功能

但是无论在人气上,开发进度上,文档完善上都不如其他的三者

Felix 示例

演示OSGi框架的使用,创建一个简单的示例,其中包含两个模块:一个模块提供Greeting服务,另一个模块使用该服务进行输出。

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
// 定义一个接口
public interface GreetingService {
void sayHello();
}

// 实现了GreetingService接口的模块GreetingModule
// BundleActivator是一个OSGi bundle的生命周期管理接口。
public class GreetingModule implements GreetingService, BundleActivator {
private BundleContext context;

// 注册了GreetingService服务,以便其他bundle可以使用它
@Override
public void start(BundleContext context) {
this.context = context;
System.out.println("GreetingModule started");
context.registerService(GreetingService.class.getName(), this, null);
}

// 在bundle停止时进行清理工作
@Override
public void stop(BundleContext context) {
System.out.println("GreetingModule stopped");
}

@Override
public void sayHello() {
System.out.println("Hello from GreetingModule");
}
}

创建一个使用GreetingService的模块ClientModule:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 实现了OSGi bundle生命周期管理接口BundleActivator
public class ClientModule implements BundleActivator {
private BundleContext context;

// 使用BundleContext获取了GreetingService的引用,并调用其sayHello方法
@Override
public void start(BundleContext context) {
this.context = context;
System.out.println("ClientModule started");
ServiceReference<GreetingService> serviceRef = context.getServiceReference(GreetingService.class);
GreetingService greetingService = context.getService(serviceRef);
greetingService.sayHello();
}

@Override
public void stop(BundleContext context) {
System.out.println("ClientModule stopped");
}
}

创建一个包含上述两个模块的META-INF/MANIFEST.MF文件:

1
2
3
Bundle-SymbolicName: com.example.osgi.demo
Bundle-Version: 1.0.0
Bundle-Activator: com.demo.osgi.GreetingModule;com.demo.osgi.ClientModule

运行OSGi应用程序,我们需要一个OSGi容器。常见的OSGi容器有Apache Felix和Eclipse Equinox

将上述代码编译成JAR文件,并将其放入Apache Felix的运行目录中。

1
2
3
4
5
6
# 启动Apache Felix容器,执行以下命令:
java -jar bin/felix.jar

# 在Apache Felix控制台中,使用以下命令来安装和启动bundle:
install file:/path/to/demo.jar
start <bundle-id>