为什么Java IoC框架支持基于注释的注入?

时间:2016-02-17 04:29:05

标签: java dependency-injection inversion-of-control

我查看了几个框架,包括Spring,Guice和Dagger,它们都需要某种形式的注释来标记注入字段/ arg / property / constructor。

例如,给定一个带有注入依赖项的类,这些注入点必须用@Inject标记,以允许IoC容器发挥其魔力:

public class ClassA  {     
  @Inject
  public ClassB objectB;      
  @Inject
  public ClassA(ClassC objectC) {...}
}

这对我来说似乎不对,因为该类已经意识到正在注入该对象。

更简洁的版本只是:

public class ClassA  {
  public ClassB objectB;
  public ClassA(ClassC objectC) {...}
}

@Inject实际上并不需要使用对象...

  • 这些依赖项可以在没有IoC容器的情况下手动注入(这正是我为单元测试所做的)
  • Java反射提供了在不使用注释的情况下识别和实例化适当对象的功能

那么,为什么我们的框架要求我们通过强制让我们的注入接收类知道IoC管理器所在的事实来打破这样一个干净,整洁的抽象?

如果有人能说出一些亮点,那将是非常感激的。

1 个答案:

答案 0 :(得分:0)

Dagger(至少是Google版本)生成与DI相关的代码 - 它使用代码生成器而不是运行时类扫描,因此这种方法很可能是有限的,需要编译时注释。即使它可以避免大多数注释,仍然存在标记应该实际注入哪些字段的问题。

考虑这个伪代码示例:

class Component {
  @Inject Value value;
  @Inject("propertyName") String property;
  Type someHelperValue;
}

在这种情况下,Value实例将被注入value(单例或默认提供程序创建的值)。 property将填充映射到所选名称的选定属性。 someHelperValue将不受影响。

现在考虑一下:

class Component {
  Value value;
  String property;
  Type someHelperValue;
}

如果在没有使用注释的情况下实现注入器,则可能会正确注入Value实例。但是,在分析其他两个领域时,问题就会出现。当字段类型不明确(多个String属性)或在上下文中不可用时,我们应该怎么做(没有Type的单例/提供者)?我们应该忽略它还是抛出异常?

当然,这可以通过使用现有Java机制(如关键字(transient)来标记被忽略的字段和字段名来解决冲突来解决。例如,如果正确实现了注入器,则可以按预期工作:

class Component {
  Value value;
  String propertyName;
  transient Type someHelperValue;
}

propertyName将填充String映射到上下文中的propertyName,而someHelperValue将被忽略。我想的越多,这实际上可行 - 但它仍然没有改变它不那么强大的事实(没有来自注释的附加参数)并且更容易重构(如果你将propertyName键更改为{{1} },该字段将不再正确填充。

总是很高兴能够传递更多参数以使注入器更加健壮,并且只能使用字段名称,类型和标志来做很多事情。注释只是传递这些额外信息的简单方法 - 但是,老实说,它们看起来相当冗长。

(但是,你确实鼓励我尝试这种无注释方法,所以我可能只是实现一个简单的DI框架来看它是如何工作的。)