Wstrzykiwanie: Qualifier & Bean

Wstrzykiwanie zależności, które opisywaliśmy w poprzednim rozdziale (Wstrzykiwanie zależności: DI & IoC) 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: DI & IoC).

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;
    }
};   
Rekomendacja
Zaleca się unikanie nadmiernego stosowania adnotacji @Bean do inicjowania własnych obiektów w Spring Framework. Optymalnym podejściem jest definiowanie klas z wykorzystaniem adnotacji takich jak @Component, @Controller, @Service, @Repository. Taki wybór adnotacji powinien odzwierciedlać intencję i funkcjonalność danej klasy, pozwalając tym samym frameworkowi na efektywne zarządzanie procesem inicjalizacji obiektów.

Istnieją jednak sytuacje, w których bezpośrednie wykorzystanie @Bean staje się koniecznością, na przykład przy integracji z klasami z zewnętrznych bibliotek, które nie są w naturalny sposób komponentami Springa. W takich przypadkach, stosowanie @Bean pozwala na precyzyjną konfigurację i zarządzanie instancjami tych klas w kontenerze aplikacji Spring, zapewniając pełną kontrolę nad ich cyklem życia i zależnościami.
Praktyka


W ramach naszej aplikacji wykorzystujemy adnotację @Qualifier w celu dostosowania niektórych aspektów implementacji pomiędzy wersją online a tą prezentowaną w ramach kursu "Kurs Aplikacji Web - Mega pakiet". Dzięki tej technice możemy na przykład stosować różne ścieżki konfiguracyjne lub łączyć się z innymi bazami danych – w wersji kursu wykorzystujemy wbudowaną bazę danych, podczas gdy w aplikacji online konfiguracja ta jest inna. Uważamy, że ten sposób wykorzystania @Qualifier jest interesującym przypadkiem użycia, wartym wspomnienia.
Zdjęcie autora
Autor: Jarek Klimas
Data: 03 stycznia 2024
Labele: Backend, Podstawowy, Java
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: Using the @Bean Annotation
Spring IO: Fine-tuning Annotation-based Autowiring with Qualifiers
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

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: stackshare
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 .


Pozycjonowanie stron: Grupa TENSE