简体   繁体   中英

Helper class as a singleton with Guice

I'm learning Google Guice. I understood how to bind an interface to its implementation.

Now, I have the following helper 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();
   }
}

Today, I'm using it like this:

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

I'm pretty sure there is a way to make this class better.

Question : How can I make this class as a singleton using Guice so that I don't lazy load the dbConfig variable at each instanciation ? (I read that there is a @Singleton annotation but, it's considered in Guice just as a scope.)

Regards

Please look at Binding @Provides method as eager singleton See if that helps. The eagerSingleton part might work for you.

Having it as a scope is exactly what you want: Scopes effectively tell Guice when it's allowed to reuse the same object it's already created, and for @Singleton that answer is "always".

If you were to list the class like this:

@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();
  }
}

Then the the class itself becomes a Singleton. The FakeDatabaseConfiguration will be created whenever the class is instantiated, but for all accesses through Guice, that will only happen once.

Of course, none of this applies to direct constructor calls as new PersonHelper() , but with few exceptions Guice is only good at making guarantees about objects that it provides. Any accesses that Guice can control, including through getInstance or @Inject -annotated fields and constructors, will only see PersonHelper (and therefore FakeDatabaseConfiguration) created exactly once.

First, in your module, you have to declare a provider ( FakeDatabaseConfigurationProvider ). As stated, this is the best way to inject a configuration object. Then, declare your helper class as a Singleton and bind it in your module. This will allow your helper class to be used like this :

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

And the same instance will be shared through your app.

Here is the suggested code :

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;
    }
  }
}

Then, in your 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();
    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM