Wstęp
Spring to jeden z najpopularniejszych frameworków w świecie Javy. Jednym z jego kluczowych elementów jest zarządzanie komponentami za pomocą adnotacji, takich jak @Component
, @Service
, @Repository
i @Controller
. Chociaż wszystkie pełnią podobną rolę – rejestrowanie klas w kontenerze Springa – to każda z nich ma swoje specyficzne przeznaczenie. Pozostaje pytanie czym się różnią i kiedy, której używać.
@Component – podstawowa adnotacja
@Component
to najbardziej ogólna adnotacja służąca do oznaczania klas jako komponentów Springa. Każda klasa oznaczona tą adnotacją jest rejestrowana w kontekście aplikacji jako Spring Bean.
@Component public class MyComponent { public void doSomething() { System.out.println("Wykonuję zadanie!"); } }
@Component
można stosować do dowolnych komponentów aplikacji, jednak w większości przypadków używa się bardziej precyzyjnych adnotacji, takich jak @Service
, @Repository
czy @Controller
. Samej adnotacji użyjemy do bardziej ogólnego użytku, która nie pasuje do żadnego typu z trzech pozostałych np. klasy pomocnicze jak walidacja czy obliczenia matematyczne, konfiguracja z zewnętrznymi bibliotekami.
@Service – warstwa logiki biznesowej
Adnotacja @Service
rozszerza funkcjonalność @Component
i oznacza, że dana klasa zawiera logikę biznesową aplikacji. Dzięki temu nasz kod staje się czytelniejszy, bo wchodząc do takiego serwisu, wiemy, że mamy do czynienia z jakąś logiką biznesową np. operacje na encjach.
@Service public class UserService { public String getUserInfo() { return "Dane użytkownika"; } }
@Repository – warstwa dostępu do danych
Adnotacja @Repository
jest dedykowana dla klas odpowiedzialnych za dostęp do danych. Ważna cechą tej adnotacji jest to, że Spring widząc ją, automatycznie przechwyci wyjątki związane z bazą danych (zostaną przetłumaczone na wyjątek DataAccessException
).
@Repository public interface UserRepository extends JpaRepository<User, Long> { User findByUsername(String username); }
@Controller – obsługa żądań HTTP
@Controller
to adnotacja dedykowana dla warstwy kontrolerów w Springu. Oznacza klasę, która obsługuje żądania HTTP i zwraca widoki.
@Controller public class UserController { @GetMapping("/users") public String getUser(Model model) { model.addAttribute("username", "Jan Kowalski"); return "userView"; } }
Jeśli chcesz, aby kontroler zwracał dane JSON/XML, zamiast HTML, użyj @RestController
lub dodaj do adnotacji @Controller
, adnotację @ResponseBody
.
@RunWith(SpringRunner.class) @RestController public class UserController { @GetMapping("/api/users") public String getUser() { return "Jan Kowalski"; } }
Testowanie aplikacji, a odpowiednia adnotacja komponentu
Kiedy nasza aplikacja Spring Boot się rozrasta, testowanie jej w całości staje się coraz większym wyzwaniem – testy działają wolno i bywają trudne w utrzymaniu. pełne testy integracyjne mogą ciągnąć się wiekami i być skomplikowane w utrzymaniu. Na szczęście twórcy frameworka pomyśleli i o tym, dając nam mechanizm testowania slices – czyli wybranych fragmentów aplikacji (np. tylko warstwy webowej albo dostępu do danych). Co to oznacza w praktyce? Prostsze i bardziej skoncentrowane testy, a przede wszystkim – ogromna oszczędność czasu przy ich uruchamianiu.
Testy slice
Na początku przybliżmy sobie czym jest to testowanie fragmentami (test slices). Testy te pozwalają na testowanie określonych warstw aplikacji w izolacji, bez uruchamiania całego kontekstu aplikacji. Dzięki nim możemy skupić się tylko na konkretnej funkcjonalności, np. warstwie webowej, repozytoriach, czy kontrolerach REST, bez ładowania wszystkich komponentów.
Spring Boot dostarcza specjalne adnotacje dla różnych rodzajów testów slices. W tabeli poniżej opisałem te adnotacje wraz z relacją do odpowiednich adnotacji dla komponentów.
Adnotacja komponentu | Adnotacja testu slice | Testowane komponenty |
---|---|---|
@Controller | @WebMvcTest | Kontrolery MVC, filtry, konfiguracja webowa |
@RestController | @WebMvcTest | Kontrolery REST, konfiguracja webowa |
@Repository | @DataJpaTest | Repozytoria Spring Data, konfiguracja JPA |
@Service | Brak bezpośredniego odpowiednika – zwykle mockowane w testach innych warstw | Logika biznesowa |
@Component | Brak bezpośredniego odpowiednika – zależnie od przeznaczenia | Różne komponenty aplikacji |
Oczywiście istnieje więcej typów adnotacji dla testów slice. W dokumentacji Springa jest opisana cała lista dostępnych adnotacji wraz z kontekstem jaki wczytuje (link do dokumentacji).
Przykład testów slice
Mechanizm testów slices działa poprzez selektywne ładowanie tylko tych komponentów, które są wymagane dla danej warstwy. Na przykład, @WebMvcTest
ładuje tylko kontrolery oraz konfigurację związaną z MVC, pomijając repozytoria, serwisy i inne komponenty. Komponenty, które nie są automatycznie ładowane, można zamockować za pomocą @MockBean
lub zaimportować używając @Import
.
@WebMvcTest(UserController.class) class UserControllerTest { @Autowired private MockMvc mockMvc; @MockBean private UserService userService; @Test void shouldReturnUser() throws Exception { // test implementacja } }
Podsumowanie
Każda z wymienionych adnotacji ma swoje konkretne przeznaczenie:
Adnotacja | Zastosowanie | Specjalizacja |
---|---|---|
@Component | Ogólna adnotacja dla komponentów | Nie |
@Service | Warstwa logiki biznesowej | Tak |
@Repository | Warstwa dostępu do danych | Tak |
@Controller | Obsługa żądań HTTP | Tak |
Jeśli tworzysz komponent ogólnego przeznaczenia, możesz użyć @Component
. Dla logiki biznesowej wybierz @Service
, dla operacji na bazie danych – @Repository
, a dla kontrolerów HTTP – @Controller
.
Dobrze dobrane adnotacje sprawiają, że kod jest czytelniejszy, bardziej modułowy i łatwiejszy w zarządzaniu. Jeśli chcesz pisać aplikacje w Springu zgodnie z najlepszymi praktykami, warto trzymać się tego podziału!