GetX 源码层面核心实现原理详解

5 阅读11分钟

一、 GetX 整体架构概述

从源码结构看,GetX 并非单一模块,而是由三大核心模块组成,彼此协同支撑整体功能,源码核心目录结构如下:

get/
├── lib/
│   ├── state_manager/  // 状态管理核心(GetBuilder/Obx/GetX)
│   ├── dependency_injection/  // 依赖注入容器(Get.put/Get.find)
│   ├── navigation/  // 路由管理(非本次重点,暂不展开)
│   └── core/  // 基础工具类(生命周期、全局配置等)

核心依赖关系:依赖注入模块状态管理模块 提供控制器生命周期管理,响应式模块状态管理模块 提供自动刷新能力,三者共同构成 GetX 的核心骨架。

二、 依赖注入(DI)模块:GetX 状态管理的基石

GetX 的依赖注入是其区别于 Provider/Bloc 的核心特性之一,源码核心实现位于 dependency_injection/get_instance.dart 文件中,核心是全局单例容器 + 生命周期绑定

1. 核心容器:GetInstance 类(全局单例)

GetInstance 是 GetX 依赖注入的核心载体,本质是一个键值对缓存容器,用于存储所有注册的控制器(或其他实例),源码核心实现简化如下:

class GetInstance {
  // 全局单例(Dart 私有构造函数实现单例模式)
  static final GetInstance _instance = GetInstance._internal();
  factory GetInstance() => _instance;
  GetInstance._internal();

  // 核心缓存容器:存储实例的键值对,key 为 类型+tag,value 为实例对象及元数据
  final Map<String, _InstanceBuilderFactory> _singl = {};

  // 存储实例的生命周期信息:是否永久存活、绑定的路由等
  final Map<String, _InstanceInfo> _instanceInfo = {};
}
  • 核心设计:通过 _singl 字典缓存实例,键的格式为 “${T.toString()}:$tag”(默认 tag 为空字符串),确保不同类型/不同 tag 的实例不冲突。
  • 单例模式:通过私有构造函数 _internal() 和工厂构造函数 factory GetInstance() 实现全局唯一的 GetInstance 实例,所有 Get.put/Get.find 操作都基于该单例。

2. Get.put():实例注册核心实现

Get.put() 是将实例存入依赖容器的入口方法,源码核心逻辑位于 GetInstance.put(),简化如下:

Future<T> put<T>(
  T dependency, {
  String? tag,
  bool permanent = false, // 是否永久存活(默认false:路由销毁时自动销毁)
  @Deprecated('Use `permanent` instead') bool lazy = true,
}) async {
  // 1. 生成唯一 key(类型 + tag)
  final key = _getKey<T>(tag);

  // 2. 若实例已存在,直接返回现有实例
  if (_singl.containsKey(key)) {
    return _singl[key]!.getInstance() as T;
  }

  // 3. 创建实例构建器,缓存实例到 _singl 容器
  _singl[key] = _InstanceBuilderFactory(
    builder: () => dependency,
    isSingleton: true,
  );

  // 4. 记录实例生命周期信息(是否永久存活、注册时间等)
  _instanceInfo[key] = _InstanceInfo(
    permanent: permanent,
    type: T,
    tag: tag,
  );

  // 5. 返回已缓存的实例
  return dependency;
}

// 生成唯一 key 的辅助方法
String _getKey<T>(String? tag) {
  return tag == null ? T.toString() : '${T.toString()}:$tag';
}
  • 关键逻辑:
    1. 生成唯一键:避免同类型不同实例的冲突(如 Get.put(CountController(), tag: "first")Get.put(CountController(), tag: "second") 是两个独立实例)。
    2. 缓存去重:若容器中已存在对应 key 的实例,直接返回,确保单例特性(默认情况下)。
    3. 生命周期标记:通过 permanent 参数标记实例是否永久存活,为后续自动销毁提供依据。

3. Get.find():实例获取核心实现

Get.find() 是从依赖容器中获取实例的入口方法,源码核心逻辑位于 GetInstance.find(),简化如下:

T find<T>({String? tag}) {
  // 1. 生成唯一 key
  final key = _getKey<T>(tag);

  // 2. 若 key 不存在,抛出异常(未注册的实例无法获取)
  if (!_singl.containsKey(key)) {
    throw "Instance of $T not found. You must call Get.put($T()) first.";
  }

  // 3. 从容器中获取实例并返回
  final instance = _singl[key]!.getInstance() as T;
  return instance;
}
  • 关键特性:无需 BuildContext,直接通过类型 + tag 从全局容器中获取实例,这是 GetX 对比 Provider 的核心优势(Provider 依赖 InheritedWidget 上下文获取实例)。

