Flutter依赖注入插件reflect_inject的使用

Flutter依赖注入插件reflect_inject的使用

ReflectInject

Buy Me A Coffee

为什么?

这个项目是出于学习目的而发起的。由于我目前在Java中使用Spring Boot,我想知道如何实现依赖注入。与一位朋友交流后,他解释说这可以通过反射来实现。在搜索Dart中是否有这种支持时,我发现Dart的反射功能有一些变化,但我决定尝试创建一个可以帮助实现类似Spring Boot依赖注入的插件。我很高兴地看到结果。

注意事项

如前所述,Flutter中的反射支持并不完全成熟。在这个情况下存在一些限制,但我还没有在一个大型应用中测试过使用反射进行依赖注入是否会带来性能损失。我认为这个想法还需要进一步完善,但到目前为止,基于这种方式进行的测试都非常成功。

我们开始吧

如果你查看这个项目,你会发现里面已经有一个示例项目,但我仍然会像往常一样记录所有步骤,以便你理解整个过程是如何工作的。

1 - 注解 reflection

首先,我们需要理解reflection注解。这个注解表示你希望进行注入操作的类可以进行反射操作。其中一个用例是遍历其声明。

因此,任何包含此注解的类都将允许进行反射操作并注入所需的依赖项。

使用示例:

import 'package:reflect_inject/global/instances.dart';

@reflection
class Example {}

2 - 混入 AutoInject

除了反射注解外,你还需要让每个需要注入依赖项的类继承AutoInject混入。这是因为这个混入包含了将在继承该类的方法中执行反射操作,并遍历声明的所有变量以验证哪些变量需要注入依赖项。重要的一点是,这里还保存了静态的依赖项,这样如果其他类依赖于相同的依赖项,则可以重用先前创建的实例。

这个注入过程只在对象被实例化时发生。这是通过调用super.inject()方法来完成的。

使用示例:

import 'package:reflect_inject/injection/auto_inject.dart';
import 'package:reflect_inject/global/instances.dart';

@reflection
class Example with AutoInject {
  Example() {
    super.inject();
  }
}

注意: 需要在类的构造函数中调用super.inject()。这是因为在Dart中不能强制开发者在构造函数中调用这些混入的操作,所以一定要记得调用super以便对类的属性进行注入。

3 - 注解 Inject

这个注解负责指示类的某个属性应该进行依赖注入。让我们理解一下它的用法。

当你使用这个注解时,你会遇到一个必需的参数和一个可选的参数。

  • nameSetter: 在这里,你需要放置一个插件需要调用的方法名来执行注入。由于在Dart中不能直接通过反射初始化变量,所以我们需要通过一个setter方法来完成这个操作。因此,对于每个你想注入依赖项的属性,都需要为其创建一个setter方法并在这个参数中定义它。

  • type: 如果你想使用依赖倒置原则,那么你应该使用这个参数。例如,当你的类依赖于抽象类型,在注入依赖项时需要注入一个实现了或扩展了这个抽象类型的对象。在这种情况下,你需要指定这个类型的名称,以便之后可以创建一个新的实例。

  • global: 默认为false,这个参数定义你的依赖项是否是全局的。如果是这样,另一个依赖于相同依赖项的对象将重用之前创建的实例。

为了更清楚地理解这个过程,这里有一个使用两种形式的示例:

import 'package:reflect_inject/annotations/inject.dart';
import 'package:reflect_inject/injection/auto_inject.dart';
import 'package:reflect_inject/global/instances.dart';

abstract class IService {
  void update();
}

@reflection
class Service extends IService {
  @override
  void update() {}
}

@reflection
class Example with AutoInject {
  @Inject(nameSetter: "setService", type: Service) // 在注入依赖项时会创建一个新的 Service 实例
  late final IService service;

  @Inject(nameSetter: "setOtherService") // 这里不是抽象类
  late final Service otherService;

  Example() {
    super.inject();
  }

