2015-03-19 2 views
0

Я недавно добавил поле Throttler в класс Server, который должен быть создан, только если включено дросселирование (это запись конфигурации), и если да, то максимальное количество запросов в секунду (другая запись конфигурации) передан его конструктору.Как передать настраиваемый параметр конструктору при использовании Провайдера?

Вот код без зависимостей инъекции Throttler:

public class Server { 
    private Config config; 
    private Throttler throttler; 

    @Inject 
    public Server(Config config) { 
     this.config = config; 

     if (config.isThrottlingEnabled()) { 
      int maxServerRequestsPerSec = config.getMaxServerRequestsPerSec(); 
      throttler = new Throttler(maxServerRequestsPerSec); 
     } 
    } 
} 

public class Throttler { 
    private int maxRequestsPerSec; 

    public Throttler(int maxRequestsPerSec) { 
     this.maxRequestsPerSec = maxRequestsPerSec 
    } 
} 

Теперь впрыснуть Throttler, я использовал Provider, так как это не всегда необходимо создать экземпляр класса. Но теперь я вынужден вводить Config в Throttler и пусть он «настроится»:

public class Server { 
    private Config config; 
    private Provider<Throttler> throttlerProvider; 

    @Inject 
    public Server(Config config, Provider<Throttler> throttlerProvider) { 
     this.config = config; 
     this.throttlerProvider = throttlerProvider; 

     if (config.isThrottlingEnabled()) { 
      this.throttler = throttlerProvider.get(); 
     } 
    } 
} 

public class Throttler { 
    private int maxRequestsPerSec; 

    @Inject 
    public Throttler(Config config) { 
     maxRequestsPerSec = config.getMaxServerRequestsPerSec(); 
    } 
} 

Мне не нравится это решение, потому что:

  1. Существует зависимость из утилиты класса (Throttler) до Config.
  2. Throttler теперь привязан к определенной записи конфигурации, что означает, что он не может использоваться ничем иным, кроме Server.

Я бы предпочел как-то ввести maxRequestsPerSec в конструктор.

Возможно ли это с помощью Guice?

ответ

2

Guice FAQ рекомендует ввести интерфейс фабрики, который строит класс с его зависимостями и дополнительными параметрами, передаваемыми клиентом.

public class Throttler { 
    ... 
    public static class Factory { 
     @Inject 
     public class Factory(... Throttler dependencies ...) {...} 
     public Throttler create(int maxRequestsPerSec) { 
      return new Throttler(maxRequestsPerSec /*, injected Throttler dependencies */); 
     } 
    } 
} 

Таким образом, все прямые зависимости от Throttler остаются инкапсулированные в классе Throttler.

Вы также можете использовать расширение AssistedInject, чтобы уменьшить код шаблона.

+0

Определенно проверить вспомогательную инъекцию, сделать вашу жизнь намного проще. –

0

Это полностью зависит от того, как вы реализуете интерфейс Provider и приложение. Если единственный способ получить maxRequestsPerSec - из Config, вы можете что-то сделать в этих строках:

У вас может быть введена конкретная реализация поставщика, и в этом случае есть сеттер. Поэтому в вашем конструкторе вы вводите CustomProvider<Throttler> (который реализует Provider), затем выполните setMaxRequestsPerSec, а затем используйте это в методе get при создании экземпляра Throttler.

Если вы не хотите вводить CustomProvider, вы можете вместо этого ввести Провайдер, а затем выполнить проверку instanceof, но я думаю, что было бы лучше ввести CustomProvider.

Смежные вопросы