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.

0 komentarzy