пользовательские аннотации привязки Guice с параметрами - PullRequest
8 голосов
/ 18 апреля 2011

Я успешно создал аннотацию привязки Guice для внедрения однопоточных экземпляров java.util.concurrent.ExecutorService в конструктор.

Вот пример использования:

public class ContainsSingleThreadedExecutorService {


    private final ExecutorService executorService;

    @Inject
    public ContainsSingleThreadedExecutorService(@SingleThreaded ExecutorService executorService) {

        this.executorService = executorService;
    }

}

Теперь я хочу создать аналогичную аннотацию для многопоточных исполнителей, указав в аннотации размер ThreadPool. Например:

public class ContainsMultiThreadedExecutorService {


    private final ExecutorService executorService;

    @Inject
    public ContainsMultiThreadedExecutorService(@MultiThreaded(poolSize = 5) ExecutorService executorService) {

        this.executorService = executorService;
    }

}

Кто-нибудь знает, как я могу получить доступ к значению параметра poolSize от провайдера Guice?

Ответы [ 4 ]

7 голосов
/ 18 апреля 2011

Вы не можете.Это не то, как аннотации привязки предназначены для использования ... параметр будет служить только для дифференциации ExecutorService, связанного с @MultiThreaded(poolSize = 5), от того, связанного с @MultiThreaded(poolSize = 2).Это не метаданные, помогающие настроить Provider.

. Если вы вводите что-то, помеченное @MultiThreaded(poolSize = 5), вам нужно связать что-то с аннотацией @MultiThreaded(poolSize = 5).Если затем вы захотите изменить размер пула, который вы используете во всех этих местах, вам нужно изменить poolSize = 5 на poolSize = 4 как в тех местах, где вы его связали, так и во всех местах, где вы его вводите.Для меня это не имеет большого смысла.

Вместо привязки ExecutorService s к тому, сколько потоков у них в пуле потоков, вы должны связать их в соответствии с тем, для чего вы хотите их использовать.Затем вы можете настроить количество потоков, которые каждый из них использует в одном месте.

2 голосов
/ 14 августа 2012

Вы можете делать подобные вещи (я когда-то делал почти точно) с Guice, но Guice действительно нужно заранее знать, что это за связывание. Так что вам нужно сделать что-то вроде:

for (int i=1; i < 100; i++) {
  ExecutorService svc = Executors.newFixedThreadPool(i);
  bind (ExecutorService.class).annotatedWith(new MultiThreadedImpl(i)).toInstance(svc);
}

(или, более вероятно, привязать к провайдеру, который его лениво инициализирует).

Это достаточно уродливо, что вы, вероятно, на самом деле не хотите этого делать. В любом случае более полезно просто использовать @Named и иметь несколько экземпляров ExecutorService, которые привязаны к имени для конкретной вещи, для которой они хороши - тогда вы можете настроить, сколько потоков используется в одном месте, вместо того, чтобы удивляться "Кто-нибудь использует 73-ниточный ExecutorService?"

2 голосов
/ 18 апреля 2011

Посмотрите на NamedImpl, который реализует @Named и метод Names.named(). Я думаю, что вы должны иметь такую ​​же реализацию.

ОБНОВЛЕНО Guice сравнивает аннотации с помощью hashCode (). Так что, если вы не используете @MultiThreaded(poolSize = 5), вы должны отобразить его перед созданием экземпляра. Это выглядит как грязный обходной путь, но вы можете написать smt как

    for (int i = 1; i < 20; i++){
        bind(ExecutorService.class).annotatedWith(Qualifiers.withValue(i)).toProvider(new DependencyProvider(i));
    } 

Если вы хотите это сделать. Помните, что ваш MultiThreadedImpl должен переопределить hashCode надлежащим образом. Это может быть что-то вроде

@Override
public int hashCode() {
    return  (127 * "poolSize".hashCode()) ^ value;
}
1 голос
/ 12 июня 2014

Да, вы можете.без итератора все ситуации.

На самом деле, у меня почти такая же проблема, как у вас. Здесь - это мой ответ и вопрос со всем моим кодом.Я знаю только, что делать с полем, а не с параметром, но я думаю, что это не большая проблема, верно?

Следуйте CustomInjection в вики, вы узнаете, как.

...