OSGi 通过为每个 Bundle 配备独立 ClassLoader 并采用“先本 Bundle,再依赖,最后父加载器”策略打破双亲委派,结合 Manifest 中 Export-Package 与 Import-Package 的精确声明,实现包级隔离、多版本共存及运行时热插拔。

Java 类加载器在 OSGi 中不是简单复用,而是被重构为模块隔离与动态管理的核心机制。
每个 Bundle 拥有独立 ClassLoader
OSGi 将应用拆分为多个 Bundle(模块),每个 Bundle 都配备专属的 ClassLoader。这个加载器不遵循标准双亲委派,而是采用“先本 Bundle,再依赖,最后父加载器”的策略:
- 优先加载自己 Bundle 内部的类(如
com.example.service.impl.MyService) - 对声明导入的包(
Import-Package: org.slf4j),委托给提供该包的其他 Bundle 加载器 - 仅对
java.*等核心包才委派给 Bootstrap 加载器 - 未声明依赖的类直接抛出
ClassNotFoundException,实现强隔离
通过 Manifest 实现精细的类可见性控制
Bundle 的 META-INF/MANIFEST.MF 文件定义了类边界:
-
Export-Package:声明对外暴露哪些包(含版本号),供其他 Bundle 导入 -
Import-Package:声明依赖哪些包及版本范围(如version="[1.7,2.0)") -
Require-Bundle(较少用):直接依赖另一个 Bundle - 没有导出的包,即使存在也无法被其他 Bundle 访问
支持运行时热插拔与多版本共存
ClassLoader 的独立性让 Bundle 可以在不停机情况下更新:
立即学习“Java免费学习笔记(深入)”;
- 卸载旧 Bundle 时,其 ClassLoader 连同所加载的类一并回收,内存无残留
- 安装新版本 Bundle 后,新 ClassLoader 加载新版类,老版本仍可被正在运行的引用持有
- 不同 Bundle 可同时使用同一类的不同版本(如 Bundle A 用 log4j 1.x,Bundle B 用 2.x)
- 服务注册中心(Service Registry)作为跨 Bundle 通信桥梁,避免直接类引用
与传统 Web 容器(如 Tomcat)的对比
Tomcat 也用多 ClassLoader 实现隔离,但逻辑更静态:
- 每个 WebApp 有独立
WebAppClassLoader,隔离WEB-INF/classes和lib - 仍基本遵守双亲委派,共享
lib下的公共库(如 JDBC 驱动) - 不支持单个模块热更新——重启整个 WAR 才生效
- OSGi 的粒度更细(Bundle 级)、契约更严(包级导入导出)、生命周期更动态


















