singleton 注入 java_java – Guice Singleton静态注入模式

你错误地考虑了依赖注入.依赖注入和服务定位器是彼此的镜像:使用服务定位器,您可以询问它是否为对象.使用依赖注入,你不会去寻找依赖,它们只是交给你.

基本上,“它一直是乌龟”!应该注入你班级的每一个依赖.如果MyApplication需要MyConfiguration对象,它应该只接受MyConfiguration对象作为构造函数参数,而不用担心它是如何构造的.

现在,这并不是说您永远不能手动使用new – 但是您应该为没有外部依赖性的值类型对象保留它. (在这种情况下,我认为你通常使用静态工厂方法而不是公共构造函数更好,但这不是重点.)

现在有几种方法可以做到这一点.一种方法是将MyConfiguration分成许多小块,这样你就可以执行@Inject @Configuration(“x”)String或类似的东西,而不是做myConfiguration.getConfig(“x”).或者,您可以使MyConfiguration本身可注入,然后为其提供访问器方法.正确的答案在某种程度上取决于您尝试建模的数据类型 – 使依赖关系过于精细化,并且您的绑定可能难以维护(尽管有方法可以使其更好);使依赖关系过于粗糙,你会让它更难测试(例如:哪个更容易,只提供你正在测试的类所需的“x”配置,或构建整个应用程序的配置?).

你甚至可以做到这两点:

/** Annotates a configuration value. */

@BindingAnnotation

@Retention(RetentionPolicy.RUNTIME)

public @interface Config {

String value();

}

/** Installs bindings for {@link MyConfiguration}. */

final class MyConfigurationModule extends AbstractModule {

@Override protected void configure() {}

@Provides

@Singleton

MyConfiguration provideMyConfiguration() {

// read MyConfiguration from disk or somewhere

}

@Provides

@Config("x")

String provideX(MyConfiguration config) {

return config.getConfig("x").getName();

}

}

// elsewhere:

/** The main application. */

final class MyApplication {

private final String xConfig;

@Inject MyApplication(@Config("x") String xConfig) {

this.xConfig = xConfig;

}

// ...

}

您可以在单元测试中采用类似的方法:

/** Tests for {@link MyApplication}. */

@RunWith(JUnit4.class)

public final class MyApplicationTest {

// Note that we don't need to construct a full MyConfiguration object here

// since we're providing our own binding, not using MyConfigurationModule.

// Instead, we just bind the pieces that we need for this test.

@Bind @Config("x") String xConfig = "x-configuration-for-test";

@Before public void setUp() {

// See https://github.com/google/guice/wiki/BoundFields

Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);

}

@Inject MyApplication app;

@Test public void testMyApp() {

// test app here

}

}

依赖注入还鼓励我强烈推荐的另一种最佳实践,即设计类型系统,使无效状态不可表示(尽可能最大程度).如果MyApplication所需的所有配置都在其构造函数中传递,则不可能有一个没有有效配置的MyApplication对象.这允许您“前加载”类不变量,这使得更容易推理对象的行为.

最后,关于Injector.getInstance()的注释.理想情况下,您只需在程序中使用一次Injector:在构建之后立即使用Injector.也就是说,您应该能够执行Guice.createInjector(…).getInstance(MyApplication.class).start()并且永远不会在任何地方存储对Injector的引用.我倾向于使用Guava的ServiceManager抽象构建应用程序(参见this question),所以我唯一需要做的就是:

public static void main(String[] args) throws Exception {

Injector injector = Guice.createInjector(...);

ServiceManager manager = injector.getInstance(ServiceManager.class);

manager.startAsync().awaitHealthy();

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值