  set setService(IService service) {
    this.service = service;
  }

  set setOtherService(Service otherService) {
    this.otherService = otherService;
  }
}

正如你在示例中看到的那样,我的Example类配置了两个属性来进行依赖注入。请注意,这个过程会在创建Example()对象时发生。其中一个属性我传递了type参数,因为它是一个抽象类。请注意,如果你传递了一个抽象类且未定义type,则注入将不会发生,并且你的项目将抛出异常。因此,当插件识别到属性是一个抽象类时,它将根据定义的type创建一个新的实例。

一个重要的点是,对于每个属性,你需要一个setter方法,并且每当你需要进行依赖注入或创建新实例的类,都需要@reflection注解才能执行这些操作。

完成/运行项目

在创建了所有类并添加了注解之后,此时你需要在项目的依赖项中添加build_runner插件,以便生成支持反射的代码。在项目的根目录下,运行以下命令:

flutter pub run build_runner build <DIR>

这里的<DIR>是你程序的主要文件所在的文件夹,例如lib/web/test。这将在你的项目中生成一个名为main.reflectable.dart的文件。

每次你创建新的类并添加新的注解时,都需要运行上述命令以生成带有更改的新文件。完成这个步骤后,在调用runApp之前,你需要调用initializeReflectable方法来初始化反射。

示例如下:

import 'package:reflect_inject/injection/auto_inject.dart';
import 'package:reflect_inject_example/main.reflectable.dart';
import 'package:flutter/material.dart';

void main() {
  AutoInject.init(initializeReflectable); // 初始化反射支持
  runApp(MaterialApp(
    home: Widget(),
  ));
}

更多关于Flutter依赖注入插件reflect_inject的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter依赖注入插件reflect_inject的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


reflect_inject 是一个用于 Flutter 的依赖注入(DI)插件,它允许你通过反射机制来实现依赖注入。依赖注入是一种设计模式,用于实现控制反转(IoC),它可以帮助你管理应用程序中的对象依赖关系,使代码更加模块化、可测试和可维护。

安装 reflect_inject

首先,你需要在 pubspec.yaml 文件中添加 reflect_inject 依赖:

dependencies:
  flutter:
    sdk: flutter
  reflect_inject: ^1.0.0

然后运行 flutter pub get 来安装依赖。

使用 reflect_inject

1. 定义依赖

首先,你需要定义一些依赖项。这些依赖项可以是类、接口或其他对象。

class UserService {
  void fetchUser() {
    print('Fetching user...');
  }
}

class AuthService {
  final UserService userService;

  AuthService(this.userService);

  void login() {
    print('Logging in...');
    userService.fetchUser();
  }
}

2. 配置依赖注入容器

接下来,你需要配置依赖注入容器,将依赖项注册到容器中。

import 'package:reflect_inject/reflect_inject.dart';

void configureDependencies() {
  // 注册 UserService
  DI.register<UserService>(() => UserService());

  // 注册 AuthService,并注入 UserService
  DI.register<AuthService>(() => AuthService(DI.get<UserService>()));
}

3. 获取依赖项

现在,你可以通过 DI.get<T>() 方法来获取依赖项。

void main() {
  configureDependencies();

  // 获取 AuthService 实例
  final authService = DI.get<AuthService>();
  authService.login();
}

4. 使用 @Inject 注解

reflect_inject 还支持使用 @Inject 注解来自动注入依赖项。

class AuthService {
  @Inject()
  UserService userService;

  void login() {
    print('Logging in...');
    userService.fetchUser();
  }
}

在这种情况下,你不需要手动调用 DI.get<UserService>()reflect_inject 会自动注入 UserService 实例。

5. 配置依赖注入容器

void configureDependencies() {
  // 注册 UserService
  DI.register<UserService>(() => UserService());

  // 注册 AuthService,并自动注入 UserService
  DI.register<AuthService>(() => AuthService());
}
回到顶部