CodeGym /Kursy /Java Server /Gradle Wrapper: sposób budowania

Gradle Wrapper: sposób budowania

Java Server
Poziom 2, Lekcja 1
Dostępny

1. Gradle i Wrapper: gradle vs gradlew

Na początku bardzo łatwo pomylić dwie podobne rzeczy: gradle jako program i gradle Wrapper jako sposób jego uruchamiania. Brzmią prawie tak samo — jak „kawa” i „ekspres do kawy”, tylko że konsekwencje pomyłki zwykle pobudzają mocniej niż poranne espresso. Spokojnie omówmy, co dokładnie uruchamiasz i dlaczego w projekcie edukacyjnym wybieramy tylko jedną drogę.

Wyobraź sobie, że piszesz w terminalu:

# Uruchomienie Gradle, który jest zainstalowany w systemie (lokalnie na Twojej maszynie)
gradle build

To znaczy: „weź Gradle, który jest zainstalowany na moim komputerze, i spróbuj zbudować projekt”. A teraz porównaj z:

# Uruchomienie Gradle przez Wrapper (wersja Gradle brana jest z ustawień projektu)
./gradlew build

To z kolei oznacza: „weź Gradle, który jest zapisany w projekcie, i zbuduj projekt”. Różnica wydaje się kosmetyczna — wszystkiego dwie kropki i ukośnik — ale inżyniersko to dwa różne światy.

Systemowy gradle żyje według reguł Twojej maszyny. Możesz mieć Gradle 8.x, Twój kolega — 9.x, a prowadzący — w ogóle nic (i nie musi zgadywać, co tam zainstalowałeś). W efekcie wychodzi klasyczna sytuacja: „u mnie się buduje”, „u Ciebie się nie buduje”, „a może po prostu wszystko zainstalujesz od nowa na wszelki wypadek”. To wygląda jak plan, ale to zły plan.

Wrapper robi odwrotnie: kładzie w repozytorium „punkt wejścia”, który gwarantuje, że projekt uruchamia się tym samym Gradle niezależnie od tego, kto go uruchamia. W naszym kursie jest to szczególnie ważne, bo baseline jest ustalony: Gradle Wrapper 9.4.0, Kotlin DSL, Java 25. Potrzebujemy, żebyś mógł otworzyć dowolny przykład z wykładu i dostać ten sam wynik, a nie przechodzić questa „zgadnij wersję”.

Dla poglądowości można zapamiętać krótki wzór:

Polecenie Kto wybiera wersję Gradle Dlaczego to jest ważne
gradle build
Twój system / Twoja lokalna instalacja projekt staje się „przywiązany do maszyny”
./gradlew build
sam projekt (przez Wrapper) projekt staje się powtarzalny

I tak, czasem systemowego gradle w ogóle u Ciebie nie będzie — i to jest w porządku. W naszym kursie nie trzeba osobno instalować Gradle w systemie. Jeśli bardzo Ci się chce coś zainstalować ręcznie — lepiej ustaw sobie przypomnienie, żeby zawsze budować projekt przez Wrapper. To bardziej przydatne.

2. Wrapper: pliki i role

Kiedy po raz pierwszy widzisz pliki Wrappera w projekcie, ręka aż się rwie pomyśleć: „O, śmieci! To przecież nie jest kod Javy”. Reakcja prawie naturalna, zwłaszcza jeśli wcześniej pisałeś małe programy, które żyją w jednym pliku. Ale dla projektu backendowego, nawet edukacyjnego, te pliki są jak klucze od mieszkania: możesz być świetnym programistą, ale bez kluczy do środka nie wejdziesz.

Minimalny zestaw Wrappera wygląda tak:

# Struktura plików, które zapewniają uruchamianie Gradle przez Wrapper
readlater-starter/
├── gradlew
├── gradlew.bat
└── gradle/
    └── wrapper/
        ├── gradle-wrapper.jar
        └── gradle-wrapper.properties

Przetłumaczmy to z formatu „zobaczyłem w drzewie projektu” na ludzki sens.

gradlew to skrypt dla macOS/Linux. Uruchamia się jako plik wykonywalny z korzenia projektu i jest Twoim głównym wejściem. gradlew.bat — to samo, ale dla Windows (skrypt batch). To nie są „dwa różne warianty do wyboru”, tylko dwa warianty dla różnych systemów operacyjnych.

W katalogu gradle/wrapper/ leżą dwa krytycznie ważne pliki. gradle-wrapper.properties — konfiguracja Wrappera, w niej właśnie jest utrwalone, jakiej wersji Gradle używać. gradle-wrapper.jar — mały program w Javie (tak, jar), który potrafi ściągnąć potrzebny Gradle, a potem uruchomić go tak, jak chce projekt.

Dla ułatwienia oto mała „ściąga” w postaci tabeli:

