在探索Guice时,我对注入依赖项的方式提出了疑问。
根据我的理解,DI的一个重要方面是,依赖性是已知的并且是在运行时注入的。
在Guice中,要注入依赖项,我们需要添加绑定或实现提供程序。添加依赖项需要一个类对象,该类对象在该类上添加编译时依赖项。避免这种情况的一种方法是将其实现为提供程序,并让提供程序使用反射来动态加载类。
public class BillingModule extends AbstractModule {
@Override
protected void configure() {
bind(CreditCardProcessor.class).toProvider(
BofACreditCardProcessorProvider.class);
bind(CreditCardProcessor.class).annotatedWith(BofA.class).toProvider(
BofACreditCardProcessorProvider.class);
bind(CreditCardProcessor.class).annotatedWith(Amex.class).toProvider(
AmexCreditCardProcessorProvider.class);
}
@Provides
PaymentProcessor createPaymentProcessor() {
return new PayPalPaymentProcessor();
}
@Provides
PayPalPaymentProcessor createPayPalPaymentProcessor() {
return new PayPalPaymentProcessor();
}}
为什么Guice选择类对象而不是类名?那可能已经删除了编译时依赖性吗?
答案 0 :(得分:2)
如果您的接口和实现在同一个依赖项中定义(即在同一个JAR文件中),那么您已经对实现具有硬构建依赖性,你是否使用Guice。
基本上,只要你有:
public final class MyClass {
public void doSomething(Foo foo);
}
然后编译MyClass
Foo
的定义需要在编译时类路径上。
解决此问题的方法是将接口与实现分开。例如,如果Foo
是一个接口,并且FooImpl
是它的实现,那么您可以将FooImpl
放在{{1}的不同依赖项(即不同的JAR文件)中}}
现在,让我们假设您在Maven中有两个子项目:
Foo
绑定foo-api/
pom.xml
src/main/java/com/foo/Foo.java
foo-impl/
pom.xml
src/main/java/com/foo/FooImpl.java
的Guice模块应该在哪里生效?它不应该存在于Foo
项目中,它应该与foo-api
一起存在于foo-impl
项目中。
现在假设您有FooImpl
的单独实现(让我们称之为Foo
),您的项目需要SuperFoo
,但它可能是{{1} }或Foo
。
如果我们将FooImpl
作为自己的项目:
SuperFoo
现在您的所有应用程序代码都可以SuperFoo
并使用foo。在super-foo/
pom.xml
src/main/java/com/super/foo/SuperFoo.java
src/main/java/com/super/foo/SuperFooModule.java
方法中(或在您创建@Inject Foo
的任何位置),您需要决定是安装main()
(来自Injector
)还是FooModule
(来自{{ 1}})。
那个是可以保证反思的地方。例如,您可以将配置标记foo-impl
设置为SuperFooModule
或super-foo
。您可以使用以下代码决定安装哪一个:
foo_module
当然,您也可以使用任何其他机制来选择要安装的模块。在许多情况下,您甚至不想反思地执行此操作,只需在更改构建依赖项的同时更改代码即可。