Внедрение зависимостей Java EE, когда использовать?

Я новичок в этом, и я хочу понять, когда уместно использовать DI в Java. Предположим, мне нужно пропинговать разные сети с разными параметрами пинга:

Класс PingParams:

public class PingParams {
int timeout;
int retries;
}

Класс PingResult:

public class PingResult {
int ttl;
boolean available;
}

Класс PingService:

public class PingService {

private PingParams pingParams;

@Inject
public PingService(PingParams pingParams) {
    this.pingParams = pingParams;
}

public PingResult ping(String ip) {
    // ping using timeout and retries from pingParams
    return new PingResult();
}
}

Клиент:

public class Client {

@Inject
PingService pingService;

private List<PingResult> doPing() {
    List<PingResult> ret = new ArrayList<>();
    String[] ips = new String[] {"127.0.0.1","127.0.0.2"};
    for (String ip : ips) {
        PingResult pr = pingService.ping(ip);
        ret.add(pr);
    }
    return ret;
}

public static void main(String[] args) {
    List<PingResult> prs = new Client().doPing();
    System.out.println(prs);
}
}

У меня есть 2 точки инъекции:

  1. Я ввожу PingParams в конструктор PingService.

Это правильно? Я имею в виду, что контейнер DI не может знать тайм-аут и повторяет попытку внедрения в PingParams, если вы не создадите какой-либо аннотированный метод «Производит», даже в этом случае кажется, что для создания объекта требуется много работы! Но, конечно, вам нужно создать несколько, по одному для каждой сети, как вы это делаете с DI?

  1. Я внедряю PingService в клиент.

Кажется законным, но PingService зависит от PingParams, что приводит нас к точке внедрения номер 1.

Мне кажется, что единственный подходящий способ использования DI — это классы, у которых нет зависимостей (поэтому они бесполезны), или очень простые классы обслуживания, в которых вы передаете все зависимости в качестве параметров методам обслуживания. Например, PingService, который принимает ip и PingParams в методе ping, опять же, этот класс не будет иметь никаких зависимостей...

Я что-то упускаю? Как вы можете использовать DI с этими классами «данных», классами, которые содержат только поля для хранения данных (PingParams)? Предполагается ли избегать DI в этих случаях? Спасибо


person dalvarezmartinez1    schedule 29.12.2013    source источник


Ответы (2)


Как правило, вы должны использовать внедрение зависимостей только для классов, не относящихся к данным. Если у вас есть классы, которые содержат как данные, так и соавторов, не связанных с данными, вы можете использовать внедрение с помощью .

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

Подводя итог: свяжите PingParam при запуске приложения (например, как Singleton), внедрите его в PingService и создайте PingResult без DI (как вы это сделали).

Для ознакомления с передовыми методами внедрения зависимостей я рекомендую прочитать Внедрение зависимостей от Prasanna< /а>

person Alex    schedule 29.12.2013
comment
Большое спасибо. Я не знаю, видели ли вы это: мне нужно пропинговать разные сети с разными параметрами пинга. Проблема может быть моей, поскольку она не приведена в пример. Я пытаюсь сказать, что мне нужно иметь несколько экземпляров PingParams, по одному экземпляру на сеть, которую я пытаюсь пропинговать, так как мне создать эти экземпляры? Без DI это было бы легко, просто создайте экземпляры PingParams и передайте их конструктору PingService, опять же без использования DI. Использование ДИ? не знаю как :) - person dalvarezmartinez1; 29.12.2013
comment
Guice довольно хорош, но в JavaEE есть Weld, который сильно отличается. - person dalvarezmartinez1; 29.12.2013
comment
сварка не знаю. В Guice будут использоваться Именованные привязки, если вы называете/знаете сети. Например, вы можете ввести @NetworkA PingParams params. В противном случае, если список сетей динамический, я бы использовал Multibindings для добавить столько, сколько я хочу. - person Alex; 30.12.2013

Предполагая, что мы говорим о CDI/Weld. Допустим, ваш класс PingParams хранился в БД, так как конфигурация загружалась из какой-то таблицы. Было бы разумно абстрагироваться от этого и просто предоставить метод производителя для класса PingParams, который считывает данные из БД и возвращает этот элемент данных. Неплохо использовать объект данных для этой конфигурации и предоставить для него производителя.

person John Ament    schedule 30.12.2013
comment
Спасибо, Джон, мне пока не ясно, откуда я возьму эти PingParams, я знаю только, что они различаются. Также я не очень хорошо понимаю, как сделать, чтобы этот метод вызывался в нужное время для IP, так как вы не контролируете создание с помощью new. Я должен изучить это. - person dalvarezmartinez1; 30.12.2013