Skip to content

Commit ed2f5f0

Browse files
authored
[2026-03-16] Czy wiesz, że zależności w Springu powinniśmy wstrzykiwać przez konstruktor? (#277)
1 parent 1c264f9 commit ed2f5f0

2 files changed

Lines changed: 175 additions & 0 deletions

File tree

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
---
2+
layout: post
3+
title: "Czy wiesz, że zależności w Springu powinniśmy wstrzykiwać przez konstruktor?"
4+
date: 2026-03-16T08:00:00+01:00
5+
published: true
6+
didyouknow: false
7+
lang: pl
8+
author: bpietrowiak
9+
image: /assets/img/posts/2026-03-16-czy-wiesz-ze-zaleznosci-w-springu-powinnismy-wstrzykiwac-przez-konstruktor/thumbnail.webp
10+
description: "Poznaj zalety tego podejścia, przykłady kodu i wskazówki dotyczące testowania oraz bezpieczeństwa aplikacji."
11+
tags:
12+
- spring boot
13+
- java
14+
---
15+
16+
Czy wiesz, że sposób wstrzykiwania zależności w Springu może mieć ogromny wpływ na jakość Twojego kodu, jego bezpieczeństwo i łatwość testowania?
17+
Jeśli chcesz pisać lepsze aplikacje, warto poznać najważniejsze techniki i wybrać tę, która przynosi najlepsze efekty.
18+
19+
## Czym jest wstrzykiwanie zależności?
20+
21+
Wstrzykiwanie zależności (ang. *Dependency Injection*, DI) w Springu to kluczowy mechanizm,
22+
który umożliwia automatyczne zarządzanie zależnościami pomiędzy obiektami w aplikacji.
23+
Jest to część szerszego podejścia do programowania, znanego jako *Inversion of Control* (IoC),
24+
w którym zarządzanie tworzeniem obiektów i ich zależnościami przekazywane jest z aplikacji do kontenera IoC (w Springu jest nim Spring Container).
25+
26+
## Metody wstrzykiwania zależności
27+
28+
Możemy wyróżnić kilka sposobów wstrzykiwania zależności, z których każdy ma swoje zalety i ograniczenia.
29+
Poniżej przedstawiam najpopularniejsze techniki DI:
30+
31+
- Wstrzykiwanie jawnie zdefiniowanym konstruktorem
32+
```java
33+
@Component
34+
public class OrderService {
35+
private final PaymentService paymentService;
36+
37+
public OrderService(final PaymentService paymentService) {
38+
this.paymentService = paymentService;
39+
}
40+
}
41+
```
42+
43+
- Wstrzykiwanie przez konstruktor z wykorzystaniem adnotacji `@RequiredArgsConstructor`
44+
```java
45+
@Component
46+
@RequiredArgsConstructor
47+
public class OrderService {
48+
private final PaymentService paymentService;
49+
}
50+
```
51+
*Adnotacja `@RequiredArgsConstructor` pochodzi z biblioteki Lombok i automatycznie generuje konstruktor przyjmujący wszystkie pola oznaczone jako `final`
52+
lub z adnotacją `@NonNull`.*
53+
- Wstrzykiwanie przez pola
54+
```java
55+
@Component
56+
public class OrderService {
57+
@Autowired
58+
private PaymentService paymentService;
59+
}
60+
```
61+
*Wstrzykiwanie przez pola jest najmniej zalecanym podejściem, ponieważ utrudnia testowanie i nie pozwala na oznaczenie zależności jako finalne.
62+
Może być stosowane w wyjątkowych przypadkach, np. w bardzo prostych klasach lub kodzie legacy.*
63+
64+
65+
### @Qualifier - kiedy i jak używać?
66+
67+
Adnotacja `@Qualifier` służy do wskazania konkretnego beana, gdy w kontekście Springa istnieje wiele beanów tego samego typu.
68+
Technicznie działa w każdym stylu wstrzykiwania, ale podejścia różnią się czytelnością i łatwością testowania.
69+
70+
Najbardziej czytelnie: `@Qualifier` w konstruktorze
71+
```java
72+
@Component
73+
public class OrderService {
74+
private final PaymentService paymentService;
75+
76+
public OrderService(@Qualifier("paymentService") PaymentService paymentService) {
77+
this.paymentService = paymentService;
78+
}
79+
}
80+
```
81+
82+
Gdy zależność jest opcjonalna: `@Qualifier` w setterze
83+
```java
84+
@Component
85+
public class OrderService {
86+
private PaymentService paymentService;
87+
88+
@Autowired
89+
public void setPaymentService(
90+
@Qualifier("paymentService") PaymentService paymentService) {
91+
this.paymentService = paymentService;
92+
}
93+
}
94+
```
95+
96+
Najmniej zalecane: `@Qualifier` na polu
97+
```java
98+
@Component
99+
public class OrderService {
100+
@Autowired
101+
@Qualifier("paymentService")
102+
private PaymentService paymentService;
103+
}
104+
```
105+
106+
Jeśli używasz Lombok (`@RequiredArgsConstructor`), możesz pozostać przy stylu konstruktorowym i jednocześnie oznaczyć pole adnotacją `@Qualifier`:
107+
108+
```java
109+
@Component
110+
@RequiredArgsConstructor
111+
public class OrderService {
112+
@Qualifier("paymentService")
113+
private final PaymentService paymentService;
114+
}
115+
```
116+
117+
W takim wariancie dodaj w pliku `lombok.config`:
118+
119+
```
120+
lombok.copyableAnnotations += org.springframework.beans.factory.annotation.Qualifier
121+
```
122+
123+
Dzięki temu Lombok przeniesie `@Qualifier` z pola do parametru wygenerowanego konstruktora.
124+
125+
- Wstrzykiwanie przez settery (metody ustawiające)
126+
```java
127+
@Component
128+
public class OrderService {
129+
private PaymentService paymentService;
130+
131+
@Autowired
132+
public void setPaymentService(PaymentService paymentService) {
133+
this.paymentService = paymentService;
134+
}
135+
}
136+
```
137+
*Wstrzykiwanie przez settery może być uzasadnione, gdy zależność jest opcjonalna lub gdy pracujemy z kodem legacy, gdzie nie możemy zmienić konstruktora.*
138+
139+
140+
## Którą metodę powinniśmy wykorzystywać i dlaczego?
141+
142+
Rekomendowanym podejściem jest wykorzystywanie wstrzykiwania przez konstruktor. Oto powody, dla których to podejście jest preferowane:
143+
144+
- **Wymuszenie przekazania zależności podczas tworzenia obiektu** – wstrzykiwanie przez konstruktor gwarantuje,
145+
że wszystkie wymagane zależności zostaną dostarczone w momencie tworzenia instancji obiektu. Dzięki temu unikamy sytuacji,
146+
w której klasa może być używana bez pełnych zależności, co mogłoby prowadzić do błędów w runtime.
147+
- **Niezmienność obiektu** – przypisanie zależności poprzez konstruktor oznacza, że pola te mogą być oznaczone jako `final`,
148+
co zapewnia ich niezmienność i chroni przed niepożądanymi modyfikacjami w trakcie cyklu życia obiektu. Taka konstrukcja promuje czystszy i bardziej bezpieczny kod.
149+
- **Testy jednostkowe** – wstrzykiwanie przez konstruktor ułatwia testowanie,
150+
ponieważ możemy ręcznie dostarczać zależności (np. mocki) bez potrzeby używania takich narzędzi wspomagających, jak refleksja.
151+
To ułatwia pisanie testów jednostkowych i pozwala na zachowanie pełnej kontroli nad zależnościami podczas testowania.
152+
153+
154+
Wstrzykiwanie przez konstruktor wspiera zasady **SOLID**, w szczególności:
155+
156+
- **Single Responsibility Principle (SRP)** – dzięki tej metodzie klasa ma jasno zdefiniowane odpowiedzialności,
157+
a zarządzanie zależnościami odbywa się na poziomie konstrukcji obiektu.
158+
- **Dependency Inversion Principle (DIP)** – poprzez konstruktor, zależności są wprowadzane od zewnątrz,
159+
co wzmacnia niezależność od szczegółowych implementacji.
160+
161+
Wstrzykiwanie przez konstruktor sprawia, że zależności klasy są jasno widoczne i wyraźnie zadeklarowane w jej definicji.
162+
Programista, przeglądając kod, natychmiast widzi, jakie komponenty są wymagane do działania klasy.
163+
164+
W przypadku wstrzykiwania przez konstruktor łatwiej jest zidentyfikować brakujące zależności lub problemy z ich konfiguracją podczas uruchamiania aplikacji,
165+
ponieważ Spring od razu poinformuje nas o braku zależności, której nie można dostarczyć.
166+
167+
Konstruktor pomaga w szybszym wykrywaniu problemów z cyklicznymi zależnościami, które mogą występować w innych formach wstrzykiwania (np. wstrzykiwanie przez pola).
168+
Spring będzie w stanie zidentyfikować takie sytuacje już na etapie konfigurowania obiektów, co ułatwia ich eliminację.
169+
170+
## Podsumowanie
171+
172+
Wstrzykiwanie zależności przez konstruktor to najlepsza praktyka w aplikacjach Spring.
173+
Zapewnia bezpieczeństwo, czytelność kodu, łatwość testowania i zgodność z zasadami SOLID.
174+
Warto przyjąć to podejście jako domyślny standard w każdym projekcie, a inne metody rezerwować dla szczególnych przypadków (opcjonalne zależności, legacy code).
175+
Dzięki temu Twój kod będzie bardziej niezawodny i łatwiejszy w utrzymaniu.
45.8 KB
Loading

0 commit comments

Comments
 (0)