Dlaczego projekt Jigsaw / JPMS?

80

System zarządzania pakietami w Javie zawsze wydawał mi się prosty i skuteczny. Jest intensywnie używany przez sam JDK. Używaliśmy go do naśladowania koncepcji przestrzeni nazw i modułów.

Co próbuje wypełnić Project Jigsaw (inaczej Java Platform Module System )?

Z oficjalnej strony:

Celem tego projektu jest zaprojektowanie i zaimplementowanie standardowego systemu modułowego dla platformy Java SE oraz zastosowanie tego systemu na samej platformie oraz w JDK.

Jan
źródło

Odpowiedzi:

101

Jigsaw i OSGi próbują rozwiązać ten sam problem: jak pozwolić gruboziarnistym modułom na interakcję, jednocześnie chroniąc ich elementy wewnętrzne.

W przypadku Jigsaw, bardziej zgrubne moduły obejmują klasy, pakiety i zależności Javy.

Oto przykład: Wiosna i hibernacja. Oba są zależne od zewnętrznego JAR CGLIB, ale używają różnych, niekompatybilnych wersji tego JAR. Co możesz zrobić, jeśli polegasz na standardowym JDK? Włączenie wersji, której chce Spring, przerywa Hibernate i vice versa.

Ale jeśli masz model wyższego poziomu, taki jak Jigsaw, możesz łatwo zarządzać różnymi wersjami JAR w różnych modułach. Pomyśl o nich jak o pakietach wyższego poziomu.

Jeśli zbudujesz Springa ze źródła GitHub , również to zobaczysz. Przeprojektowali framework, więc składa się z kilku modułów: core, persence, itd. Możesz wybrać i wybrać minimalny zestaw zależności modułów, których potrzebuje twoja aplikacja, a resztę zignorować. Kiedyś był to pojedynczy plik JAR Spring ze wszystkimi plikami .class.

Aktualizacja: pięć lat później - Jigsaw może nadal mieć pewne problemy do rozwiązania.

duffymo
źródło
5
A jeśli nadal potrzebujesz tego samego modułu, ale dwóch różnych wersji? Czy nie powinni po prostu dodać wsparcia, aby dwie wersje tych samych klas mogły współistnieć?
Didier A.,
7
ten post jest mylący, biorąc pod uwagę to, co faktycznie ma zostać wydane w wersji java 9. Być może było dokładne w momencie pisania.
xenoterracide
1
mreinhold.org/blog/jigsaw-complete Projekt ukończony i wydany dla Java 9
Zasz
@xenoterracide, nie można nikogo winić za to, że nie jest jasnowidzem. Post poprzedzał Java 9 o pięć lat. Czy przeglądasz również każdą odpowiedź Jona Skeeta?
duffymo
Ten post nie zestarzał się dobrze. Moduły Java celowo nie rozwiązują problemu wersjonowania, zobacz ten wątek . Nadal nie ma łatwego sposobu na obejście naszych starych przyjaciół NoSuchMethodErrori NoClassDefFoundError.
Tamas Hegedus
45

AFAIK Planujemy uczynić środowisko JRE bardziej modułowym. To znaczy masz mniejsze słoiki, które są opcjonalne i / lub możesz pobrać / zaktualizować tylko te funkcje, których potrzebujesz.

Dzięki temu jest mniej rozdęty i daje możliwość upuszczenia starszych modułów, których być może większość ludzi nie używa.

Peter Lawrey
źródło
7
Przyjęta odpowiedź jest ważna, ale ta odpowiedź jest lepsza, ponieważ wyjaśnia rzeczywiste pożądane efekty. +1, zasłużony.
Silviu Burcea
Jestem ciekawy, czy to również oznacza, że ​​jeśli mam Google Guava jako zależność, ale używam w niej tylko ImmutableList, wtedy mogę tylko importować zależności ImmutableList i pozostawić resztę klas Guava?
tmn
1
@ThomasN. Kiedy używasz importmetody, wszystko to robi, to wprowadzenie tej klasy do przestrzeni nazw klasy dla kompilatora. Jeśli faktycznie go nie używasz, nie pojawi się w utworzonym kodzie bajtowym. Jeśli faktycznie używasz tej klasy, musisz mieć tę klasę i każdą klasę, której używa w czasie wykonywania. Teoretycznie możesz stworzyć okrojoną wersję interfejsu API guawy, która będzie miała tylko to, czego potrzebujesz, i zamiast tego użyj tego pliku JAR. W rzeczywistości jest to podatne na błędy i niezbyt przydatne w większości przypadków, a kończy się na dodaniu całego pliku JAR w stanie, w jakim został wydany.
Peter Lawrey,
43

