Apache Felix 快速入门与集成示例
Apache Felix 快速入门与集成示例:从环境准备到首个 OSGi bundle 的编写、MANIFEST 要点与部署,并演示以嵌入式 Felix(FrameworkFactory API)启动框架的代码与输出。
Apache Felix 快速入门与集成示例
本文以 Apache Felix Framework 7.0.5 为例,先跑通「启动框架 → 观察 bundle」的最小场景,再编写并部署第一个 OSGi bundle,最后演示在自有 Java 应用中嵌入 Felix 的两种方式。所有回显均来自真实运行。
一、快速入门
1.1 环境准备
| 项目 | 要求 |
|---|---|
| JDK | JDK 11 及以上(示例 bundle 声明 osgi.ee=JavaSE 11) |
| Felix | Apache Felix Framework 7.0.5 发行包 |
| Maven | 3.5+(用于构建示例 bundle) |
| 运行账号 | root |
安装 JDK(以 Ubuntu 22.04 为例):
apt-get update
apt-get install -y openjdk-17-jdk unzip
java -version
openjdk version "17.0.20.1" 2026-08-18
下载并解压 Felix:
mkdir -p /opt/felix
cd /tmp
curl -sL -o felix.zip \
https://archive.apache.org/dist/felix/org.apache.felix.main.distribution-7.0.5.zip
unzip -q felix.zip -d /opt/felix
ls /opt/felix
felix-framework-7.0.5
1.2 首例:启动框架
cd /opt/felix/felix-framework-7.0.5
java -Xms256m -Xmx512m -jar bin/felix.jar
进入 Gogo shell 后执行 lb:
Welcome to Apache Felix Gogo
g! lb
START LEVEL 1
ID|State |Level|Name
0|Active | 0|System Bundle (7.0.5)|7.0.5
1|Active | 1|jansi (1.18.0)|1.18.0
2|Active | 1|JLine Bundle (3.13.2)|3.13.2
3|Active | 1|Apache Felix Bundle Repository (2.0.10)|2.0.10
4|Active | 1|Apache Felix Gogo Command (1.1.2)|1.1.2
5|Active | 1|Apache Felix Gogo JLine Shell (1.1.8)|1.1.8
6|Active | 1|Apache Felix Gogo Runtime (1.1.4)|1.1.4
1.3 解读
- ID 0 是 System Bundle,代表框架自身,版本 7.0.5。
- ID 1–6 是发行包
bundle/目录下 Gogo 技术支持相关的 bundle,由felix.auto.deploy.action=install,start默认自动安装并启动。 - State 一列显示 bundle 运行状态,
Active表示已启动。 - 该启动方式即「独立发行包」形态,shell 中即可完成安装与调试。
二、编写你的第一个 OSGi bundle
2.1 工程结构
hello-osgi/
├── pom.xml
└── src/main/java/com/example/hello/Activator.java
2.2 pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>hello-osgi</artifactId>
<version>1.0.0</version>
<packaging>bundle</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>5.1.9</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>com.example.hello</Bundle-SymbolicName>
<Bundle-Version>1.0.0</Bundle-Version>
<Bundle-Activator>com.example.hello.Activator</Bundle-Activator>
<Export-Package>com.example.hello</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>
<packaging>bundle</packaging> 配合 maven-bundle-plugin 才会生成 OSGi 响应头。
2.3 Activator 实现
package com.example.hello;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
public class Activator implements BundleActivator {
public void start(BundleContext ctx) {
System.out.println("[hello-osgi] Bundle started: " + ctx.getBundle().getSymbolicName());
}
public void stop(BundleContext ctx) {
System.out.println("[hello-osgi] Bundle stopped: " + ctx.getBundle().getSymbolicName());
}
}
2.4 MANIFEST 要点解读
构建后产物 target/hello-osgi-1.0.0.jar 的响应头关键项:
Bundle-ManifestVersion: 2
Bundle-SymbolicName: com.example.hello
Bundle-Version: 1.0.0
Bundle-Activator: com.example.hello.Activator
Export-Package: com.example.hello;uses:="org.osgi.framework";version="1.0.0"
Import-Package: org.osgi.framework;version="[1.8,2)"
Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=11))"
Bundle-SymbolicName+Bundle-Version是 bundle 的唯一标识。Bundle-Activator指定框架在 start/stop 时回调的类。Import-Package声明对 OSGi 核心包的依赖,由 Felix 在解析时从 System Bundle 满足。Require-Capability中的osgi.ee=JavaSE 11要求运行环境至少 JDK 11。
2.5 构建
cd /opt/felix-bundle
mvn -q -B package
ls target/hello-osgi-1.0.0.jar
target/hello-osgi-1.0.0.jar
三、集成示例一:部署到 Felix
在运行中的 Felix Gogo shell 里安装并启动:
g! install file:/opt/felix-bundle/target/hello-osgi-1.0.0.jar
Bundle ID: 7
g! start 7
[hello-osgi] Bundle started: com.example.hello
g! lb
7|Active | 1|hello-osgi (1.0.0)|1.0.0
启动后状态为 Active,Activator#start 输出日志。停止与卸载:
g! stop 7
[hello-osgi] Bundle stopped: com.example.hello
g! uninstall 7
g!
若希望框架启动时自动装载,可在 conf/config.properties 中加入:
felix.auto.start.1=file:/opt/felix-bundle/target/hello-osgi-1.0.0.jar
四、集成示例二:嵌入式 Felix(FrameworkFactory API)
4.1 依赖
嵌入式启动只需把发行包的 bin/felix.jar 加入 classpath,无需额外依赖。
4.2 示例代码
EmbedFelix.java:
import java.util.HashMap;
import java.util.Map;
import java.util.ServiceLoader;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkFactory;
import org.osgi.framework.launch.Framework;
public class EmbedFelix {
public static void main(String[] args) throws Exception {
FrameworkFactory factory = ServiceLoader.load(FrameworkFactory.class).iterator().next();
Map<String, String> config = new HashMap<String, String>();
config.put("org.osgi.framework.storage", "/tmp/embedded-felix-cache");
config.put("felix.log.level", "1");
Framework framework = factory.newFramework(config);
framework.start();
System.out.println("[embed] framework state = " + framework.getState());
Bundle bundle = framework.getBundleContext()
.installBundle("file:/opt/felix-bundle/target/hello-osgi-1.0.0.jar");
bundle.start();
System.out.println("[embed] bundle " + bundle.getSymbolicName()
+ " state = " + bundle.getState());
bundle.stop();
framework.stop();
framework.waitForStop(0);
System.out.println("[embed] framework stopped");
}
}
FrameworkFactory 由 felix.jar 内的 META-INF/services 注册,通过 ServiceLoader 发现。
4.3 编译与运行
cd /root/embed
javac -cp /opt/felix/felix-framework-7.0.5/bin/felix.jar EmbedFelix.java
java -cp .:/opt/felix/felix-framework-7.0.5/bin/felix.jar EmbedFelix
真实输出:
[embed] framework state = 32
[hello-osgi] Bundle started: com.example.hello
[embed] bundle com.example.hello state = 32
[hello-osgi] Bundle stopped: com.example.hello
[embed] framework stopped
state = 32 即 OSGi Bundle.ACTIVE 常量值(0x00000020)。
五、集成示例三:直接实例化 Felix 类
除 FrameworkFactory 外,也可直接使用框架实现类 org.apache.felix.framework.Felix,它实现了 Framework 接口:
import java.util.HashMap;
import java.util.Map;
import org.apache.felix.framework.Felix;
import org.osgi.framework.launch.Framework;
Map<String, String> config = new HashMap<String, String>();
config.put("org.osgi.framework.storage", "/tmp/embedded-felix-cache");
Framework framework = new Felix(config);
framework.start();
// ... 使用 framework.getBundleContext() 安装/启动 bundle
framework.stop();
framework.waitForStop(0);
该写法与 FrameworkFactory 方式行为一致,区别仅在于直接依赖 Felix 实现类,牺牲了可移植性(FrameworkFactory 是 OSGi 标准发现方式,便于切换实现)。
六、常见问题
Q1:mvn package 生成的 jar 缺 OSGi 响应头?
检查 <packaging>bundle</packaging> 是否设置、maven-bundle-plugin 是否配置 <extensions>true</extensions>。
Q2:bundle.start() 抛 BundleException?
多为 osgi.ee 或包导入未满足。用 inspect req osgi.wiring.package <id> 定位缺失依赖,确认 JDK 版本满足 Require-Capability。
Q3:嵌入式启动后缓存目录在哪?
由配置 Map 中的 org.osgi.framework.storage 决定,示例为 /tmp/embedded-felix-cache。
Q4:如何限制嵌入式框架内存?
在启动 JVM 时指定 -Xms256m -Xmx512m,框架本身不管理堆大小。
Q5:ServiceLoader.load(FrameworkFactory.class) 取不到工厂?
确认运行 classpath 中包含发行包的 bin/felix.jar。