几种面向服务的模块化框架(OSGi)
OSGi(Open Service Gateway initiative)是一个用于模块化 Java 应用程序的动态组件模型标准。旨在解决 Java 平台在模块化、动态性和服务管理方面的不足。
OSGi
OSGi是一种面向服务的模块化框架,它将应用程序划分为多个独立的、可重用的模块,每个模块被称为一个bundle。每个bundle都有自己的生命周期、类加载器和依赖管理机制。
OSGi框架提供了动态部署、服务导向、类加载隔离和生命周期管理等关键特性,使得应用程序更具灵活性和可维护性。
OSGi 的核心思想是将应用程序划分为多个模块(称为 Bundle),这些模块可以在运行时动态安装、启动、停止、更新和卸载,同时支持服务的发布与发现机制。
特点
-
模块化(Modularity)
OSGi 将应用程序划分为多个称为 Bundle(包)的模块。每个 Bundle 是一个 JAR 文件,包含代码、资源以及一个特殊的清单文件(MANIFEST.MF),用于声明模块的元数据,如:- Bundle 名称、版本
- 导出的包(Export-Package)
- 依赖的包(Import-Package)
- 所需的服务等
这种机制实现了清晰的模块边界和依赖管理,避免了传统 Java 应用中“类路径地狱”(classpath hell)的问题。
-
动态性(Dynamism)
OSGi 支持在运行时动态安装、启动、停止、更新和卸载 Bundle,而无需重启整个应用。这使得系统具备高度的灵活性和可维护性,特别适用于需要长期运行、持续更新的系统(如嵌入式设备、企业服务器等)。 -
面向服务的架构(Service-Oriented Architecture)
OSGi 提供了一个轻量级的服务注册与发现机制。Bundle 可以:- 注册服务(通过接口暴露功能)
- 查找和绑定其他 Bundle 提供的服务
- 监听服务的动态变化(如服务上线/下线)
服务以 Java 接口形式定义,实现了解耦和动态绑定。
-
生命周期管理
每个 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-SymbolicName、Export-Package、Import-Package等)声明模块的依赖和导出内容。 -
包级别的可见性控制:Bundle 可以精确控制哪些 Java 包对外可见(导出),哪些包仅内部使用(私有),从而实现强封装。
Bundle其实就是个jar包, 是OSGi特定描述的一个jar包,具体位置在
META-INF/MANIFEST.MF文件,Bundle有很多中状态。很好的隔离了外部类和内部类,一个个的Bundle组成了基于OSGi的应用,Bundle是组件和服务的载体;SOCM(Service-Oriented Component Model)是面向服务的组件模型(Component),任何一个普通的java对象都可以通过配置文件中的定义来得到,Component其实就是服务的载体,既可以提供对外使用的服务也可以使用外部服务;
![]()
服务层(Service Layer)
OSGi 的核心优势之一,支持面向服务的编程模型。
-
服务(Service):普通 Java 对象(POJO),通过接口注册到 OSGi 服务注册表中。
-
服务注册与发现:
- Bundle 可通过
BundleContext.registerService()发布服务。 - 其他 Bundle 可通过
BundleContext.getServiceReference()或使用服务追踪器(ServiceTracker)或声明式服务(Declarative Services)来消费服务。
- Bundle 可通过
-
动态绑定:服务可以随时注册或注销,消费者能动态响应服务的变化(如服务上线/下线)。
一个OSGi Service就是一个注册到OSGi框架中的java对象,在注册的时候可以设置Service的属性,在获取Service的时候也可以根据属性进行过滤,具体交互过程如图:
![]()
Declarative Service 简称DS,DS可以让我们在Bundle中定义Component,通过配置的方式发布服务和获取服务;
生命周期层
提供对 Bundle 的动态管理能力。
-
BundleContext:每个 Bundle 在启动时获得一个
BundleContext对象,用于与 OSGi 框架交互(如安装/卸载其他 Bundle、注册/查找服务等)。 -
生命周期状态:Bundle 有明确的状态(INSTALLED、RESOLVED、STARTING、ACTIVE、STOPPING、UNINSTALLED)。
-
动态性:支持在运行时安装、启动、停止、更新、卸载 Bundle,无需重启整个应用。
架构
OSGi就如同操作系统一样,为应用程序的运行提供运行环境,我们并不能直接感受到操作系统,但是他一直为我们服务,同样,OSGi我们感知不到他的存在,但是我们却每时每刻都在享受他带给我们的便利;
OSGi一共分三层,就如同网络分层结构一样,层次分明同时逐层依赖,顺序是万万不能颠倒的;
-
模块层:定义了OSGi的概念,称之为bundle,包含元数据、类文件和 相关资源的jar包,Bundle可以声明哪些包可以对外可见,以及声明可以依赖哪些外部包,也就是哪些包是可以导入的;
-
生命周期层: 生命周期层一个是在应用程序的外部定义了Bundle生命周期的操作(安装、卸载等),另一个就是在应用程序的内部定义了Bundle如何访问他们的执行环境;
-
服务层:工作原理与面向服务相似。实现的时候先定义一个接口再实现,用Bundle激活器完成服务注册和服务发现
框架
运行OSGi应用程序,我们需要OSGi容器,常见的OSGi容器有如下几种,都是基于OSGi标准实现的
Apache Felix(推荐)
Apache旗下的一个OSGi框架,项目本身非常成熟,提供的服务也是最全的,几乎涵盖了全部的OSGi 4.2的标准
使用方法:
-
下载,解压
-
启动
java -jar bin/felix.jar <cache-path>,此命令会安装bundle目录所有的bundles。默认的,bundle目录含有shell相关的用户界面来与框架交互。安装到框架的bundle会复制一份到缓存目录(felix-cache)。不指定目录就是本目录下 -
IDEA 安装OSGI插件,加入felix
-
新建一个OSGI项目:JBoss -> OSGI
-
src 同级别下,创建目录和文件 META-INF/manifest.mf
1
2
3
4
5
6Bundle-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 -
创建 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
41package 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.");
}
}
} -
IDEA 配置运行
- 运行配置,选择osgi bundle 选择合适的osgi框架,并将当前module添加进来
- 右键项目,open module settings,在mainfest generation 中 添加 bundle
-
将项目打成jar,安装在Apache Felix中,使用以下命令来安装和启动bundle
1
2install 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 | // 定义一个接口 |
创建一个使用GreetingService的模块ClientModule:
1 | // 实现了OSGi bundle生命周期管理接口BundleActivator |
创建一个包含上述两个模块的META-INF/MANIFEST.MF文件:
1 | Bundle-SymbolicName: com.example.osgi.demo |
运行OSGi应用程序,我们需要一个OSGi容器。常见的OSGi容器有Apache Felix和Eclipse Equinox
将上述代码编译成JAR文件,并将其放入Apache Felix的运行目录中。
1 | # 启动Apache Felix容器,执行以下命令: |