Plik Po co jest potrzebny Czy można usuwać
gradlew
uruchamianie Gradle przez Wrapper na macOS/Linux nie
gradlew.bat
uruchamianie Gradle przez Wrapper na Windowsie nie
gradle/wrapper/gradle-wrapper.properties
utrwala wersję Gradle i ustawienia dystrybucji nie
gradle/wrapper/gradle-wrapper.jar
implementacja Wrappera, która pobiera i uruchamia Gradle nie

Tu łatwo zawiesić się na pytaniu: a skąd te pliki w ogóle biorą się w samym pierwszym stanie projektu? Nie pisze się ich ręcznie. Zwykle przychodzą już razem ze startowym szkieletem projektu — na przykład jeśli tworzysz projekt Gradle z szablonu albo bierzesz gotowe repozytorium edukacyjne. Dalej Wrapper żyje w repozytorium jako część projektu i wszystkie polecenia idą tylko przez niego.

Słowo „nie” w kolumnie „czy można usuwać” — nie dlatego, że jesteśmy złośliwi. A dlatego, że jeśli usuniesz pliki Wrappera, projekt przestanie mieć uniwersalny punkt wejścia, i wrócimy do epoki „zainstaluj sobie Gradle jakoś sam”.

3. Wersja Gradle w gradle-wrapper.properties

Jeśli szukasz w projekcie miejsca, gdzie „tak naprawdę” utrwalona jest wersja Gradle, to nie jest to build.gradle.kts ani ustawienie IDE. To plik gradle/wrapper/gradle-wrapper.properties. Jest mały, nudny i właśnie dlatego niezawodny: żadnej magii, tylko tekst, który czyta Wrapper.

Najważniejsza linia tam zazwyczaj wygląda tak:

# Skąd Wrapper pobiera Gradle (i właśnie tą linijką utrwalana jest wersja)
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip

Ten zapis dosłownie znaczy: „jeśli trzeba uruchomić Gradle, weź dystrybucję gradle-9.4.0-bin.zip z oficjalnej strony Gradle”. Czyli wersja 9.4.0 jest utrwalona w projekcie. Nie „najnowsza na dziś”, nie „która jest zainstalowana” i nie „ta, co u mnie w IDE”. A ta, z którą to repozytorium ma żyć.

Dlaczego to jest ważne nawet dla nowicjusza, który na razie nie buduje wielomodułowych potworów? Bo Gradle to żywe narzędzie. W różnych wersjach różnią się szczegóły Kotlin DSL, dostępne możliwości, zachowanie niektórych zadań, a nawet komunikaty błędów. A Ty się teraz uczysz i potrzebujesz, żeby przykład z wykładu pokrywał się z tym, co dzieje się na Twoim komputerze.

Wrapper ma też inne właściwości: gdzie przechowywać ściągniętą dystrybucję, jak rozkładać pliki i tak dalej. Ale w ramach naszego kursu wystarczy trzymać w głowie jedną kotwicę: distributionUrl utrwala wersję Gradle i czyni uruchomienie powtarzalnym.

Jeszcze jeden szczegół: bin w nazwie archiwum oznacza „binary distribution”, czyli zwykły wariant roboczy. Istnieją też inne warianty dystrybucji, ale nie zamieniamy tego kursu w kurs inżynierii buildu. Nasz cel jest prostszy: jednakowe uruchomienie u wszystkich.

4. Pierwsze uruchomienie: pobranie Gradle

Pierwsze uruchomienie Wrappera często straszy nowicjuszy: wpisujesz polecenie, a zamiast natychmiastowego „sukces!” widzisz, jak coś się pobiera, szurka, rozpakowuje. Tu ważne jest nie wyciągnąć wniosku „u mnie wszystko się zepsuło” i nie biec przeinstalowywać Javy, IDE, a na wszelki wypadek klawiatury.

Mechanika jest mniej więcej taka: gdy uruchamiasz ./gradlew ..., Wrapper sprawdza, czy w lokalnym cache'u jest potrzebna wersja Gradle. Jeśli nie ma — pobiera po distributionUrl, rozpakowuje i dopiero potem uruchamia odpowiednie zadanie (build, run itd.).

W uproszczonej formie wygląda to tak:

# Cała logika niżej — to, co robi Wrapper zanim uruchomi build
Uruchamiasz ./gradlew build
→ Wrapper czyta gradle-wrapper.properties
→ Widzi gradle-9.4.0-bin.zip
→ Jeśli Gradle 9.4.0 jeszcze nie ma lokalnie — pobiera
→ Uruchamia Gradle 9.4.0 i wykonuje build

Gdzie to jest przechowywane? Zazwyczaj w katalogu domowym użytkownika, w folderze .gradle. Czyli pobrany Gradle to nie część repozytorium, tylko lokalny cache na Twojej maszynie. Dlatego pierwsze uruchomienie może być wyraźnie wolniejsze, a drugie i trzecie — już znacząco szybsze.

