Metody wstrzykiwania zależności
Koziołek
1 Wstęp
2 Wstrzyknięcia przez metodę ustawiającą
3 Wstrzyknięcie przez konstruktor
4 Różnice
5 Użycie wielu metod w jednej klasie
Wstęp
W artykule wprowadzającym pokazano podstawową metodę wstrzyknięcia zależności. Oznaczenie pola klasy za pomocą adnotacji @Inject. Google Guice udostępnia też inne sposoby na wstrzyknięcie zależności.
W artykule będą wykorzystane przykłady z tekstu wprowadzającego.
Wstrzyknięcia przez metodę ustawiającą
Jednym ze sposobów wstrzyknięcia zależności jest oznaczenie metody za pomocą adnotacji @Inject tak jak na poniższym listingu.
package net.programers4.guice;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class MySystem {
private BussinessInterface bussinessInterface;
public void callBussinessInterface() {
bussinessInterface.printMessage();
}
public BussinessInterface getBussinessInterface() {
return bussinessInterface;
}
@Inject
public void setBussinessInterface(BussinessInterface bussinessInterface) {
this.bussinessInterface = bussinessInterface;
}
}
Sposób przetwarzania nie różni się w tym przypadku od oznaczenia pola. Metoda ma pewne właściwości i musi spełniać pewne kryteria:
- Metoda musi mieć parametry, które mogą zostać wstrzyknięte. Inaczej mówiąc wszystkie klasy (interfejsy) wykorzystywane jako parametry muszą być dodane do konfiguracji Guice (nie dotyczy klas).
- Metoda może zwracać wartość, ale nie ma możliwości pobrania tej wartości.
- Może być wiele metod posiadających adnotację @Inject i pozwalających na ustawienie tego samego pola. Wszystkie zostaną wywołane.
Jak widać w tym przypadku mamy bardzo dużą swobodę jeśli chodzi m.n. o sygnaturę metody. Jeżeli jednak chcemy wykorzystać metodę do przeprowadzenia dodatkowych akcji to warto w tym celu wykorzystać adnotacje JSR-250 [#]_ i zdefiniowanej tam adnotacji @PostConstruct.
Wstrzyknięcie przez konstruktor
Guice udostępnia wstrzykiwanie zależności poprzez konstruktor. Klasa i konstruktor muszą spełniać następujące warunki:
- Tylko jeden konstruktor może zostać oznaczony adnotacją @Inject.
- Konstruktor może mieć tylko parametry, które są zarządzane przez Guice albo oznaczone adnotacją @Assisted.
- Jeżeli klasa ma wiele konstruktorów, które powinny być dobierane w zależności od potrzeb to należy je oznaczyć adnotacją @AssistedInject[#]_.
Przykładowa klasa gdzie wykorzystano ten sposób wstrzykiwania zależności:
package net.programers4.guice;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class MySystem {
private BussinessInterface bussinessInterface;
@Inject
public MySystem(BussinessInterface bussinessInterface) {
super();
this.bussinessInterface = bussinessInterface;
}
public void callBussinessInterface() {
bussinessInterface.printMessage();
}
}
Różnice
Opisane tu metody różnią się pomiędzy sobą tym w jakim stanie jest obiekt w momencie wstrzykiwania zależności. Jeżeli wykorzystujemy metodę ustawiającą albo adnotujemy pole to wstrzyknięcie jest wykonane już po utworzeniu obiektu. Oznacza to, że istnieje okres pomiędzy wywołaniem konstruktora, a zakończeniem wstrzykiwania zależności kiedy obiekt jest w stanie nieokreślonym i nie jest w pełni zainicjowany. Z tego też powodu należy zwrócić uwagę na to czy obiekt taki jest wykorzystywany przez inne obiekty. Jeżeli inne obiekty wywołają metody nie w pełni zainicjowanego obiektu może to doprowadzić do trudnej do usunięcia usterki.
W przypadku wstrzyknięcia z wykorzystaniem konstruktora nie ma takiego ryzyka ponieważ tworzenie obiektu jest z założenia operacją atomową. Obiekt będzie dostarczony w spójnym stanie.
Użycie wielu metod w jednej klasie
Jeżeli zajdzie taka potrzeba możemy użyć wielu sposobów wstrzyknięć w ramach jednej klasy. Przykładowa klasa wykorzystująca wstrzyknięcia zarówno za pomocą konstruktora jak i adnotacji pola:
package net.programers4.guice;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class MySystem {
private BussinessInterface bussinessInterface;
@Inject
private BussinessInterface bussinessInterface2;
@Inject
public MySystem(BussinessInterface bussinessInterface) {
super();
this.bussinessInterface = bussinessInterface;
}
public void callBussinessInterface() {
bussinessInterface.printMessage();
}
}
.. [#] http://jcp.org/en/jsr/detail?id=250
.. [#] Adnotacje @AssistedInject i @Assisted zostały opisane w osobnym artykule.