跳到主要内容

基础知识

依赖性注入、键、绑定#

  • 应用程序由组件组成,每个组件都有一个内部 id ,称为 Key
  • KeyType 类型和可忽略的限定词 Object (当你需要同一个 Type的不同实现时很有用)。
public class Key<T> {    @NotNull    private final Type type;    @Nullable    private final Object qualifier;}
  • 应用程序组件可能需要一些依赖性才能被创建。
  • 依赖性注入负责为应用程序组件提供这些所需的对象。
  • 为了做到这一点,我们需要指定 ,它需要提供什么 ,以及 ,如何使用提供的对象
  • 因此。 绑定 有两个相应的属性。
 public final class Binding<T> {     final Set<Dependency> dependencies;     final BindingCompiler<T> compiler;}
  • Binding 就像一个 "配方",说明如何创建一个组件的实例。
    • 依赖性 显示应该使用什么成分
    • 编译器 知道如何把它们放在一起煮。
  • 现在,我们需要一些能够使用配方的东西来正确地烹调该组件,这里就有了 Injector

注射器#

  • 为组件 ,以后序方式递归地遍历依赖关系图,并首先创建它们,提供所有需要的依赖关系(注入)。
  • 绑定是默认的单子--如果一个实例被创建过一次,就不会再从头开始创建。 如果 ,它被其他绑定所需要, 注射器 将从缓存中获取它。 你不需要为它应用任何额外的 注释。
  • 为了提供请求的密钥, 注射器 递归地创建它的所有依赖,如果在它的范围内没有找到绑定,则退回到其 父 范围 的注射器。

瞄准镜#

简而言之-- Scope 给我们提供了 "本地单子",它的寿命与范围本身一样长。 ActiveJ Inject的作用域与其他DI库有些不同。

  • 注射器 的内部结构是一个 前缀树 ,前缀是一个范围。
  • 树的标识符(或前缀)是简单的注释。
  • 注射器 可以 进入范围。 这意味着你创建了一个 Injector ,它的范围将被设置为它所进入的那个范围。
  • 这可以做多次,所以你可以在某些范围内有 N 注射器。
public class Injector { ...    final Trie<Scope, ScopeLocalData> scopeDataTree; ...
    public Injector enterScope(Scope scope) {        return new Injector(this, scopeDataTree.get(scope));    } ...}

这个例子 可以向你展示作用域的工作原理。

模块#

依赖关系图很难直接创建,所以我们用简单而强大的DSL提供了自动图转换、生成和验证的 机制。

所有这些预处理步骤都是在启动时通过编译完成的 Modules

  • 每个模块都会输出绑定,这些绑定是相互结合的。 如果任何一个键有两个或更多的绑定, ,它们会被用户提供的 Multibinder reduce函数还原成一个绑定。

    • 这个简单的解决方案使得 ,实现多绑定器 集/地图或任何特定应用的多绑定器变得微不足道。
    • 如果没有为特定的键定义 Multibinder ,则抛出异常。
  • 如果依赖关系图有缺失的依赖关系,它们会被自动生成为 BindingGenerator

    • BindingGenerators是用户定义的,由模块导出。
    • 有一个隐含的 DefaultModule ,默认的 BindingGenerator,它通过扫描所需类的注解自动提供所需的依赖性 Inject
    • 用户指定的模块也可以导出特殊类的自定义绑定生成器
    • 你可以选择不使用 DefaultModule 和其默认的 BindingGenerators。
  • 所有的捆绑都是用用户提供的 BindingTransformers

    • 为了拦截/修改/包裹所提供的实例
    • 拦截/修改/包裹所提供实例的依赖关系
  • Multibinders, BindingGenerators 和 BindingTransformers可以用干净和极其简单的Java8功能DSL制作。

  • 结果的依赖图被验证--检查循环和缺失的依赖,然后编译成最终的范围树并传递给 Injector

<BindingGenerator<?>公共接口 {    Trie<Scope, Map<Key<?>, Set<Binding<?>>>> getBindings();    Map<Integer, Set<BindingTransformer<?>>> getBindingTransformers();    Map<Class<?>, Set>> getBindingGenerators();    Map<Key<?>, Multibinder<?>> getMultibinders();}

手动实现Module接口是很琐碎的,但是扩展 AbstractModule,它支持 @Provides 方法扫描和用于创建/转换/生成绑定的DSL。