4. 控制器自动销毁:生命周期绑定实现

GetX 控制器(继承 GetxController)的自动销毁功能,源码核心依赖 GetxController 的生命周期方法 + GetInstance 的缓存清理逻辑,步骤如下:

  1. 控制器生命周期定义GetxController 源码中定义了核心生命周期方法,简化如下:
abstract class GetxController extends DisposableInterface {
  // 初始化时调用
  @mustCallSuper
  void onInit() {}

  // 初始化完成后调用
  @mustCallSuper
  void onReady() {}

  // 销毁时调用(核心:释放资源、取消订阅)
  @mustCallSuper
  void onClose() {}
}
  1. 路由生命周期绑定:当使用 GetX 路由时,路由销毁时会触发 GetInstancedelete() 方法,清理非 permanent 标记的实例,简化如下:
void delete<T>({String? tag, bool force = false}) {
  final key = _getKey<T>(tag);
  final info = _instanceInfo[key];

  // 仅清理 非永久存活 或 强制清理 的实例
  if (info == null || (info.permanent && !force)) {
    return;
  }

  // 1. 调用控制器的 onClose() 方法,释放资源
  final instance = _singl[key]?.getInstance();
  if (instance is GetxController) {
    instance.onClose();
  }

  // 2. 从缓存容器中移除实例
  _singl.remove(key);
  _instanceInfo.remove(key);
}
  • 核心优势:无需手动管理控制器销毁,避免内存泄漏,这是 GetX 对比手动创建控制器的核心优化。

三、 非响应式状态管理:GetBuilder 源码实现

GetBuilder 是 GetX 非响应式状态管理的核心,源码位于 state_manager/get_builder.dart,核心原理是手动标记状态变更 + 观察者订阅通知

1. 核心类结构

GetBuilder 依赖两个核心类协同工作:

  • GetxController:维护状态变量,提供 update() 方法标记状态变更。
  • GetBuilder<T>:作为观察者,订阅控制器的状态变更,触发 UI 重建。

2. update() 方法:状态变更标记实现

update() 方法是触发 GetBuilder 刷新的关键,源码位于 GetxController 中(继承自 DisposableInterface),简化如下:

abstract class GetxController extends DisposableInterface {
  // 存储该控制器对应的观察者(GetBuilder)列表
  final List<Function()> _updaters = [];

  // 手动触发状态更新
  void update([List<Object>? ids, bool condition = true]) {
    if (!condition) return;

    // 遍历所有观察者,通知其刷新 UI
    for (final updater in _updaters) {
      updater();
    }
  }

  // 注册观察者(由 GetBuilder 调用)
  void addListener(Function() listener) {
    _updaters.add(listener);
  }

  // 移除观察者(GetBuilder 销毁时调用)
  void removeListener(Function() listener) {
    _updaters.remove(listener);
  }
}
  • 核心逻辑:
    1. 维护观察者列表:_updaters 存储所有订阅该控制器的 GetBuilder 刷新回调。
    2. 遍历通知:调用 update() 时,遍历 _updaters 列表,执行每个观察者的刷新回调,触发 GetBuilder 重建。
    3. 可选参数:ids 用于局部刷新(指定仅某个/某些 GetBuilder 刷新),condition 用于条件性刷新。

3. GetBuilder<T>:观察者订阅与 UI 重建实现

GetBuilder<T> 是一个 StatefulWidget,其状态类 _GetBuilderState<T> 负责订阅控制器的状态变更,源码简化如下:

class GetBuilder<T extends GetxController> extends StatefulWidget {
  final Widget Function(T) builder;
  final T? init;
  final String? tag;
  final bool global; // 是否使用全局控制器(默认true)

  const GetBuilder({
    required this.builder,
    this.init,
    this.tag,
    this.global = true,
    Key? key,
  }) : super(key: key);

  @override
  _GetBuilderState<T> createState() => _GetBuilderState<T>();
}

class _GetBuilderState<T extends GetxController> extends State<GetBuilder<T>> {
  late T _controller;

  @override
  void initState() {
    super.initState();

    // 1. 获取控制器实例(全局容器 或 局部初始化)
    _controller = widget.global
        ? Get.find<T>(tag: widget.tag)
        : (widget.init ?? Get.put(widget.init!, tag: widget.tag));

    // 2. 注册刷新回调:将 setState 作为观察者添加到控制器的 _updaters 列表
    _controller.addListener(_update);
  }

  // 刷新回调:触发 State 重建,更新 UI
  void _update() {
    if (mounted) {
      setState(() {});
    }
  }

