ANGULAR 2 INJECTOR TREE – jak działają serwisy

Angular 2 proponuje nam całkowicie nowe podejście dotyczące serwisów w aplikacji. W Angularze 1.x byliśmy mocno ograniczeni, wszystkie serwisy były singletonami oraz aplikacja posiadała wyłącznie jeden injector. Nowy Angular porzuca te ograniczenia.

DRZEWO INJECTORÓW I INSTANCJE SERWISÓW

Injectory są ściśle powiązane z pojęciem dependency injection, który w ogólnym pojęciu jest wzorcem projektowym. W kontekście angulara, DI (dependency injection) jest całym systemem, bez którego wykonanie aplikacji jest praktycznie niemożliwe. Natomiast Injector w Angularze, jest obiektem, który dostarcza metody do tworzenia instancji zależności.

Angular 2 ma przynajmniej jeden Injector (Root Injector), na głównym poziomie aplikacji. Nie musimy go tworzyć, powstaje samoistnie w tle podczas załadowania aplikacji, w pliku main.ts:

Pozostaje nam go tylko skonfigurować poprzez providers, które są odpowiedzialne za tworzenie serwisów. Provider mówi Injectorowi, w jaki sposób ma stworzyć instancję zależności, wydaje instrukcję.

Czym się różni dodanie serwisu w NgModule a w komponencie?

Wszystkie serwisy, które dodamy w głównym ngModule do tablicy providers: […], zostają zarejestrowane przez Root Injector. Stają się singletonami i są dostępne dla każdego komponentu w aplikacji, wystarczy wstrzyknąć dany serwis do konstruktora w klasie komponentu.

W przypadku dodawania serwisu do providers bezpośrednio w komponencie, powstaje nowy Injector i tworzy nową instancję serwisu, która staje się singletonem dla tego komponentu i wszystkich jego dzieci.

Zobrazujmy sobie to na podstawie drzewa, jakiejś przykładowej, wymyślonej struktury:

 

Jak widzimy, Injector Tree biegnie równolegle do Component Tree. W komponencie OrderProductComponent, dodaliśmy jeszcze raz ProductService do providers. W tym momencie, powstał nowy Injector wraz z nową instancją serwisu. Komponent OrderProduct oraz jego dzieci, będą korzystać już z tej instancji serwisu, a nie z głównej instancji pochodzącej z Root Injector. Brzmi sensownie.

ZŁAMANIE DOMYŚLNEGO SCHEMATU

W naszym diagramie widzimy, że komponenty najniższej położone w drzewie, OrderProductDetail oraz PriceProductDetail korzystają z tego samego ProductService. W przypadku usunięcia ProductService z providers w OrderProductComponent, wszystkie komponenty z danego pod-drzewa, zaczną szukać wstrzykniętego serwisu u Injectora wyżej, aż po sam root injector, póki nie zostaną zaspokojone poprzez kolejne napotkane Providers. Jeśli ostatecznie nie trafią na poszukiwany serwis w żadnej tablicy Providers po drodze ani w Root Injector, angular wypluje nam błąd.

Wyobraźmy sobie teraz scenariusze:

  • OrderProductComponent w przypadku nieznalezienia serwisu ProductService w tablicy providers ma zaprzestać poszukiwania (domyślnie sięgnie po instancję serwisu z Root Injectora)
  • OrderProductComponent ma korzystać z instancji serwisu ProductService pochodzącej z Root Injectora, natomiast jego dzieci-komponenty, mają korzystać już z nowej instancji serwisu, pochodzącej z Order Product Injector

Angular umożliwia nam wyłamanie się z domyślnego schematu, za pomocą dekoratorów @SkipSelf() oraz @Host().

W pierwszym przypadku, jeśli chcemy zablokować szukanie serwisu w parent Injectorach , zrobimy to w następujący sposób:

Dodanie dekoratora @Host(), zapewni nam, że OrderProductComponent sięgnie tylko po ProductService z providers dodanym na poziomie tego komponentu. Jeśli go tam nie znajdzie – nie sięgnie po instancję ProductService z Root Injectora oraz zwróci nam błąd w konsoli, że występuje brak providera dla danego serwisu.

W drugim scenariuszu, jeśli chcemy aby OrderProductComponent skorzystał z instancji ProductService pochodzącej z Root Injectora, musimy użyć dekoratora @SkipSelf():

Należy pamiętać, że użycie @SkipSelf() dotyczy tylko komponentu, które ma zadeklarowane providers: […]. Wszystkie dzieci tego komponentu, skorzystają już z nowej instancji serwisu. Nie zapomnij również zaimportować SkipSelf oraz Host z @angular/core.

Podsumowując, Angular 2 wprowadził rewolucję w Dependency Injection w stosunku do Angulara 1.x. Sposób operowania DI jest przejrzysty, a dzięki narzędziom typu Augury, możemy w graficzny sposób sprawdzić jak wygląda nasze drzewo Injectorów.

One Comment

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *