第3章 Atlas整体架构:Bundle容器、动态部署层、组件化路由、资源与So管理

3.1 架构总览:分层边界与核心职责

Atlas 是阿里巴巴开源的组件化(Bundle)框架,其核心思想是将一个大型 App 拆分为多个独立的 Bundle,并在运行时实现动态部署。与 RePlugin 的“插件即独立 APK”不同,Atlas 更强调“组件化容器”,所有 Bundle 共享宿主进程空间,具备更紧密的耦合和更高的性能。

Atlas 架构分为四层,各层边界清晰,职责分离:

  • 运行时容器层 (Bundle Container) — 提供 Bundle 的生命周期管理、ClassLoader 隔离、组件注册与安全校验。
  • 动态部署层 (Dynamic Deployment Layer) — 负责 Bundle 的下载、安装、更新、卸载,以及版本管理和灰度策略。
  • 组件化路由层 (Component Router) — 实现跨 Bundle 的 Activity、Fragment、Service、Provider 等组件的显式/隐式路由跳转。
  • 资源与 So 管理层 (Resource & So Manager) — 统一管理 Bundle 内的资源文件(布局、图片、字符串等)和 Native 库的加载与合并。

以下结构图展示了 Atlas 的四层架构及数据流传递路径:

Atlas 整体架构分层与数据流 运行时容器层(Bundle Container) ClassLoader 隔离 | 生命周期管理 | 安全校验 | 依赖解析 提供容器级 API:安装、卸载、激活、去激活 Bundle 动态部署层(Dynamic Deployment Layer) Bundle 下载 | 安装 | 更新 | 卸载 | 版本管理与灰度策略 支持增量更新、patch 合并、签名校验 组件化路由层(Component Router) Activity / Fragment / Service / Provider 跨 Bundle 路由 | 拦截器 | 降级 资源与 So 管理层(Resource & So Manager) Bundle 资源合并 | 资源 ID 冲突解决 | So 加载与解压 触发资源合并 所有 Bundle 运行在 宿主进程空间

3.2 模块边界与系统分层

分层名称 模块边界 组件职责 对外依赖
Bundle 容器 只管理 Bundle 的生命周期与 ClassLoader,不处理网络、IO、路由 安装/卸载/激活 Bundle、隔离 ClassLoader 命名空间、提供安全校验 依赖宿主 Application Context、系统 ClassLoader
动态部署层 只处理 Bundle 的获取与更新,不感知具体组件 下载、校验、合并 patch、灰度下发、版本回退 依赖网络库(OkHttp/URLConnection)、文件系统、数据库(版本信息)
组件化路由 只处理路由注册、查找、跳转,不涉及资源/So 加载 维护路由表、拦截器、参数解析、降级/兜底策略 依赖宿主路由表、字节码生成辅助
资源与 So 管理 只处理资源对象和 Native 库的合并、加载、缓存 资源包合并、ID 冲突解决、So 解压到宿主加载路径 依赖 AssetManager、System.loadLibrary

3.3 组件职责详解

3.3.1 Bundle 容器

容器层是 Atlas 的核心入口,它维护着 BundleManager 单例,提供 installBundle()、activeBundle()、deactiveBundle() 等接口。每个 Bundle 对应一个独立的 BundleClassLoader,该 ClassLoader 的 parent 为宿主 ClassLoader,但彼此之间不可见,以此实现代码隔离;而资源隔离通过合并式 AssetManager 实现(见 3.3.4)。

设计权衡: 容器层要求所有 Bundle 必须遵循统一的“组件注册表”格式(JSON/XML),容器启动时扫描所有已安装 Bundle 并注册其组件,这与 RePlugin 的“插件即 APK,直接解析”模式相比,前期编译期约束更高,但运行时性能更优。

3.3.2 动态部署层

采用“宿主 + patch”双层版本管理策略。每次部署发布时,Atlas 生成 Base 包与 Patch 包;客户端部署层先从服务端拉取 DiffManifest,基于宿主已安装版本计算增量,只下载变更的 Bundle。以下为典型部署流程:

  1. 轮询/推送 — 客户端向部署服务器查询可用更新。
  2. DiffManifest 下载 — 获取增量包清单和签名。
  3. 增量 Bundle 下载 — 只下载差异部分,宿主本地合成完整包。
  4. 签名校验 — 校验文件摘要与签名,防止篡改。
  5. 容器层安装 — 将 Bundle 放入安装目录,解析组件注册表。

3.3.3 组件化路由层

Atlas 的路由并非完全动态,而是采用“编译期注解 + 运行时查表”模式。通过 APT 在编译期生成 RouterMapping 类,记录每个 Activity/Fragment 与目标 Bundle 的映射;运行时路由层查询该表,按目标 Bundle 是否激活做跳转或降级。

// 编译期生成的 RouterMapping 代码示例(简化)
public final class RouterMapping {
    public static final String ACTIVITY_LOGIN = "com.shop.bundle.user.LoginActivity";
    public static final String BUNDLE_LOGIN = "bundle_user";
    // ...
}