  @override
  Widget build(BuildContext context) {
    // 3. 构建 UI:传递控制器给 builder 方法
    return widget.builder(_controller);
  }

  @override
  void dispose() {
    // 4. 移除观察者:避免内存泄漏
    _controller.removeListener(_update);
    super.dispose();
  }
}
  • 核心流程:
    1. 控制器获取:优先从全局依赖容器中获取(global: true),否则使用局部初始化的控制器。
    2. 订阅状态:将 _update 方法(内部调用 setState)注册到控制器的 _updaters 列表,完成观察者订阅。
    3. 触发重建:当控制器调用 update() 时,_update 方法被执行,通过 setState 触发 GetBuilder 局部重建。
    4. 取消订阅:GetBuilder 销毁时,从控制器的 _updaters 列表中移除 _update 方法,避免内存泄漏。

4. 局部刷新:ids 参数实现原理

GetBuilder 支持通过 ids 参数实现精准局部刷新,源码核心在 update() 方法和 GetBuilder 的初始化逻辑中,简化如下:

// 1. GetxController 的 update 方法增强
void update([List<Object>? ids, bool condition = true]) {
  if (!condition) return;

  // 若未传入 ids,通知所有观察者
  if (ids == null) {
    for (final updater in _updaters) {
      updater();
    }
    return;
  }

  // 若传入 ids,仅通知匹配 id 的观察者
  for (final updater in _updaters) {
    if (ids.contains(updater.id)) { // 简化:实际源码中 updater 携带 id 信息
      updater();
    }
  }
}

// 2. GetBuilder 传入 id 参数
GetBuilder<CountController>(
  id: 'count1', // 唯一标识
  builder: (controller) => Text("计数:${controller.count}"),
)

// 3. 控制器中指定 id 刷新
void increment() {
  count++;
  update(['count1']); // 仅刷新 id 为 count1 的 GetBuilder
}
  • 核心优势:避免不必要的 UI 重建,提升性能,尤其在多 GetBuilder 绑定同一个控制器的场景下。

四、 响应式状态管理:Obx / .obs 源码实现

GetX 响应式状态管理(Obx/.obs)是其核心亮点,源码位于 state_manager/reactive 目录,核心原理是Dart 扩展方法 + 观察者模式(发布-订阅),无需依赖 Stream

1. .obs 扩展方法:可观察对象(Observable)创建

.obs 是 GetX 为所有类型提供的扩展方法,用于将普通对象转化为可观察对象(Observable),源码核心位于 reactive/extensions.dart,简化如下:

// 为所有类型 T 提供 .obs 扩展方法
extension ReactiveExtension<T> on T {
  Rx<T> get obs => Rx<T>(this);
}

// 核心可观察对象类:Rx<T>
class Rx<T> extends RxNotifier<T> {
  Rx(T initialValue) : super(initialValue);

  // 重写 value 属性,实现状态变更监听
  @override
  set value(T newValue) {
    if (_value == newValue) return; // 避免重复更新
    super.value = newValue;
    // 状态变更时,通知所有订阅者
    notifyListeners();
  }

  @override
  T get value => super.value;

  // 简化赋值语法(可选)
  T call([T? v]) {
    if (v != null) {
      value = v;
    }
    return value;
  }
}

// 可观察对象基类:RxNotifier(维护订阅者列表)
class RxNotifier<T> extends ListNotifier {
  T _value;

  RxNotifier(this._value);

  // 订阅者列表(存储 Obx 的刷新回调)
  final List<Function()> _listeners = [];

  // 添加订阅者
  void addListener(Function() listener) {
    _listeners.add(listener);
  }

  // 移除订阅者
  void removeListener(Function() listener) {
    _listeners.remove(listener);
  }

  // 通知所有订阅者
  void notifyListeners() {
    for (final listener in _listeners) {
      listener();
    }
  }
}
  • 核心逻辑:
    1. 扩展方法:ReactiveExtension 为所有类型提供 .obs 方法,快速创建 Rx<T> 实例。
    2. 状态拦截:重写 value 属性的 set 方法,当值发生变更时,自动调用 notifyListeners() 通知所有订阅者。
    3. 避免重复更新:通过 _value == newValue 判断,避免相同值重复触发刷新,提升性能。

2. Obx 组件:观察者订阅与 UI 重建

Obx 是监听可观察对象(Rx<T>)状态变更的核心组件,源码位于 reactive/obx.dart,本质是一个 StatelessWidget(内部通过 Observer 实现订阅),简化如下:

class Obx extends StatelessWidget {
  final Widget Function() builder;

