Dzisiaj temat wydania mógł być tylko jeden – Spring. A że w temacie najpopularniejszego frameworku JVM wydarzyło się ostatnio bardzo wiele, poświęciłem mu całą edycję.
Wbrew temu, co się przyjęło, świat Javy jest ostatnimi laty całkiem dynamiczny. Pojawia się spora ilość nowych inicjatyw, frameworków czy zmianach w standardach – na tyle dużo, by zracjonalizować pojawianie się cotygodniowego przeglądu. Prawdą jednak jest, że choć ta proporcja nieco się ostatnimi latami zmienia, to jednak w tym świecie dalej dzieli i rządzi Spring – i mowa tutaj zarówno o starszych projektach, jak i o nowych inicjatywach. Dlatego też, choć możemy się cieszyć z tego, jak inne frameworki czy biblioteki pchają ekosystem do przodu, tak już szeroko pojęta adopcja standardów jak GraalVM czy JPMS zależy od Króla. A że ostatnie tygodnie to masa ważnych ogłoszeń od Springa, to dzisiejszą edycję poświęcimy właśnie jemu. Przyglądniemy się premierze Spring Framework 6.0 i Spring Boot 3.0, ich reperkusją, a także inicjatywą im towarzyszącym, bo tych jest sporo.
Kto tak naprawdę użyje nowego Springa?
W przeciągu ostatniego tygodnia ukazały się nowe wersje obu największych projektów spod springowej parasolki – Spring Framework 6.0 oraz Spring Boot 3.0. I choćby nie wiem jak wiele zmian przynosiły same w sobie, to z pewnością największą rewolucją jest porzucenie wsparcia starszych wersji Javy. I kiedy mówię tutaj „starsze”, na myśli mam nie Jave 1.6, nawet nie Java 1.8 ale nawet… Jave 16. Nowy Spring do działania wymaga Javy 17. Pivotal nie poszedł tutaj na żadne kompromisy i nowego „majora” projektów przystosował do działania wyłącznie z najnowszym dostępnym w tej chwili wydaniem LTS.
Ilu w teorii projektów będzie w stanie się na nowego Springa przepiąć? Spójrzmy na statystyki użycia Javy. Najnowszy raport opisujący ekosystem javowy, czyli wydany w kwietniu 2022 przez New Relic 2022 State of the Java Ecosystem Report pokazywał użycie Javy 17 na poziomie 0.37%. Na dane te trzeba patrzeć jednak w kontekście. Poprzedni LTS, czyli JDK 11, wyprzedził w raporcie bowiem królujące przez lata JDK 1.8 i osiągnął niemal 50% wysycenia rynku. Oznacza to, że proces migracji ma się jak najlepiej, a że przejście z JDK 11 na JDK 17 to naprawdę prosta sprawa (zwłaszcza w porównaniu z dojściem do JDK 11, co swego czasu zgrabnie opisał LinkedIn), to jedyne co stoi na przeszkodzie to danie potencjalnym użytkownikom argument, aby takowe zadanie dorzucić do Sprintu.
Zainstaluj teraz i czytaj tylko dobre teksty!
Główne danie: Spring Framework 6.0
Nie byłoby tego tekstu (oraz wielu opisywanych tu premier), gdyby swojej premiery siedemnastego listopada nie miał Spring Framework 6.0 – czyli nowe wydanie serca całego systemu. Przez lata to właśnie ono było na nagłówkach, ostatnimi laty zostało trochę przyćmione przez Spring Boota, który wraz z popularnością Mikroserwisów stał się sztandarową edycją Springa. Niech Was jednak nie zwiedzie pozorne wycofanie się w cień – to właśnie Spring Framework jest tą częścią, gdzie zwykle dochodzi do tych najciekawszych z inżynierskiego punktu widzenia zmian. Przejdziemy sobie przez te najbardziej spektakularne:
Papa Java EE, witaj Jakarta EE!
Nowa Java to jedno, ale Spring Framework 6.0 przynosi również nową Jakarte w wersji 9.1+. Warto o tym wiedzieć, ponieważ proces migracyjny może okazać się tutaj (co dla wielu będzie pewnie zaskoczeniem) trudniejszy niż w wypadku Javy. Przypominam bowiem o tym, że Jakarta EE 9.1+ to ta edycja, która pozbyła się pakietu javax.*
na rzecz jakarta.*
, w ten sposób uchodząc z zasięgu Oracle i należących do nich trademarków. Dla Springa jest to olbrzymi skok, umożliwi bowiem kompatybilność z kolejnymi, przynoszącymi więcej wartości do ekosystemu wersjami Jakarty EE. Sami twórcy radzą, że najlepiej przejść od razu na wydaną niedawno dziesiątkę – ta przynosi bowiem podbicie kilku istotnych standardów.
W zależności od tego, jak bardzo Wasza aplikacja zależała od Javy EE i związanych z nią bibliotek, tym trudniejsza będzie migracja. Chyba, że użyjecie narzędzia od JetBrains – wtedy powinno być sporo prościej.
Kompilacja Ahead-of-Time lub JPMS – wybierz jedno
Jeśli śledziliście wiadomości o nowym Springu od jego pierwszych zapowiedzi, mam dla Was złą nowinę: mie będzie to jednak tak bogate wydanie, jak się zapowiadało – okazuje się bowiem, że długo oczekiwane wsparcie JPMSa, systemu modułów Javy, nie będzie gotowe na premierę. Jak przyznają twórcy, można się spodziewać jego pojawienia w późniejszych wersjach, ale pierwsza wersja Spring Framework 6 skupia się szczególnie na wsparciu kompilacji Ahead-of-Time i GraalVM, a moduły utrudniałyby ten proces, komplikując tak zwaną „analizę osiągalności”. Należy bowiem pamiętać, że w odróżnieniu od nowych graczy na rynku frameworków jak Quarkus, Helidon czy Micronaut, Spring bardzo, bardzo mocno opiera się na Reflection API. Dla niego więc proces wsparcia dla GraalVM, który refleksji nie wspiera jest więc znacznie trudniejszy.
Stąd też moduły zeszły na dalszy plan, twórcy jasno bowiem piszą, że liczą tutaj na Project Leyden, mający ustandaryzować tworzenie kompilacji AoT na JVM. Jako że jest to część JDK, musi brać JPMSa pod uwagę, co powinno sprawić, że praca programistów zewnętrznych w tym aspekcie będzie łatwiejsza. Na ten moment Spring wybiera jednak wsparcie Natywnych Obrazów. Jeśli zaś chcecie dowiedzieć się więcej o wsparciu samych Natywnych obrazów i na co się przekłada w kontekście Springowym, odsyłam Was do prezentacji Ahead Of Time and Native in Spring Boot 3.0 autorstwa Stéphane Nicolla i Briana Clozela.
Wydaje mi się, że cała sytuacja jest mocno symptomatyczna do wszystkiego, co dzieje się z JPMS-em – nawet Frameworki, które teoretycznie mogłyby wprowadzić modularyzację łatwiej niż Spring nie do końca się do tego kwapią. Na ten moment moduły zdają się służyć głównie twórcom JDK i… w tej formie sprawdzają się świetnie, pozwalają bowiem na inkrementalny rozwój całej platformy.
Parę rzeczy pod maską
Dla kompletności, nie mogę nie wspomnieć tutaj o dwóch ciekawych zmianach pod maską. Otóż kolejną rzeczą, której twórcy Springa się przyglądają, jest rozwój wirtualnych wątków. Początkiem października pojawiła się dość obszerna publikacja, która stanowi chyba pierwsze oficjalne stanowisko Springa w tej kwestii. Ponownie długie dziedzictwo frameworki kładzie się tutaj cieniem – framework posiada duże ilości bloków synchronized, co choć samo w sobie nie stanowi blokera, to jednak cały proces trochę komplikuje. Twórcy zdają sobie z tego jednak sprawę i analizują, którymi fragmentami muszą zająć się w pierwszej kolejności i eksperymentują z dostarczonymi przez JDK metodami, i tak naprawdę pierwsze refeaktoringi trafiły już do wydanego Spring Framework 6.0. Jako społeczność powinno nas to podejście cieszyć. Miło, że Springowi zależy na tym, aby realnie coś na tych wirtualnych wątkach zyskać, a nie tylko odhaczyć sobie kolejny „rewolucyjny” feature.
Ostatnią rzeczą w kontekście Spring Framework 6.0 o której chciałbym wspomnieć, to przymiarki do Project CRaC. Może on pozwolić na wyeliminowanie jednej z największych i najczęściej wypominanych Springowi wad – jego długiemu czasowi uruchamiania. Na razie gotowe funkcjonalności (nawet w Preview) jeszcze nie są gotowe dla szerokich testów, ale już sam sneak peak, który możemy zobaczyć w prezentacji [Java on CRaC: Superfast JVM Application Startup, wygłoszonej przez Simona Rittera na Devoxx Belgium](https://www.youtube.com/watch?v=bWmuqh6wHgE&t=2500s) zaostrza apetyt.
To, czego realnie będziecie używać – Spring Boot 3.0
Tak jak wspominałem, zakładam że spora ilość z Was będzie używać właśnie tej dystrybucji Springa. Dlatego, mimo że już zahaczyliśmy o temat AoT to właśnie przy okazji Spring Boota zastanowimy się, do czego tak naprawdę w praktyce się to sprowadza. Dlatego trzeba odkurzyć stare zapowiedzi i przyglądnąć się projektowi, który nazywa się Spring-Native.
Kompilacja Ahead-of-Time o której to tak naprawdę nic innego, jak kompilowanie kodu źródłowego do wariantu finalnego nie poprzez krok pośredni (bajtkod, a następnie kompilator Just-in-Time), ale na samym starcie procesu. Takie podejście sprawia, że z góry można dokonać optymalizacji i wygenerowanie kodu maszynowego, przy okazji pozbawiając się całego JVM-owego balastu, jak Classpath czy też sama maszyna wirtualna. Dzięki temu aplikacje startują szybciej, pożerają również mniej zasobów – wynika to z faktu, że po prostu w uruchomionym procesie jest mniej niepotrzebnych klocków.
Nie jest to jednak za darmo – aplikacje kompilowane prze Graal VM (bo to właśnie on jest kompilatorem AoT o którym cały czas mówimy) muszą działać w ramach „założenia zamkniętego świata”. Oznacza ono, że cały bytecode w aplikacji, który może być wywołany w czasie pracy aplikacji, musi być znany (obserwowany i analizowany) już w czasie budowania. Szczególnie mocno wpływa to na programy używające mechanizmu refleksji. Kompilator bowiem musi domyśleć się, jakie (zwykle dynamicznie) zasoby powinien dołożyć do finalnego artefaktu, mimo że w kodzie nie ma do nich bezpośrednich odwołań. Spring, jak wszyscy zdają sobie sprawę – jest bardzo mocno oparty o refleksję, dlatego prace służące do przystosowania go właśnie do działania z GraalVM zostały zapakowane w projekt R&D o nazwie Spring-Native, który rozwijany jest od prawie trzech lat. Teraz finalnie staje się on częścią Springa, a najwięcej skorzysta na nim Spring Boot.
Jeśli chcecie dowiedzieć się więcej o tym, jak działa GraalVM, zapraszam do artykułu napisanego w kontekście Spring Framework, ale również oficjalnego tekstu Oracle na temat natywnych obrazów.
Co poza Spring-Native? Jednym z moich ulubionych dodatków do Spring Boota to ulepszonemu wsparciu dla Micrometer. Od pewnego czasu przyglądam się rozwojowi tej biblioteki i jestem pewien, że na naszych oczach rodzi się właśnie nowy standard, który zostanie z nami na lata. Objawia się to choćby przez to, że coraz więcej narzędzi zapewnić próbuje dla niego jak najwygodniejsze wsparcie. Tak jak Quarkus porzucił dla Micrometer rozwiązania pochodzące z Jakarty EE, tak teraz w Spring Boot 3.0 również położono nacisk na jak największą kompatybilność. Przykładowo, w nowej wersji frameworki Micrometer Tracing zastąpi Spring Cloud Sleuth. Jeżeli jesteście ciekawi, jakie nowości w tym aspekcie czekają użytkowników Spring Boot 3.0, zapraszam do artykułu Observability with Spring Boot 3
To oczywiście nie wszystkie nowości – spore przemodelowanie przeszedł min. model propertiesów aplikacji. te najważniejsze znajdziecie w oficjalnym Release Note.
Projekty towarzyszące
Żeby zrozumieć, jak wielką zmianą były poprawki wprowadzone przez Spring Framework 6.0 – kompilacja Ahead-of-Time, migracja do Jakarty EE 10, a także dodanie wsparcia dla Micrometer w Spring Boot – wystarczy spojrzeć na release notes większości projektów towarzyszących. Te dominowane są bowiem przez raportowanie o kompatybilności z najnowszą wersją projektu, spod której przebijają się co najwyżej drobne poprawki – pokazuje to, ile pracy całej społeczności było wymagane, żeby zrobić duży krok do przodu.
Taki np. Spring Web Service 4.0 nie chwali się (poza powyższymi upgrade’ami) niczym poza przejściem na GitHuba jeśli chodzi o śledzenie releasów. Spring Security 6.0 też wprowadza raczej drobne dodatki. Trochę ciekawiej prezentuje się to w wypadku Spring GraphQL 1.1.0, Spring Data 2022.0 czy nowych Spring for Apache Kafka 3.0 i Spring for RabbitMQ 3.0 – te zawierają trochę nowych API. Jednak nawet w ich przypadku gro zapowiedzi to jednak informacji o udanej migracji, nawet jeśli Spring Data można uznać za wybijający się przypadek projektu, który realnie poinformował, z czym ta cała kompilacja AoT się wiąże.
Mikroserwisy zaczynają być passe – Spring Modulith
Przy okazji opisywania Spring Boota 3.0 wspomniałem, że to właśnie ta wersja będzie prawdopodobnie docelową dla większości użytkowników Springa (a przynajmniej tych, którzy w ogóle rozważają migrację na jego nową aktualizację). Spring Boot to w końcu wydanie dedykowane choćby takim aplikacją Cloud Native czy ogólnie pojętym Mikroserwisom. Ostatnimi laty (czy nawet w ciągu ostatniej dekady) to właśnie Mikroserwisy były tym wzorcem architektonicznym, który stał się tym „nowoczesnym” sposobem tworzenia aplikacji, do poziomu, gdy można go uznać za swoisty kult cargo, również w świecie Javy. Tak długo walczyliśmy, aby nasze frameworki nadawały się do tego typu architektur, że teraz traktujemy je jako rozwiązanie domyślne.
W społeczności jednak coraz częściej pojawia nawoływanie do powrotu do monolitu, ale trochę wymyślonego na nowo. Zwolennicy tego podejścia nawołują, że przy użyciu dzisiejszych narzędzi i dobrej modularyzacji jesteśmy w stanie stworzyć codebase posiadający sporą ilość zalet mikroserwisów przy zaskakująco małej ilości jego wad. Zainteresowanych odsyłam do koncepcji Majestatycznego Monolitu autorstwa DHH, a także interesującej serii Modular Monolith: A Primer.
No dobra, ale jak to się ma do tematu Springa? Otóż wraz ze Spring Bootem swoją premierę miał projekt Spring Modulith w wersji 0.1, który ma wprowadzić Springa w erę majestatycznego monolitu. Spring-Modulith to rozwinięcie istniejącego projektu Moduliths (którego zastąpi), ale jeszcze lepiej zintegrowanego z samym Springiem. Bardzo ciekawy jest sam sposób działania całości – zamiast mocno ingerować on w proces budowania, wykorzystuje do weryfikacji projektu testy integracyjne. Te odpalają ArchUnit – bibliotekę, której celem jest właśnie weryfikacja zależności między poszczególnymi modułami. Magia Modulitha polega jednak na tym, że dzięki znanemu środowisku uruchomieniowemu (aplikacje Spring Boot 3.0) jest w stanie prekonfigurować ArchUnita – co też czyni. Dzięki temu w łatwy sposób jesteśmy w stanie przetestować, czy jakieś architektoniczne spaghetti nie przemknęło przez Code Review.
Jako, że jak pisaliśmy wyżej, Spring wycofał się (na razie) ze wsparcia JPMS-a, Modulith wydaje się być interesującą, prostą alternatywą. Jeżeli dodamy do tego fakt, że projekt jest w stanie automatycznie generować nam diagramy architektoniczne z żywego kodu, warto się projektem zainteresować. W tym celu podrzucam dwa dodatkowe materiały – wywiad z twórcą projektu, Oliverem Drotbohmem, od InfoQ oraz tutorial od Nicolasa Fränkela.
Zainstaluj teraz i czytaj tylko dobre teksty!
To na sam koniec – jak się zmigrować?
No dobra, porozmawialiśmy sobie o zmianach, jakie nowy Spring (traktując go jako całokształt) przyniesie i mam nadzieje, że pomimo pewnej ilości pracy, jaką trzeba wykonać, udało mi się Was zachęcić do spróbowania. Wiadomo jednak, że w taką przygodę najlepiej ruszyć przygotowanym.
Twórcy Springa już w maju podrzucili trochę sugestii, w jaki sposób przystosować swój kod na Spring Boota 3.0 i jeśli rzeczywiście to zrobiliście (podbiliście Jave, Jakarte, prze migrowaliście Propertiesy, pousuwaliście przestarzały kod) to jesteście w zasadzie gotowi od razu zacząć się bawić całością. Jeżeli jednak oprócz tego, że chcecie po prostu podbić wersje zależności, to jeszcze chcecie maksymalnie wykorzystać nowe możliwości frameworka (i Javy), koniecznie rzućcie okiem na artykuł The best way to do the Spring 6 migration Vlada Mihalcea. Przeczytacie w nim, jak uzyskać najwięcej wartości z całego procesu.