// 运行时路由调用
Router.with(context)
     .url("shop://user/login")
     .param("from", "main")
     .start();

路由层内置“降级兜底”:若目标 Bundle 未安装或版本不匹配,可统一跳转到“下载中”或“错误提示”页面。

3.3.4 资源与 So 管理层

Atlas 的资源管理采用“合并式 AssetManager”,即在宿主进程创建一个“合并后的”全局 AssetManager,将所有 Bundle 的 assets 和 res 合并进来。资源冲突通过编译期分配的固定资源 ID 段解决——每个 Bundle 在 Gradle 插件中声明 bundleId,资源 ID 前缀与其绑定。

// build.gradle 中配置 Bundle ID
atlas {
    bundleConfig {
        bundleId = 10  // 分配给 bundle_user 的资源 ID 段 0x0Axxxxxx
    }
}

So 文件管理则通过“解压 + 合并”策略:所有 Bundle 中的 .so 在安装时被解压到宿主私有目录,运行时通过 System.load() 指定路径,避免 System.loadLibrary 名称冲突。同时 Atlas 支持 SoMerge 模式,将多个 Bundle 的同名 .so 按优先级合并为一个。

风险点: 资源合并策略会带来“资源 ID 碰撞”的风险。若两个 Bundle 分配了相同的 ID 段,运行时可能加载到错误的资源。落地时必须通过 CI 插件严格校验资源 ID 唯一性,否则会出现难以排查的界面错乱。

3.4 数据流与控制流

以“用户点击跳转到另一个 Bundle 的 Activity”为例,完整的数据/控制流如下:

  1. 用户操作 — 宿主 Activity 发起路由调用(Router.with(context).url("shop://detail/item?itemId=123").start())。
  2. 路由层解析 — 路由层查表,判断目标 Activity 属于 bundle_detail。
  3. 容器层查询 — 路由层调用容器层 BundleManager.isActive("bundle_detail"),若未激活则先调用 activeBundle()。
  4. 容器层激活 — 容器层从指定目录加载 Bundle 的 dex 和资源(若未加载过),创建 BundleClassLoader,合并资源到全局 AssetManager。
  5. 路由跳转 — 路由层通过反射或 Intent.setClassName 设置目标 Activity 的完整类名(如 com.shop.detail.DetailActivity),由系统 Intent 机制完成跳转。
  6. So 加载(可选) — 若目标 Activity 依赖 Native 库,资源管理层在 Activity.onCreate 前解压对应的 .so 并调用 System.load()。

3.5 选型权衡与风险点

维度 Atlas 方案 与 RePlugin 对比
代码隔离程度 BundleClassLoader 隔离,但共享宿主堆内存 RePlugin 插件 ClassLoader 完全独立,更严格
资源管理 合并式 AssetManager,ID 冲突风险较高 插件自身 AssetManager,无冲突
部署效率 支持增量 patch,适合频繁更新 全量插件包,更新粒度较粗
编译期侵入 需要 Gradle 插件定制(bundleId、资源段) 几乎零侵入,插件编译独立
学习成本 高(需理解容器、部署、路由、资源管理四层) 低(插件即 APK)

3.6 落地步骤与验收标准

落地步骤

  1. 架构决策 — 评估业务场景是否适合“组件化 + 动态部署”模式,确定使用细粒度 Bundle 还是粗粒度 Bundle。
  2. Gradle 插件集成 — 在宿主工程中引入 Atlas Gradle 插件,配置 BundleConfig(bundleId、依赖关系)。
  3. 容器初始化 — 在 Application.onCreate 中调用 Atlas.getInstance().start(),配置安装目录和 ClassLoader 策略。
  4. 部署层搭建 — 实现部署服务器 API 接口,客户端封装下载/校验逻辑。
  5. 路由接入 — 添加 APT 注解处理器,生成路由表,编写路由拦截器。
  6. 资源与 So 验证 — 启动 CI 任务,对所有 Bundle 的资源 ID 段做冲突检测;交叉编译不同 .so 架构并验证加载。
  7. 灰度发布测试 — 在测试环境中使用少量设备推送 Bundle 更新,验证全链路(下载 → 校验 → 容器激活 → 路由跳转 → 资源展示 → So 调用)。

验收标准

  • 所有 Bundle 能在宿主进程内独立安装、激活、去激活,无 ClassNotFoundException 或 NoSuchMethodError。
  • 资源合并后,所有 Bundle 的界面显示正确,无资源错位或 ID 冲突异常。
  • So 加载接口回调正常,Native 函数调用无 UnsatisfiedLinkError。
  • 路由跳转在目标 Bundle 未激活时能自动触发容器激活,且耗时不超过 500ms(冷启动首次除外)。
  • 增量部署场景下,客户端只下载差异数据,全量 diff 比率低于 20%。