Helper class 作为 Guice 的单例

Helper class as a singleton with Guice

我正在学习 Google Guice。 我了解如何将接口绑定到它的实现。

现在,我有以下帮手 class :

class PersonHelper {
   public static FakeDatabaseConfiguration dbConfig;
   public PersonHelper(){
      if (dbConfig == null){
          dbConfig = new FakeDatabaseConfiguration();
          dbConfig.setHost('127.0.0.1');
          dbConfig.setPort('3306');
          dbConfig.setUsername('root');
          dbConfig.setPassword('root');
       }
   }

   public List<Person> getPersons(){
      FakeResult fakeResult = dbConfig.executeSQL("select * from Person");
      return fakeResult.asList();
   }
}

今天,我是这样使用它的:

PersonHelper personHelper = new PersonHelper();
List<Person> personsList = personHelper. getPersons();

我很确定有办法让这个 class 变得更好。

问题:如何使用 Guice 将此 class 设为单例,这样我就不会在每次实例化时延迟加载 dbConfig 变量? (我读到有一个 @Singleton 注释,但它在 Guice 中被视为一个范围。)

此致

请查看 Binding @Provides method as eager singleton 看看是否有帮助。 eagerSingleton 部分可能适合您。

将它作为范围正是你想要的:范围有效地告诉 Guice 什么时候允许重用它已经创建的同一个对象,对于 @Singleton答案是 "always".

如果您要像这样列出 class:

@Singleton  // Could also be in your module or @Provides method.
class PersonHelper {
  private FakeDatabaseConfiguration dbConfig;

  public PersonHelper(){
    dbConfig = new FakeDatabaseConfiguration();
    dbConfig.setHost('127.0.0.1');
    dbConfig.setPort('3306');
    dbConfig.setUsername('root');
    dbConfig.setPassword('root');
  }

  public List<Person> getPersons(){
    FakeResult fakeResult = dbConfig.executeSQL("select * from Person");
    return fakeResult.asList();
  }
}

然后 class 本身 成为单例。 FakeDatabaseConfiguration 将在 class 实例化时创建,但对于通过 Guice 进行的所有访问,只会发生一次。

当然,其中 none 适用于直接构造函数调用,如 new PersonHelper(),但除了少数例外,Guice 只擅长对其提供的对象进行保证。 Guice 可以控制的任何访问,包括通过 getInstance@Inject 注释的字段和构造函数,只会看到 PersonH​​elper(因此 FakeDatabaseConfiguration)只创建一次。

首先,在您的模块中,您必须声明一个提供者 (FakeDatabaseConfigurationProvider)。如前所述,这是注入配置对象的最佳方式。 然后,将您的助手 class 声明为 Singleton 并将其绑定到您的模块中。 这将允许您的助手 class 像这样使用:

public class SomeClass{
  @Inject
  private PersonHelper personHelper;
  ...
  public void someMethod(){
    ...
    List<Person> personsList = personHelper.getPersons();
    ..
  }
}

并且将通过您的应用共享同一个实例。

这是建议的代码:

public class MyModule extends AbstractModule {

  @Override
  protected void configure() {
    bind(FakeDatabaseConfiguration.class).toProvider(FakeDatabaseConfigurationProvider.class);
    bind(PersonHelper.class).in(Scopes.SINGLETON);
  }

  /**
   * FakeDatabaseConfigurationProvider implementation
   */
  static class FakeDatabaseConfigurationProvider implements Provider<FakeDatabaseConfiguration> {

    @Override
    public FakeDatabaseConfiguration get() {
      FakeDatabaseConfiguration dbConfig = new FakeDatabaseConfiguration();
      dbConfig.setHost('127.0.0.1');
      dbConfig.setPort('3306');
      dbConfig.setUsername('root');
      dbConfig.setPassword('root');
      return dbConfig;
    }
  }
}

然后,在您的 PersonHelper 中:

public class PersonHelper{
    private FakeDatabaseConfiguration fakeDatabaseConfiguration;
    @Inject
    public PersonHelper(final FakeDatabaseConfiguration fakeDatabaseConfiguration){
        this.fakeDatabaseConfiguration = fakeDatabaseConfiguration;
    }

    public List<Person> getPersons(){
      FakeResult fakeResult = fakeDatabaseConfiguration.executeSQL("select * from Person");
      return fakeDatabaseConfiguration.asList();
    }

}