Na podstawie Mark Reinhold „s przemówienie na Devoxx Belgii , Projekt Jigsaw będzie dotyczą dwóch głównych punktów bólowych:

  1. Classpath
  2. Masywny monolityczny JDK

Co jest nie tak z Classpath?

Wszyscy wiemy o piekle JAR . Termin ten opisuje wszystkie różne sposoby, w jakie proces ładowania klas może zakończyć się niepowodzeniem. Najbardziej znane ograniczenia ścieżki klas to:

  • Trudno powiedzieć, czy są konflikty. narzędzia do budowania, takie jak maven, mogą wykonać całkiem niezłą robotę w oparciu o nazwy artefaktów, ale jeśli same artefakty mają różne nazwy, ale taką samą zawartość, może wystąpić konflikt.
  • Podstawowy problem z plikami jar polega na tym, że nie są one komponentami. To po prostu kilka kontenerów plików, które będą przeszukiwane liniowo. Classpath to sposób na przeszukiwanie klas niezależnie od tego, w jakich składnikach się znajdują, w jakich pakietach się znajdują i jaki jest ich cel.

Masywny monolityczny JDK

Duży monolit JDK powoduje kilka problemów:

  • Nie pasuje do małych urządzeń. Mimo że małe urządzenia typu IoT mają procesory zdolne do obsługi maszyny wirtualnej klasy SE, ale niekoniecznie mają one pamięć, aby pomieścić cały pakiet JDK, zwłaszcza gdy aplikacja używa tylko niewielkiej jego części.
  • To nawet problem w chmurze. Chmura polega na optymalizacji wykorzystania sprzętu, jeśli masz tysiące obrazów zawierających cały JDK, ale aplikacje używają tylko niewielkiej jego części, byłoby to marnotrawstwem.

Moduły: powszechne rozwiązanie

Aby rozwiązać powyższe problemy, traktujemy moduły jako fundamentalny nowy rodzaj komponentu programu Java. Moduł to nazwana, samoopisująca się kolekcja kodu i danych. Jego kod jest zorganizowany jako zbiór pakietów zawierających typy, tj. Klasy i interfejsy Java; jego dane obejmują zasoby i inne rodzaje informacji statycznych.

Aby kontrolować, w jaki sposób jego kod odwołuje się do typów w innych modułach, moduł deklaruje, jakich innych modułów wymaga do skompilowania i uruchomienia. Aby kontrolować, jak kod w innych modułach odwołuje się do typów w swoich pakietach, moduł deklaruje, które z tych pakietów eksportuje.

System modułów lokalizuje wymagane moduły i, w przeciwieństwie do mechanizmu ścieżki klas, zapewnia, że ​​kod w module może odwoływać się tylko do typów w modułach, od których zależy. Mechanizmy kontroli dostępu języka Java i wirtualnej maszyny Java uniemożliwiają kodowi dostęp do typów w pakietach, które nie są eksportowane przez ich moduły definiujące.

Oprócz większej niezawodności modułowość może poprawić wydajność. Gdy kod w module odwołuje się do typu w pakiecie, wtedy pakiet ten jest zdefiniowany albo w tym module, albo dokładnie w jednym z modułów czytanych przez ten moduł. Szukając definicji konkretnego typu, nie ma zatem potrzeby wyszukiwania jej w wielu modułach lub co gorsza po całej ścieżce klasowej.

JEP-y do naśladowania