Jeśli chce się zobaczyć, że Wrapper rzeczywiście żyje i działa, można bezpiecznie wykonać polecenie, które niczego nie kompiluje, a po prostu pokazuje informacje o Gradle:

# Sprawdzamy, którą wersję Gradle naprawdę uruchamia Wrapper
./gradlew --version
# Gradle 9.4.0
# Kotlin: ...
# JVM: ...

Komentarz pod poleceniem to nie jest dokładny „bajt w bajt” output, może się różnić szczegółami. Ale sens łapiesz: zobaczysz wersję Gradle i będzie to dokładnie ta wersja, która jest utrwalona we Wrapperze.

Jeśli pierwsze pobieranie idzie długo, najczęściej powód jest prozaiczny: wolny internet, pierwsze uruchomienie, czasem korporacyjne proxy. Ale na poziomie kursu odbieramy „pierwsze uruchomienie pobiera Gradle” jako normalną część życia projektu. Ważne jest tylko pamiętać: dzieje się to raz na wersję Gradle i potem jest cache'owane.

5. Zadania przez Wrapper

Gdy mówi się „uruchamiać przez Wrapper”, to nie filozofia, tylko całkiem konkretny format poleceń. Uruchamiasz skrypt z korzenia projektu i przekazujesz mu nazwę zadania. Gdyby Gradle był ekspresem do kawy, to Wrapper byłby przyciskiem „włącz”, a zadanie — poleceniem „zrób latte”. Tak, porównanie dziwne, ale nieoczekiwanie pomaga zapamiętać strukturę.

Ogólny szablon polecenia jest taki:

# <taskName> to nazwa zadania Gradle, na przykład build/run/test itd.
./gradlew <taskName>

Na przykład najbardziej podstawowe zadania, które już niedługo będą u nas aktywnie używane, wyglądają tak:

# Zbuduj projekt (kompilacja, testy, pakowanie — zależy od ustawień projektu)
./gradlew build
# Uruchom aplikację (jeśli w projekcie skonfigurowane jest zadanie run)
./gradlew run

Na Windowsie zamiast ./gradlew zazwyczaj używa się gradlew.bat (i to jest właśnie nazwa pliku, a nie „coś z IDE”):

REM Na Windowsie używamy skryptu batch Wrappera z korzenia projektu
gradlew.bat build
gradlew.bat run

Skoro nawet tutaj łatwo się pogubić, oto mała tabela-przypominajka:

System Polecenie
macOS / Linux
./gradlew build
Windows
gradlew.bat build

A teraz o dziwnym prefiksie ./. Oznacza on „uruchom plik z bieżącego katalogu”. W systemach uniksowych (Linux/macOS) bieżący katalog nie wchodzi w PATH domyślnie, i jest tak zrobione specjalnie ze względów bezpieczeństwa. Dlatego gradlew bez ./ często się nie uruchamia. Nie dlatego, że „masz nie ten terminal”, tylko dlatego, że tak jest zbudowany system.

Jeszcze jeden przydatny nawyk: zawsze uruchamiać polecenia z korzenia projektu — z tego katalogu, gdzie leżą gradlew, build.gradle.kts i settings.gradle.kts. Jeśli stoisz gdzieś w głębi src/main/java, Wrapper fizycznie może nie znajdować się po drodze, a polecenie nie zadziała. To nie „Gradle jest dziwny”, to po prostu stoisz nie tam.

6. Wrapper w repozytorium

Na starcie pliki Wrappera często odbierane są jako coś tymczasowego: „no przecież już pobrałem Gradle, po co przechowywać te skrypty”. I tu ważne jest złapać główną ideę: Wrapper przechowuje się w repozytorium nie dlatego, że Ci się nie chce zainstalować Gradle. Przechowuje się dlatego, że projekt musi umieć uruchomić się sam z siebie, bez wstępnych tańców.

W zespołowej pracy projekt żyje tak: ktoś klonuje repozytorium Git, otwiera README i uruchamia polecenia. Jeśli w projekcie nie ma Wrappera, pierwsze polecenie zamienia się w „najpierw zainstaluj Gradle potrzebnej wersji”. A dalej zaczynają się dopytywania: „a jaką wersję?”, „a gdzie pobrać?”, „a co jeśli mam już inną?”, „a to na pewno niczego nie zepsuje?”.

Wrapper ucina tę gałąź pytań u korzeni. Mówi: „oto wejście, oto wersja, uruchamiaj”. Właśnie dlatego pliki Wrappera muszą być scommitowane w Git razem z kodem. I właśnie dlatego wszelkie .gitignore, które przypadkiem ignorują gradle-wrapper.jar albo gradle-wrapper.properties — to dywersja przeciw powtarzalności.

