Java » Google Guice

Metody wstrzykiwania zależności



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 1 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ą @AssistedInject2.

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();
        }
 
}


[1] http://jcp.org/en/jsr/detail?id=250
[2] Adnotacje @AssistedInject i @Assisted zostały opisane w osobnym artykule.