Jigsaw to ogromny projekt, który trwa już od kilku lat. Ma imponującą liczbę JEP-ów, które są świetnymi miejscami, w których można uzyskać więcej informacji o projekcie. Oto niektóre z tych JEP:

  • JEP 200: Modułowy JDK : Użyj Java Platform Module System (JPMS) do modularyzacji JDK
  • JEP 201: Modułowy kod źródłowy : zreorganizuj kod źródłowy JDK w moduły, ulepsz system kompilacji, aby skompilować moduły i wymuszaj granice modułów w czasie kompilacji
  • JEP 261: System modułów : Zaimplementuj system modułów platformy Java, określony w JSR 376, wraz z powiązanymi zmianami i ulepszeniami specyficznymi dla JDK
  • JEP 220: Modułowe obrazy czasu pracy : przebudowa wykonawczych JDK i JRE, aby pomieścić moduły i poprawić wydajność, bezpieczeństwo i łatwość konserwacji
  • JEP 260: Hermetyzuj większość wewnętrznych interfejsów API : większość wewnętrznych interfejsów API JDK jest domyślnie niedostępnych, ale pozostaw kilka krytycznych, szeroko używanych wewnętrznych interfejsów API dostępnych do czasu, gdy będą dostępne obsługiwane zamienniki dla wszystkich lub większości ich funkcji
  • JEP 282: jlink: Java Linker : Utwórz narzędzie, które może złożyć i zoptymalizować zestaw modułów i ich zależności w niestandardowy obraz wykonawczy, zgodnie z definicją w JEP 220

Uwagi końcowe

W pierwszej edycji raportu The State of the Module System Mark Reinhold opisuje następujące cele szczegółowe systemu modułowego:

  • Niezawodna konfiguracja , w celu zastąpienia kruchego, podatnego na błędy mechanizmu ścieżki klas środkami umożliwiającymi komponentom programu deklarowanie jawnych zależności od siebie, wraz z
  • Silna hermetyzacja , aby umożliwić składnikowi deklarowanie, które z jego typów publicznych są dostępne dla innych składników, a które nie.

Funkcje te przyniosą korzyści twórcom aplikacji, twórcom bibliotek i firmom wdrażającym samą platformę Java SE bezpośrednio, a także pośrednio, ponieważ zapewnią skalowalną platformę, większą integralność platformy i lepszą wydajność.

Ali Dehghani
źródło
3
Mark Reinhold jest głównym architektem Java Platform Group w Oracle i ta odpowiedź jest w istocie jego bezpośrednią odpowiedzią na to dokładne pytanie.
Jay
1
Aby to oszacować, HelloWorld może używać 15 MB zamiast 553 MB; youtu.be/rFhhLXcOBsk?t=31m12s
user1133275
14

Dla celów argumentacji załóżmy, że Java 8 (i wcześniejsze) już je posiada „formę” modułów (jars) i systemu modułów (ścieżka klas). Ale są z nimi dobrze znane problemy.

Analizując problemy, możemy zilustrować motywację do Jigsaw. (Poniższy tekst zakłada, że ​​nie używamy OSGi, modułów JBoss itp., Które z pewnością oferują rozwiązania.)

Problem 1: publiczny jest zbyt publiczny

Rozważ następujące klasy (załóżmy, że obie są publiczne):

com.acme.foo.db.api.UserDao
com.acme.foo.db.impl.UserDaoImpl

W Foo.com możemy zdecydować, że nasz zespół powinien użyć UserDao a nie używaćUserDaoImpl bezpośrednio. Jednak nie ma sposobu, aby wymusić to na ścieżce klas.

W Jigsaw moduł zawiera module-info.javaplik, który pozwala nam jawnie określić, co jest publiczne dla innych modułów. Oznacza to, że opinia publiczna ma niuanse. Na przykład:

// com.acme.foo.db.api.UserDao is accessible, but
// com.acme.foo.db.impl.UserDaoImpl is not 
module com.acme.foo.db {
    exports com.acme.foo.db.api;
}

Problem 2: refleksja jest nieokiełznana

Biorąc pod uwagę klasy w # 1, ktoś nadal mógłby to zrobić w Javie 8:

Class c = Class.forName("com.acme.foo.db.impl.UserDaoImpl");
Object obj = c.getConstructor().newInstance();