Ważne uściślenie: katalog build/, który Gradle tworzy podczas budowania, to rzeczywiście generowany artefakt, jego zazwyczaj nie commitujemy. A oto gradle/wrapper/ — to nie „wynik budowania”, tylko część opisu tego, jak budować. Traktuj to jako instrukcję do projektu, która ma leżeć obok samego projektu.

7. Schemat uruchamiania Wrappera

U nowicjusza bardzo często pojawia się wewnętrzny dyskomfort: „uruchamiam ./gradlew build, i gdzieś tam coś się dzieje, ale nie rozumiem co”. I to jest normalna emocja. Nie studiujemy teraz wnętrzności Gradle, ale ważne jest zdjąć poczucie czarnej skrzynki przynajmniej na poziomie ogólnego schematu.

Oto uproszczony schemat blokowy tego, co się dzieje:

flowchart TD
    A["W korzeniu projektu uruchamiasz ./gradlew build"] --> B["Skrypt gradlew / gradlew.bat"]
    B --> C["Wrapper (gradle-wrapper.jar)"]
    C --> D["Czyta gradle-wrapper.properties i pozna wersję Gradle"]
    D --> E{"Potrzebna wersja Gradle jest już pobrana?"}
    E -->|Nie| F["Pobiera dystrybucję Gradle i kładzie w lokalnym cache"]
    E -->|Tak| G["Używa lokalnego cache"]
    F --> H["Uruchamia Gradle potrzebnej wersji"]
    G --> H["Uruchamia Gradle potrzebnej wersji"]
    H --> I["Gradle wykonuje zadanie build/run według reguł projektu"]

Ten schemat ważny jest tym, że pokazuje: Wrapper nie „zastępuje Gradle”. Po prostu gwarantuje, że Gradle będzie właściwej wersji i że uruchomienie zawsze zaczyna się tak samo.

A teraz można starannie powiązać to z naszym projektem. ReadLater Starter — to repozytorium, które ma uruchamiać się jednakowo u wszystkich studentów. Dlatego wszędzie — w README, w przykładach poleceń i we własnych nawykach — będziemy używać tylko poleceń Wrappera. To stanie się „regułą gry” projektu — taką samą, jak „kod Javy leży w src/main/java”, a nie gdzie popadnie.

8. Typowe błędy przy pracy z Wrapperem

Błąd nr 1: uruchamiać gradle build zamiast ./gradlew build.
To jedna z najczęstszych pomyłek. Polecenie gradle build odwołuje się do Gradle zainstalowanego w Twoim systemie (jeśli w ogóle jest zainstalowany) i może mieć inną wersję. W efekcie tracisz czas nie na naukę i projekt, tylko na zgadywanie, dlaczego przykład z wykładu nie zgadza się z Twoim outputem w konsoli.

Błąd nr 2: usuwać albo nie commitować plików Wrappera, bo są „służbowe”.
Wydaje się logiczne „posprzątać projekt” i usunąć zbędne. Ale Wrapper to nie śmieci ani cache. To część kontraktu repozytorium: jak dokładnie ten projekt ma się uruchamiać. Jeśli w repozytorium nie ma Wrappera, druga osoba nie ma gwarantowanego sposobu na odtworzenie Twojego uruchomienia.

Błąd nr 3: mylić gradlew i gradlew.bat i próbować uruchamiać nie ten plik na swoim systemie.
Na macOS/Linux zwykle uruchamiasz ./gradlew. Na Windowsie — gradlew.bat. Próba uruchamiania „nie swojego” skryptu często kończy się dziwnymi komunikatami: terminal nie rozumie formatu pliku, prawa nie te, kodowanie nie to. Łatwiej przyjąć to za fakt: są dwa wejścia dla dwóch rodzin systemów operacyjnych.

Błąd nr 4: uruchamiać Wrapper nie z korzenia projektu.
Polecenia ./gradlew ... mają sens, gdy stoisz w katalogu, gdzie leży plik gradlew. Jeśli przypadkiem zaszedłeś do src/main/java i próbujesz uruchamiać stamtąd, dostaniesz „No such file or directory” albo podobny komunikat. To nie „Gradle nie działa”, tylko po prostu stoisz w nie tym katalogu.

Błąd nr 5: bać się długiego pierwszego uruchomienia i brać pobieranie Gradle za awarię.
Przy pierwszym uruchomieniu Wrapper rzeczywiście może pobrać dystrybucję Gradle. To normalna mechanika, a nie błąd. Jeśli internet jest, a link w distributionUrl jest poprawny, dalej wszystko będzie działać szybciej dzięki cache.

1
Zadanie
Java Server, poziom 2, lekcja 1
Niedostępne
Pliki wrappera jako część repozytorium
Pliki wrappera jako część repozytorium
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION