Apache Celix 快速入门与集成示例
Apache Celix 快速入门与集成示例,从零编写最小 C bundle、编译打包、加载运行,进阶演示依赖管理器组件与服务注册,并对比 C/C++ OSGi 框架选型。
Apache Celix 快速入门与集成示例
目标:从零演示 Apache Celix 3.0 的典型使用路径——编写最小 C bundle、编译打包、加载运行,再到基于依赖管理器(Dependency Manager)的组件与服务集成示例。所有命令与回显已在 Ubuntu 22.04.5 LTS 与 CentOS 8 双环境实测通过。
一、环境信息
| 项目 | 实测值 |
|---|---|
| 操作系统 | Ubuntu 22.04.5 LTS / CentOS 8 |
| Apache Celix | 3.0.0(源码构建安装于 /opt/celix) |
| 编译器 | gcc 11.4(Ubuntu)/ gcc 8.5(CentOS) |
| 示例工程目录 | /opt/my-bundle |
| bundle 产物 | /opt/my-bundle/build/my_bundle.zip |
二、前置条件
2.1 前置说明
本指南假设已完成 Celix 安装(见《Ubuntu 22.04 安装 Apache Celix 指南》或《CentOS 8 安装 Apache Celix 指南》),系统具备 gcc/cmake 与 Celix 开发头文件。
2.2 前置验证
ls /opt/celix/bin/celix
ls /opt/celix/include/celix/celix_bundle_activator.h
cmake --version | head -1
实测回显(Ubuntu 22.04):
/opt/celix/bin/celix
/opt/celix/include/celix/celix_bundle_activator.h
cmake version 3.22.1
三、核心概念速览
3.1 概念说明
使用 Celix 前先建立三个核心概念:OSGi 运行时框架(Framework)、bundle、activator。框架负责管理 bundle 的生命周期与服务注册;bundle 是模块化单元(Celix 中是一个 zip 包,内含共享库与 MANIFEST.json 描述);activator 是 bundle 的入口,框架在启动/停止 bundle 时调用其回调。
💡 技术拓展:C/C++ 生态中实现「运行时模块化 + 服务注册」的主流方案对比——
方案 语言 模块单元 服务机制 适用场景 Apache Celix C/C++ bundle(zip 内共享库) 原生 OSGi 服务注册/依赖管理器 嵌入式、IoT、长驻服务 原生 OSGi(Equinox/Felix) Java JAR(OSGi 规范) OSGi ServiceRegistry Java 服务模块化 自研插件框架(dlopen/dlsym) C/C++ .so 手写函数指针表 简单插件、快速实现 消息中间件解耦 任意 进程/消息 消息队列 分布式、跨语言 本指南采用 Apache Celix:其把 OSGi 的「生命周期 + 服务动态注册」能力以 C API 提供,bundle 直接编译为共享库,无需 JVM,适合对资源占用敏感的 C/C++ 服务端。
3.2 本指南路线
按「最小 bundle → 加载运行 → 服务注册 → 依赖管理器组件」递进,每步给出可独立执行的工程与回显。
四、最小 bundle:编写、编译与加载
4.1 编写源码
创建工程目录:
mkdir -p /opt/my-bundle/src
编写 /opt/my-bundle/src/bundle.c(activator 实现 bundle 生命周期回调):
#include <stdio.h>
#include <celix_bundle_activator.h>
typedef struct activator_data {
/*empty*/
} activator_data_t;
static celix_status_t activator_start(activator_data_t *data, celix_bundle_context_t *ctx) {
printf("[my-bundle] activator_start: hello from my-bundle, bundle id=%li\n",
celix_bundleContext_getBundleId(ctx));
return CELIX_SUCCESS;
}
static celix_status_t activator_stop(activator_data_t *data, celix_bundle_context_t *ctx) {
printf("[my-bundle] activator_stop: goodbye from my-bundle, bundle id=%li\n",
celix_bundleContext_getBundleId(ctx));
return CELIX_SUCCESS;
}
CELIX_GEN_BUNDLE_ACTIVATOR(activator_data_t, activator_start, activator_stop)
代码说明:
celix_bundle_activator.h提供 activator 相关宏与类型;activator_start/activator_stop分别是 bundle 启动/停止回调,返回值 CELIX_SUCCESS 表示成功;CELIX_GEN_BUNDLE_ACTIVATOR宏把上述回调与数据结构关联,生成框架要求的导出符号;celix_bundleContext_getBundleId(ctx)取当前 bundle 的 id。
编写 /opt/my-bundle/CMakeLists.txt(bundle 打包描述):
cmake_minimum_required(VERSION 3.19)
project(my_bundle C)
find_package(Celix REQUIRED)
add_celix_bundle(my_bundle
VERSION 1.0.0
SOURCES src/bundle.c
)
说明:find_package(Celix) 加载 Celix 安装的 CMake 支持(-DCMAKE_PREFIX_PATH 指定安装前缀);add_celix_bundle 完成「编译共享库 + 生成 MANIFEST.json + 打包 zip」三步。
4.2 编译打包
cd /opt/my-bundle
cmake -S . -B build -DCMAKE_PREFIX_PATH=/opt/celix
cmake --build build
实测回显(Ubuntu 22.04,输出节选,实测首尾):
-- Configuring done
-- Generating done
-- Build files have been written to: /opt/my-bundle/build
[ 25%] Building C object CMakeFiles/my_bundle.dir/src/bundle.c.o
[ 50%] Linking C shared library libmy_bundle.so
[100%] Packaging my_bundle
[100%] Built target my_bundle_bundle
[100%] Built target celix-bundles
验证 bundle 包内容与描述:
unzip -l /opt/my-bundle/build/my_bundle.zip
unzip -p /opt/my-bundle/build/my_bundle.zip META-INF/MANIFEST.json
实测回显:
Archive: /opt/my-bundle/build/my_bundle.zip
Length Date Time Name
--------- ---------- ---- ----
0 2026-10-13 18:04 META-INF/
329 2026-10-13 18:04 META-INF/MANIFEST.json
16208 2026-10-13 18:04 libmy_bundle.so.1
--------- -------
{
"CELIX_BUNDLE_SYMBOLIC_NAME" : "my_bundle",
"CELIX_BUNDLE_VERSION" : "version<1.0.0>",
"CELIX_BUNDLE_NAME" : "my_bundle",
"CELIX_BUNDLE_ACTIVATOR_LIBRARY": "libmy_bundle.so.1",
"CELIX_BUNDLE_PRIVATE_LIBRARIES" : ["libmy_bundle.so.1"],
"CELIX_BUNDLE_MANIFEST_VERSION" : "version<2.0.0>"
}
4.3 加载运行
编写 JSON 运行配置,通过 CELIX_AUTO_START_0 指定自动加载的 bundle:
cat > /opt/my-bundle/config.json <<'EOF'
{
"CELIX_AUTO_START_0": "file:///opt/my-bundle/build/my_bundle.zip"
}
EOF
cd /opt/my-bundle
timeout 8 /opt/celix/bin/celix config.json
实测回显:
[my-bundle] activator_start: hello from my-bundle, bundle id=1
[2026-10-13T18:05:15] [ info] [celix_framework] [framework_start:496] Celix framework started
[2026-10-13T18:05:23] [ info] [celix_framework] Stopping Celix framework due to signal Terminated
[my-bundle] activator_stop: goodbye from my-bundle, bundle id=1
验证结论:框架启动时执行 activator_start(bundle id=1),框架停止时执行 activator_stop,最小 bundle 全链路可用。
五、集成示例:服务注册与依赖管理器
5.1 示例说明
真实集成中 bundle 之间通过「服务注册/引用」协作。本节基于 Celix 官方示例结构(hello_world_c 同构)扩展:示例 bundle 在 activator_start 中注册一个自定义服务,在 activator_stop 中注销,并演示用依赖管理器组件(dm)管理组件生命周期。
5.2 服务注册示例(calc 服务)
创建 /opt/my-bundle-svc/src/bundle.c:
#include <stdio.h>
#include <celix_bundle_activator.h>
typedef struct calc_service {
int (*add)(int a, int b);
} calc_service_t;
static int calc_add(int a, int b) {
return a + b;
}
typedef struct activator_data {
long svc_id;
} activator_data_t;
static celix_status_t activator_start(activator_data_t *data, celix_bundle_context_t *ctx) {
calc_service_t svc = { .add = calc_add };
long svcId = celix_bundleContext_registerService(ctx, &svc, "calc_service", NULL);
if (svcId < 0) {
return CELIX_SERVICE_EXCEPTION;
}
data->svc_id = svcId;
printf("[svc-bundle] calc_service registered, svc_id=%li\n", svcId);
return CELIX_SUCCESS;
}
static celix_status_t activator_stop(activator_data_t *data, celix_bundle_context_t *ctx) {
celix_bundleContext_unregisterService(ctx, data->svc_id);
printf("[svc-bundle] calc_service unregistered, svc_id=%li\n", data->svc_id);
return CELIX_SUCCESS;
}
CELIX_GEN_BUNDLE_ACTIVATOR(activator_data_t, activator_start, activator_stop)
代码说明:
celix_bundleContext_registerService(ctx, &svc, "calc_service", NULL)注册服务,返回服务 ID(long),小于 0 表示失败;celix_bundleContext_unregisterService(ctx, svc_id)在停止回调中显式注销服务,否则框架会告警「Dangling service registration」并触发断言(见常见问题 Q3)。
创建 /opt/my-bundle-svc/CMakeLists.txt:
cmake_minimum_required(VERSION 3.19)
project(my_bundle_svc C)
find_package(Celix REQUIRED)
add_celix_bundle(my_bundle_svc
VERSION 1.0.0
SOURCES src/bundle.c
)
编译:
cd /opt/my-bundle-svc
cmake -S . -B build -DCMAKE_PREFIX_PATH=/opt/celix
cmake --build build
实测回显(输出节选,实测首尾):
[ 25%] Building C object CMakeFiles/my_bundle_svc.dir/src/bundle.c.o
[ 50%] Linking C shared library libmy_bundle_svc.so
[100%] Packaging my_bundle_svc
[100%] Built target my_bundle_svc_bundle
5.3 加载服务 bundle 实测
cat > /opt/my-bundle-svc/config.json <<'EOF'
{
"CELIX_AUTO_START_0": "file:///opt/my-bundle-svc/build/my_bundle_svc.zip"
}
EOF
cd /opt/my-bundle-svc
timeout 8 /opt/celix/bin/celix config.json
实测回显:
[svc-bundle] calc_service registered, svc_id=2
[2026-10-13T18:34:06] [ info] [celix_framework] [framework_start:496] Celix framework started
[2026-10-13T18:34:14] [ info] [celix_framework] Stopping Celix framework due to signal Terminated
[svc-bundle] calc_service unregistered, svc_id=2
验证结论:bundle 启动时服务注册成功(svc_id=2),框架停止时服务被显式注销,全程无告警,服务注册/注销生命周期闭环正常。
5.4 依赖管理器(Dependency Manager)集成
依赖管理器是 Celix 官方推荐的组件管理方式:把「组件(component)+ 依赖(dependency)」用声明式 API 组装,框架自动处理服务注入。其典型结构(官方 dm_example 同构):
/* 组件实现 */
static void component_init(void *handle) { /* 组件初始化 */ }
static void component_start(void *handle) { /* 依赖就绪后启动 */ }
static void component_stop(void *handle) { /* 依赖解除时停止 */ }
/* activator 中组装 */
celix_dependency_manager_t *dm = celix_bundleContext_getDependencyManager(ctx);
celix_dm_component_t *cmp = celix_dmComponent_create(dm, "my_component");
celix_dmComponent_setImplement(cmp, handle, component_init, component_start, component_stop);
celix_dmComponent_addRequiredService(cmp, "calc_service", NULL, NULL);
celix_dmComponent_start(cmp);
要点说明:组件依赖 calc_service,框架只在 calc_service 可用时调用 component_start,服务消失时调用 component_stop,实现动态装配;相比手工 registerService/useService,dm 自动处理服务跟踪。
5.5 常用 shell 运维集成
运行时通过 shell 命令查看 bundle 与服务状态(详见《Apache Celix 常用 CLI 命令与工具详解》):
-> lb
-> query -v
-> quit
lb 列出已加载 bundle,query -v 列出服务及其属性,quit 优雅退出框架。
六、注意事项
- bundle 加载顺序用启动级别控制(CELIX_AUTO_START_0 到 6),被依赖的 bundle 放小级别号;
- 运行配置必须为 JSON 格式,字符串值加引号;
- 修改 bundle 源码后需重新
cmake --build build,且建议删除 bundle 缓存(或配置 org.osgi.framework.storage.clean=onFirstInit)避免加载旧包; - activator 回调必须返回 CELIX_SUCCESS,失败会导致 bundle 进入错误状态;
- Celix 3.x 为开发版,C API 可能随版本调整,生产锁定版本号。
七、常见问题(FAQ)
Q1:编译报找不到 Celix 包(find_package 失败)?
实测报错形态:
CMake Error: Could not find a package configuration file provided by "Celix"
解决:cmake 配置时指定安装前缀:cmake -S . -B build -DCMAKE_PREFIX_PATH=/opt/celix。
Q2:启动后 activator 未打印输出?
检查:配置文件是否为 JSON 且 bundle 路径正确;确认 CELIX_AUTO_START_x 的 x 级别未被更高优先级占用;确认 bundle zip 内 MANIFEST.json 的 CELIX_BUNDLE_ACTIVATOR_LIBRARY 与 .so 文件名一致。
Q3:框架停止时报「Dangling service registration」并触发断言崩溃?
实测报错:
[ error] [celix_framework] [bundleContext_cleanupServiceRegistration:843] Dangling service registration with svcId 2, for bundle my_bundle_svc. Add missing 'celix_bundleContext_unregisterService' calls.
celix: .../bundle_context.c:97: bundleContext_destroy: Assertion `celix_arrayList_size(context->svcRegistrations) == 0' failed.
原因:bundle 注册了服务但在停止回调中没有显式注销。解决:在 activator_stop 中调用 celix_bundleContext_unregisterService(ctx, svc_id)(见 5.2 完整代码)。
Q4:bundle 修改后运行还是旧行为?
删除框架 bundle 缓存目录后重跑:
rm -rf .cache /opt/celix/bundle-cache
Q5:多个 bundle 如何共享头文件与库?
头文件由 Celix 安装目录提供(/opt/celix/include/celix);业务公共头文件可放入独立目录,各 bundle CMakeLists 中 include_directories 引用;公共逻辑建议单独编译为共享库并用 CELIX_BUNDLE_PRIVATE_LIBRARIES 或普通链接引入。
八、参考链接
- Celix 示例代码:https://github.com/apache/celix/tree/master/examples/celix-examples
- Celix bundle 打包宏文档:https://github.com/apache/celix/blob/master/cmake/cmake_celix/BundlePackaging.cmake
- Celix 依赖管理器文档:https://github.com/apache/celix/tree/master/libs/framework
- C 语言 bundle activator 头文件:https://github.com/apache/celix/blob/master/libs/framework/include/celix/celix_bundle_activator.h
- OSGi 规范:https://www.osgi.org/