To znaczy: refleksja jest potężna i niezbędna, ale jeśli nie jest zaznaczona, może być wykorzystana do sięgnięcia do wnętrza modułu w niepożądany sposób. Mark Reinhold podaje dość niepokojący przykład . (Post SO jest tutaj .)

W Jigsaw silna enkapsulacja daje możliwość odmowy dostępu do klasy, w tym refleksji. (Może to zależeć od ustawień wiersza poleceń, w oczekiwaniu na poprawioną specyfikację techniczną JDK 9.) Należy zauważyć, że ponieważ Jigsaw jest używany w samym JDK, Oracle twierdzi, że pozwoli to zespołowi Java na szybsze unowocześnianie wewnętrznych elementów platformy.

Problem 3: ścieżka klas wymazuje zależności architektoniczne

Zespół zazwyczaj ma model mentalny dotyczący relacji między słoikami. Na przykład foo-app.jarmoże użyć, foo-services.jarktóre używa foo-db.jar. Moglibyśmy stwierdzić, że klasy w foo-app.jarnie powinny omijać „warstwy usług” i używać ich foo-db.jarbezpośrednio. Jednak nie ma sposobu, aby wymusić to za pomocą ścieżki klas. Mark Reinhold wspomina o tym tutaj .

Dla porównania Jigsaw oferuje wyraźny, niezawodny model dostępności dla modułów.

Problem 4: monolityczne środowisko wykonawcze

Środowisko wykonawcze Java jest monolityczne rt.jar. Na moim komputerze jest to ponad 60 MB z 20 000 klas! W dobie mikrousług, urządzeń IoT itp. Niepożądane jest posiadanie na dysku bibliotek Corba, Swing, XML i innych, jeśli nie są używane.

Jigsaw dzieli JDK na wiele modułów; np. java.sql zawiera znane klasy SQL. Ma to kilka zalet, ale nowe jest to jlinknarzędzie. Zakładając, że aplikacja jest całkowicie zmodularyzowana, jlinkgeneruje dystrybuowalny obraz czasu wykonywania, który jest przycinany tak, aby zawierał tylko określone moduły (i ich zależności). Patrząc w przyszłość, Oracle przewiduje przyszłość, w której moduły JDK będą kompilowane z wyprzedzeniem do kodu natywnego. Chociaż jlinkjest to opcjonalne, a kompilacja AOT jest eksperymentalna, są one głównymi wskazówkami, dokąd zmierza Oracle.

Problem 5: wersjonowanie

Jest dobrze wiadomo, że ścieżka klasy nie pozwala nam korzystać z wielu wersji tego samego słoika: Np bar-lib-1.1.jari bar-lib-2.2.jar.

Jigsaw nie rozwiązuje tego problemu; Mark Reinhold podaje tutaj uzasadnienie . Istota jest taka, że ​​Maven, Gradle i inne narzędzia reprezentują duży ekosystem do zarządzania zależnościami, a inne rozwiązanie będzie bardziej szkodliwe niż korzystne.

Należy zauważyć, że inne rozwiązania (np. OSGi) rzeczywiście rozwiązują ten problem (i inne, oprócz punktu 4).

Podsumowanie

To kilka kluczowych punktów dla Jigsaw, motywowanych określonymi problemami.

Zwróć uwagę, że wyjaśnienie kontrowersji między Jigsaw, OSGi, JBoss Modules itp. To osobna dyskusja, która należy do innej witryny Stack Exchange. Różnic między rozwiązaniami jest znacznie więcej niż opisano tutaj. Co więcej, istniał wystarczający konsensus, aby zatwierdzić głosowanie w sprawie ponownego rozpatrzenia przeglądu publicznego dla JSR 376.

Michaela Wielkanocy
źródło
3

W tym artykule szczegółowo wyjaśniono problemy, które próbują rozwiązać zarówno OSGi, jak i JPMS / Jigsaw:

„Java 9, OSGi i przyszłość modułowości” [22 września 2016 r.]

Dokładnie omawia również podejście zarówno OSGi, jak i JPMS / Jigsaw. Jak na razie wydaje się, że autorzy nie wymienili prawie żadnych praktycznych zalet JPMS / Jigsaw w porównaniu z dojrzałymi (16-letnie) OSGi.

uvsmtid
źródło