Metody wstrzykiwania zależności

Koziołek

# Wstęp

W artykule wprowadzającym pokazano podstawową metodę wstrzyknięcia zależności. Oznaczenie pola klasy za pomocą adnotacji samp>@Inject</samp. 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 samp>@Inject</samp 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ę samp>@Inject</samp 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 samp>@PostConstruct</samp.

# 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ą samp>@Inject</samp.
  • Konstruktor może mieć tylko parametry, które są zarządzane przez Guice albo oznaczone adnotacją samp>@Assisted</samp.
  • Jeżeli klasa ma wiele konstruktorów, które powinny być dobierane w zależności od potrzeb to należy je oznaczyć adnotacją samp>@AssistedInject</samp[#]_.

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 samp>@AssistedInject</samp i samp>@Assisted</samp zostały opisane w osobnym artykule.

0 komentarzy