Инжектиране на зависимост от 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, освен ако не създадете някакъв анотиран метод "Produces", дори в този случай това е огромна работа само за създаване на обект! Но, разбира се, трябва да създадете няколко, по една за всяка мрежа, как да направите това с 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. Използване на 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 клас се съхранява в DB като конфигурация, заредена от някаква таблица. Би имало много смисъл да се абстрахира това и просто да се предостави метод на производител за класа PingParams, който чете данните от DB и предоставя обратно този елемент от данни. Не е лоша идея да използвате обект с данни за тази конфигурация и да предоставите производител за него.

person John Ament    schedule 30.12.2013
comment
Благодаря, Джон, все още не ми е ясно откъде ще взема тези PingParams, знам само, че се различават. Също така не разбирам много добре как да накарам този метод да бъде извикан в точното време за IP, тъй като вие не контролирате създаването с помощта на new. Ще трябва да го разгледам. - person dalvarezmartinez1; 30.12.2013