  const Obx(this.builder, {Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // 核心:通过 Observer 组件实现订阅
    return Observer(
      builder: (_) => builder(),
      name: 'Obx',
    );
  }
}

// 核心观察者类:Observer
class Observer extends StatefulWidget {
  final Widget Function(BuildContext) builder;
  final String? name;

  const Observer({
    required this.builder,
    this.name,
    Key? key,
  }) : super(key: key);

  @override
  _ObserverState createState() => _ObserverState();
}

class _ObserverState extends State<Observer> {
  // 刷新回调:触发 UI 重建
  void _update() {
    if (mounted) {
      setState(() {});
    }
  }

  @override
  void initState() {
    super.initState();
    // 注册全局订阅者:GetX 会在可观察对象被访问时,自动绑定该观察者
    Get.reactiveManager.addListener(_update);
  }

  @override
  Widget build(BuildContext context) {
    // 1. 标记当前观察者为活跃状态
    Get.reactiveManager.startTracking();
    // 2. 构建 UI:执行 builder 方法,访问可观察对象
    final widget = this.widget.builder(context);
    // 3. 停止跟踪,绑定可观察对象与当前观察者
    Get.reactiveManager.stopTracking();
    return widget;
  }

  @override
  void dispose() {
    // 4. 移除订阅者,避免内存泄漏
    Get.reactiveManager.removeListener(_update);
    super.dispose();
  }
}

3. 自动绑定核心:ReactiveManager 跟踪机制

Obx 能自动感知 .obs 对象的访问,核心依赖 ReactiveManager 类的跟踪机制,源码位于 reactive/reactive_manager.dart,简化如下:

class ReactiveManager {
  // 全局单例
  static final ReactiveManager _instance = ReactiveManager._internal();
  factory ReactiveManager() => _instance;
  ReactiveManager._internal();

  // 当前活跃的观察者刷新回调
  Function()? _currentListener;

  // 开始跟踪:记录当前观察者的刷新回调
  void startTracking() {
    // _currentListener 由 Observer 传入(即 _update 方法)
  }

  // 停止跟踪:解除当前观察者的绑定
  void stopTracking() {
    _currentListener = null;
  }

  // 当可观察对象被访问时,自动绑定观察者
  void track<T>(RxNotifier<T> rx) {
    if (_currentListener != null && !rx._listeners.contains(_currentListener)) {
      // 将当前观察者的刷新回调添加到可观察对象的订阅者列表
      rx.addListener(_currentListener!);
    }
  }
}
  • 核心流程(自动绑定):
    1. Observer 构建时,调用 startTracking(),将自身的 _update 方法设为 _currentListener(当前活跃观察者)。
    2. 执行 builder 方法,当访问 Rx<T> 对象的 value 属性时,会触发 ReactiveManagertrack() 方法。
    3. track() 方法将 _currentListener_update)添加到 Rx<T> 的订阅者列表 _listeners 中,完成自动绑定。
    4. Observer 构建完成后,调用 stopTracking(),解除当前活跃观察者标记。
    5. Rx<T>value 变更时,调用 notifyListeners(),执行 _update 方法,触发 setState 重建 Obx UI。

4. 关键特性:精准局部重建

Obx 仅会刷新自身包裹的 UI 组件,核心原因是:

  • 每个 Obx 对应一个独立的 Observer 状态类,其 _update 方法仅触发自身的 setState
  • 可观察对象仅通知订阅它的 Observer,不会影响其他未订阅的组件,实现精准局部刷新,性能优于全局重建。

五、 GetX 源码核心设计总结

  1. 依赖注入核心:基于 GetInstance 全局单例容器,通过 Get.put() 缓存实例、Get.find() 获取实例,配合 permanent 参数实现控制器自动销毁,无需手动管理生命周期。
  2. 非响应式状态管理(GetBuilder):基于 GetxController_updaters 观察者列表,update() 手动通知刷新,GetBuilder 订阅并通过 setState 实现局部重建,性能开销极低。
  3. 响应式状态管理(Obx/.obs)
    • .obs 通过扩展方法将普通对象转为 Rx<T> 可观察对象,重写 value 属性拦截状态变更。
    • Obx 基于 Observer 组件,通过 ReactiveManager 自动跟踪可观察对象的访问,完成订阅绑定。
    • 状态变更时,Rx<T> 通知所有订阅者,Observer 触发局部重建,无需手动调用 update()
  4. 核心优势底层支撑
    • 无需 BuildContext:依赖全局 GetInstance 容器,而非 InheritedWidget
    • 精准局部刷新:观察者模式确保仅订阅的组件重建,避免无效开销。
    • 低侵入性:无需顶层包裹组件,按需使用 GetBuilder/Obx,代码简洁。