Wstrzykiwanie zależności - rozszerzenie

Wstrzykiwanie zależności, które opisywaliśmy w poprzednim rozdziale (Wstrzykiwanie zależności - podstawy) nie wyczerpuje w pełni tematu zarówno w kontekście adnotacji @Autowired jak i innych możliwości wstrzykiwania.

Adnotacja @Qualifier

Kontynuując wątek adnotacji @Autowired musimy odpowiedzieć na jedno pytanie. Co się stanie w przypadku gdy mamy dwie klasy implementujące ten sam interfejs i używając tego interfejsu chcemy wstrzyknąć konkretnie jedną z tych klas? Mamy więc interfejs:
public interface ItemService {

    ItemResponseDTO getItem(Long id);
}
Następnie mamy dwie klasy implementujące ten sam interfejs:
@Service("simpleItemService")
public class SimpleItemServiceImpl implements ItemService {

    ...
}
@Service("compositeItemService")
public class CompositeItemServiceImpl implements ItemService {

    ...
}
Spróbujmy zatem wstrzyknąć ItemService używając jego konkretnej implementacji - SimpleItemServiceImpl. Aby Spring wiedział, że ma wybrać właśnie tą klasę należy ją opisać dodatkowo adnotacją @Qualifier. Jako atrybut podajemy nazwę zdefiniowaną dla konkretnej klasy serwisu:
@RestController
public class ItemController {

    @Autowired
    @Qualifier("simpleItemService")
    private ItemService itemService;
}
W ten sposób wstrzykniemy konkretną implementację interfejsu ItemService do klasy ItemController, czyli nasz cel został osiągnięty. Dodajmy jeszcze dlaczego wstrzykujemy itemService przez pole, a nie tak jak zwykle zalecamy - przez konstruktor. Związane jest to z tym, że nie planujemy pisać testów jednostkowych dla kontrolerów (tylko dla serwisów), a to ma kluczowe znaczenie w kontekście wyboru metody wstrzykiwania (dla zainteresowanych zapraszamy do rozdziału Wstrzykiwanie zależności - podstawy).

Adnotacja @Bean

Kolejnym rozwiązaniem umożliwiającym wstrzyknięcie obiektu jest wykorzystanie adnotacji @Bean. W takim przypadku jeśli jesteśmy w klasie oznaczonej adnotacją @Configuration, możemy zdefiniować jaki obiekt i w jaki sposób chcemy stworzyć (w naszym przypadku PasswordEncoder). W tym momencie Spring uruchomi naszą metodę i zarejestruje obiekt w kontenerze. Wtedy będziemy mogli go wstrzyknąć w innym miejscu korzystając np. z adnotacji @Autowired.
...
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    ...

    @Bean
    public PasswordEncoder passwordEncoder() {
    
        return new PasswordEncoder() {
    
            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                return md5Encoder.getMD5Hash(rawPassword.toString()).equals(encodedPassword);
            }
        
            @Override
            public String encode(CharSequence rawPassword) {
                return md5Encoder.getMD5Hash(rawPassword.toString());
            }
        };
    }
} 
@Service
public class UserService() {
        
    private PasswordEncoder passwordEncoder;
    
    @Autowired
    public UserService(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }
};   
Nasza rekomendacja
Dobrze jest nie nadużywać adnotacji @Bean w celu inicjalizacji włanych obiektów. Najlepiej jest tworzyć klasy oznaczone adnotacjami @Component, @Controller, @Service, @Repository (tak aby klasy wypełniały przeznaczenie tych adnotacji) i tym samym pozostawić inicjalizację obiektów frameworkowi. Oczywiście w pewnych przypadkach jest to niemożliwe, np. gdy chcemy stworzyć obiekt klasy dostępnej w zewnętrznej bibliotece, która nie jest komponentem Springa. Wówczas pozostaje nam użycie wspomnianej adnotacji.
Używamy w StartAPPa


Ciekawostką związana z aplikacją jest to, że stosujemy adnotację @Qualifier, aby czasem odróżnić niektóre szczegóły implementacji w aplikacji dostępnej online od implementacji modułów, które są pobierane przez Was. Na przykład, w danym module używamy innych ścieżek konfiguracyjnych, bądź też łączymy się do innej bazy danych niż moduły (moduły domyślnie mają wbudowaną bazę). Jest to według nas bardzo ciekawy przypadek użycia i dlatego postanowiliśmy o tym wspomnieć. Niemniej przykład opisany wyżej (SimpleItemServiceImpl i CompositeItemServiceImpl) nie pochodzi dokładnie z naszego kodu źródłowego i został specjalnie przygotowany na potrzeby tego kursu. Warto jednak zauważyć, że bazuje on na interfejsie ItemService, który ze względu na swoje znaczenie tematyczne znajdziecie w większości naszych kursów.
Natomiast MD5Encoder to komponent, którego wyciągnęliśmy już bezpośrednio z kursów takich jak: Formularz Zaawansowany, Logowanie & Reset oraz Wykres Danych Statystycznych & Reset.
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-annotation-config
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/factory/annotation/Qualifier.html
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html

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 .