Wstrzykiwanie zależności (ang. dependency injection) jest konkretnym przypadkiem metodyki
wytwarzania oprogramowania, którą nazywamy potocznie z języka angielskiego -
IOC (Inversion of Control).
Odwrócenie sterowania polega na przekazaniu kontroli nad cyklem życia obiektów kontenerowi.
Kontener Springa jest odpowiedzialny za tworzenie obiektów (tzw. beanów) oraz dostarczanie ich w odpowiednim momencie
do danej klasy. Krótko mówiąc, jeśli do tej pory programista chciał stworzyć instancję obiektu, był on
zobowiązany do użycia słowa kluczowego
new:
Obecnie, korzystając z kontenera Springa, w ogóle nie musi się on martwić o wykonanie tej operacji,
ponieważ Spring zrobi to niejawnie za niego. Jak zatem uzyskać referencję do obiektu tworzonego przez
kontener? W bardzo prosty sposób. Obiekt taki możemy wstrzyknąć do naszej klasy poprzez
konstruktor,
pole (field) lub
metodę set (setter).
Wiązania tego typu w zdecydowanej większości przypadków oznaczamy adnotacją
@Autowired:
- Konstruktor - w tym przypadku dodajemy adnotację nad konstruktorem i w ten sposób
wstrzykujemy obiekt itemService jako parametr (od wersji 4.3
Spring umożliwia w ogóle pominięcie adnotacji @Autowired, jednak
tylko w przypadku gdy klasa posiada zdefiniowany tylko jeden konstruktor):
- Pole - ustawiamy adnotację nad polem, co jest nieco rzadziej używane, ze względu na pewne
utrudnienie napotykane podczas tworzenia testów. Ciężko jest bowiem utworzyć obiekt klasy ItemController w przypadku gdy chcemy zainicjować go od razu naszą
własną implementacją ItemService, jeśli konstruktor nie zawiera opcji podania
takiego parametru (zakładamy również, że w teście z jakiegoś powodu nie możemy zainicjować kontekstu Springa, co uniemożliwia użycie adnotacji @Autowired):
- Setter - ustawiamy adnotację nad metodą - przytaczamy dla porządku (chyba kilka razy w
życiu spotkaliśmy coś takiego w kodzie realnego projektu i zawsze dało się to zastąpić
wstrzykiwaniem przez konstruktor - aplikacja StartAPPa również nie zawiera ani jednego przypadku
użycia wstrzykiwania setterem):
Uwagi
Na koniec dwie sprawy, które mogą spędzać sen z powiek u rzetelnych czytelników. Pierwsza z nich dotyczy
stwierdzenia, że adnotacje dodajemy u góry (nad konstruktorem, nad polem itp). Piszemy tak z
przyzwyczajenia, bo to jest bardzo ale to bardzo popularne rozwiązanie. Absolutna większość używanych przez
nas formaterów kodu w projektach jest konfigurowana właśnie w ten sposób. Niemniej dla porządku wspomnijmy,
że można takie adnotacje również napisać przed polem, tudzież konstruktorem. Co prawda wydłuża to linie i podczas czytania właściwy kod miesza
się optycznie z adnotacjami, ale jest to możliwe i działa.
Druga sprawa dotyczy samej adnotacji @Autowired. Czy ona wyczerpuje
wszystkie nasze możliwości, w kontekście opisanych sposobów wiązań? Nie do końca. Alternatywnie możemy użyć
również dwóch innych adnotacji, np. @Resource lub @Inject.
Stosuje się je jednak relatywnie rzadko bowiem raz, że nie pochodza one z samego Springa, a dwa że warto jednak
utrzymywać spojność w kodzie w ramach całości projektu i jeśli coś jest wykonalne za pomocą adnotacji @Autowired,
to zwykle dokonuje się takiego wyboru.
Rekomendacja
Zalecamy wiązanie obiektów w Springu przez konstruktor z użyciem adnotacji @Autowired lub bez (od Springa
4.3, w przypadku posiadania tylko jednego konstruktora w klasie). Sprzyja to pisaniu testów oraz jest
bardziej naturalnym obiektowo rozwiązaniem, poprzez zastosowanie kompozycji obiektów (zawieranie się w
sobie obiektów zależnych).
Jest to szczególnie istotne, gdy piszemy testy jednostkowe, w których nie chcemy stawiać kontekstu Springa. Wówczas
możemy zainicjalizować obiekty już na etapie uruchamiania konstruktora takiego obiektu (przekazując w parametrach referencje do obiektów powiązanych).
Warto pamiętać, że od dłuższego czasu nie musimy sami tworzyć konstruktorów. Wystarczy, że skorzystamy z biblioteki Lombok, która zrobi to za nas,
jeśli użyjemy właściwej adnotacji.
Praktyka
W ramach naszych kursów dotyczących Spring Framework, a także w aplikacji webowej w
Kurs Aplikacji Web - Mega pakiet,
stosujemy adnotację
@Autowired do automatycznego wstrzykiwania zależności.
W większości sytuacji preferujemy wstrzykiwanie zależności poprzez
konstruktor, co jest zgodne z zalecanymi praktykami i zapewnia większą przejrzystość oraz łatwość
testowania kodu.
Autor: Jarek Klimas
Data: 03 stycznia 2024
Labele: Backend, Podstawowy, Java
Czy informacje, które otrzymałeś, były pomocne?
Jeśli tak, zapraszam Cię do podarowania mi kawy.
[TEORIA i PRAKTYKA] Strefa doładowania wiedzy
W tej strefie znajdziesz wszystko co niezbędne, aby komfortowo uczyć się Springa.
Doskonale opisany kod nie zawiera zbędnych komplikacji, tylko samą esencję w postaci praktycznych przykładów.
Tutaj odnajdziesz wszystko co jest istotne w danym temacie. Otrzymujesz pakiet złożony z kilku projektów
wraz z obszernym wytłumaczeniem kodu.
Topowe Materiały
Spring IO: The IoC Container
Spring IO: Dependency Injection
Baeldung: Intro to Inversion of Control
Baeldung: Spring Dependency Injection
Udemy: [NEW] Spring Boot 3, Spring 6 & Hibernate for Beginners — polskie napisy