Guice Singleton和Constructor Exceptions

时间:2015-02-20 22:10:46

标签: guice guice-3

我有一个@Singleton类,可以从数据库中加载一些数据。 Singleton在引导期间加载,但构造函数从DAO数据加载类中抛出异常。我从来没有看到过这个异常,我假设是因为Guice的单身自举加载吞噬了它。有没有更好的方法来做到这一点,我至少可以看到堆栈跟踪或异常消息?我希望不必过多地了解这个课程,但也许一旦我用@Singleton标记它,我应该知道在抛出之前记录异常?

1 个答案:

答案 0 :(得分:3)

我建议不要让你的单身人士尝试从数据库的构造函数中加载数据。一般来说,构造者不应该工作。在构造函数中完成工作会使代码更难测试(因为在调用对象上的任何方法之前,需要构造它)。如果使用注入器,它也会减慢进程的速度,并使注入器创建过程变得脆弱,因为依赖关系图中的细微更改将导致初始化以不同的顺序发生。

一种解决方案是使用Guava Service抽象。您在启动时需要完成的任何工作都在服务中进行。服务使用Multibinder.newSetBinder()绑定。

为此,main方法组装模块,创建主类,并在该主类上调用一个方法。您可以在主类中注入ServiceManager,并且entry方法启动服务。

这是一个例子

@Singleton
public class MySingleton {
  private final FooDao dao;
  private final List<Foo> foos = new ArrayList<>();

  @Inject
  MySingleton(FooDao dao) {
    this.dao = dao;
  }

  @VisibleForTesting
  void initialize() {
    foos.addAll(dao.getAllFoos());
  }

  private static class StartupService extends AbstractIdleService {
    private final MySingleton singleton;

    @Inject
    StartupService(MySingleton singleton) {
      this.singleton = singleton;
    }

    @Override protected void startUp() {
      singleton.initialize();
    }
  }

  public static class Module extends AbstractModule {

    @Override protected void configure() {
      Multibinder.newSetBinder(binder(), Service.class)
          .addBinding().to(StartupService.class);
    }
  }
}

您可以通过创建扩展ServiceModule并添加AbstractModule方法的可重复使用的bindService(Class<? extends Service>)类来简化此操作。

如果您愿意使单件类扩展AbstractIdleService,则可以进一步简化此操作,但这会将Service接口中的方法添加到您的单例的公共API中。