Guice FactoryModuleBuilder an instance with constructor parameters

半腔热情 提交于 2019-12-12 03:24:58

问题


I´m using Guice to initalize a class with some arguments from a config file

@Provides
@Singleton
RetryServiceCaller provideMaxRetryAttempts(@Named("config") JsonObject config) throws IOException {
    JsonObject retryDetails = config.getJsonObject("retry_details");
    return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
                                  retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}

This class is injected in another class which is singleton as well.

class A{
   @Inject private RetryServiceCaller retryServiceCaller;
}

But now the problem is that since this new class A is singleton, I need to clone the retryServiceCaller every time that somebody use this class A.

I´ve been investigating FactoryModuleBuilder to use it and create a factory for this class. But since the class has parameters from the config file I could not find the way to make it works.

Something like this

  class A{
       @Inject private RetryServiceCaller.Factory retryServiceCallerFactory;

   }

Then in my RetryServiceCaller implement this

public interface Factory {
    @Inject
    RetryServiceCaller create();
}


@Inject
public RetryServiceCaller(int maxRetryAttempts, int upperBoundary, int lowerBoundary, long multiplicationFactor, int timeout, int incrementTimeout) {
    this.maxRetryAttempts = maxRetryAttempts;
    this.upperBoundary = upperBoundary;
    this.lowerBoundary = lowerBoundary;
    this.multiplicationFactor = multiplicationFactor;
    this.timeout = timeout;
    this.incrementTimeout = incrementTimeout;
}

But guice throw me errors saying

No implementation for com.proxy.handlers.RetryServiceCaller$Factory was bound

回答1:


Guice can automatically provide a zero-argument factory: Instead of injecting Foo, you can always inject Provider<Foo>. This allows you to call fooProvider.get() to create an instance whenever and wherever you'd like. You don't have to bind to a Provider or use a Provides method to get access to this; you can inject Foo or Provider<Foo> whether you use a bind(...).to(...) type binding, a toProvider binding, a toInstance binding, a @Provides method, or anything else, and Guice will call get or return an internal Provider automatically.

(The returned Provider will also respect scopes, so you'll need to drop your @Singleton scope in order to get more than one instance, and be aware that toInstance bindings will always return the same instance.)

This is not a job for FactoryModuleBuilder; only use FactoryModuleBuilder when you need to mix injected and non-injected constructor parameters in the same type.

Your finished binding should look like this:

@Provides
/* NOT @Singleton */
RetryServiceCaller provideMaxRetryAttempts(@Named("config") JsonObject config) throws IOException {
    JsonObject retryDetails = config.getJsonObject("retry_details");
    return new RetryServiceCaller(retryDetails.getInteger("maxRetryAttempts"), retryDetails.getInteger("upperBoundary"), retryDetails.getInteger("lowerBoundary"),
                                  retryDetails.getLong("multiplicationFactor"), retryDetails.getInteger("timeout"), retryDetails.getInteger("increaseTimeout"));
}

And in your class:

@Inject public YourCallerConsumer(Provider<RetryServiceCaller> callerProvider) {
  this.callerProvider = callerProvider;
}

public void doAction() {
  RetryServiceCaller newCaller = callerProvider.get();
  // interact with caller
}



回答2:


Your first approach should work just fine. If you don't want the RetryServiceCaller to be a singleton, remove the @Singleton annotation from the provider method, and a new instance will be created for every injection point.

Assisted inject could work here too, but it's overkill. If you want to go that route:

interface RetryServiceCallerFactory {
  RetryServiceCaller create(String configParam1, String configParam2);
}

public class RetryServiceCaller {
  @AssistedInject
  public RetryServiceCaller(String configParam1, String configParam2) {}
}

then, in your module

install(new FactoryModuleBuilder().build(Factory.class);

and in your injection points

@Inject RetryServiceCallerFactory factory;

RetryServiceCaller create(JsonObject config) {
  return factory.create(config.getFirstParam(), config.getSecondParam());
}

You can refer to the documentation for more extensive examples.



来源:https://stackoverflow.com/questions/36290073/guice-factorymodulebuilder-an-instance-with-constructor-parameters

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!