Wstrzykiwanie zależności - podstawy

Wstrzykiwanie zależności (ang. dependency injection) jest konkretnym przypadkiem metodyki wytwarzania oprogramowania, którą nazywamy potocznie z 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 operatora new:
ItemService itemService = new ItemService();
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):
    public class ItemController {
    
        private ItemService itemService; 
    
        @Autowired
        public ItemController(ItemService itemService) {
            this.itemService = itemService;
        }
    }
    
  • 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ą intrerfejsu 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):
    public class ItemController {
    
        @Autowired
        private ItemService itemService; 
    
        public ItemController(/* bez parametru ItemService */) {
    
        }
        
        ...
    }
    
  • 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):
    public class ItemController {
    
        private ItemService itemService; 
    
        @Autowired
        public void setItemService(ItemService itemService) {
            this.itemService = itemService;
        }    
    }
    
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.
Nasza 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).
Używamy w StartAPPa


W kodzie kursów wszystkie automatyczne wiązania wykonujemy za pomocą adnotacji @Autowired. W zdecydowanej większości przypadków wstrzykujemy dane za pomocą konstruktora. Obecna wersja kursów mogła by pomijać tą adnotację w niektórych przypadkach (zgodnie z naszą rekomendacją), natomiast w kursach postanowiliśmy ją umieszczać, ze względu na przyjętą konwencję przedstawania tego tematu. Lepiej czasem dodać adnotację mając jeden konstruktor, niż zapomnieć o niej (jeśli nie wejdzie nam to w krew) w przypadku gdy klasa będzie miała dwa lub więcej konstruktorów i wywali się w trakcie deploymentu (bo wymagany obiekt nie zostanie wstrzyknięty).
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.
Linki
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-collaborators
https://docs.spring.io/spring/docs/4.3.x/spring-framework-reference/htmlsingle/#beans-autowired-annotation
https://spring.io/blog/2016/03/04/core-container-refinements-in-spring-framework-4-3

Stale się rozwijamy, a więc bądź na bieżąco!
Na ten adres będziemy przesyłać informacje o ważniejszych aktualizacjach, a także o nowych materiałach pojawiających się na stronie.
Polub nas na Facebooku:
Nasi partnerzy:
Javappa to również profesjonalne usługi programistyczne oparte o technologie JAVA. Jeśli chesz nawiązać z nami kontakt w celu uzyskania doradztwa bądź stworzenia aplikacji webowej powinieneś poznać nasze doświadczenia.
Kliknij O nas .