我查看了几个框架,包括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管理器所在的事实来打破这样一个干净,整洁的抽象?
如果有人能说出一些亮点,那将是非常感激的。
答案 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框架来看它是如何工作的。)