Навіщо проектувати Jigsaw / JPMS?


79

Система управління пакунками Java мені завжди здавалася простою та ефективною. Він активно використовується самим JDK. Ми використовували його для імітації концепції просторів імен та модулів.

Що намагається заповнити проект Jigsaw (він же Java Platform Module System )?

З офіційного сайту:

Метою цього проекту є розробка та впровадження стандартної модульної системи для платформи Java SE, а також застосування цієї системи до самої платформи та до JDK.

Відповіді:


100

Jigsaw та OSGi намагаються вирішити одну і ту ж проблему: як дозволити більш грубим модулям взаємодіяти, захищаючи свої внутрішні елементи.

У випадку Jigsaw, більш грубі модулі включають класи Java, пакети та їх залежності.

Ось приклад: Весна та Зимовий сон. Обидва мають залежність від сторонніх JAR CGLIB, але вони використовують різні, несумісні версії цього JAR. Що ви можете зробити, якщо покладаєтесь на стандартний JDK? Включаючи версію, що Весна хоче перервати сплячий режим і навпаки.

Але якщо у вас є модель вищого рівня, така як Jigsaw, ви можете легко керувати різними версіями JAR в різних модулях. Подумайте про них як про пакети вищого рівня.

Якщо ви побудуєте Spring з джерела GitHub, ви також побачите його. Вони переробили фреймворк, тому він складається з декількох модулів: ядро, стійкість тощо. Ви можете вибрати та вибрати мінімальний набір залежностей модулів, який потрібен вашій програмі, а решту ігнорувати. Раніше це був один Spring JAR, у якому були всі файли .class.

Оновлення: П’ять років потому - у Jigsaw все ще можуть бути вирішені деякі проблеми .


5
Що робити, якщо вам все одно потрібно було використовувати той самий модуль, але дві різні його версії? Чи не слід їм просто додати якусь підтримку, щоб дві версії однакових класів могли співіснувати?
Дідьє А.

7
ця публікація вводить в оману, враховуючи те, що насправді планується випустити у Java 9. Можливо, це було точно на момент написання статті.
ксенотерацид

1
mreinhold.org/blog/jigsaw-complete Проект завершено та випущено для Java 9
Zasz

@xenoterracide, ти не можеш когось звинуватити в тому, що він не був ясновидцем. Пост передував Java 9 на п'ять років. Ви також переглядаєте кожну відповідь Джона Скіта?
duffymo

Цей пост погано старів. Модулі Java навмисно не вирішують проблему версій, див. Цю тему . Досі немає простого способу обійти наших старих друзів NoSuchMethodErrorі NoClassDefFoundError.
Тамаш Гегедус,

45

AFAIK План - зробити JRE більш модульним. Тобто є менші баночки, які є необов’язковими та / або ви можете завантажити / оновити лише ті функції, які вам потрібні.

Це робить його менш роздутим і дає вам можливість скинути застарілі модулі, якими, можливо, більшість людей не користуються.


7
Прийнята відповідь є дійсною, але ця відповідь є кращою, оскільки вона пояснює фактичні бажані ефекти. +1, заслужено.
Silviu Burcea

Мені цікаво, чи це також означає, якщо у мене є Google Guava як залежність, але я використовую в ньому лише ImmutableList, тоді я можу лише імпортувати залежності ImmutableList і залишити решту класів Guava поза?
tmn

1
@ThomasN. коли ви використовуєте importвсе, що це робить, це ввести цей клас у простір імен класу для компілятора. Якщо ви насправді не використовуєте його, він не відображатиметься у створеному байт-коді. Якщо ви насправді використовуєте клас, вам потрібно мати цей клас і кожен клас, який він використовує під час виконання. Теоретично ви можете створити скорочену версію API гуави, яка мала лише те, що вам потрібно, і замість цього використовувати цей JAR. Насправді це схильність до помилок і не дуже корисне в більшості випадків, і в кінцевому підсумку ви просто додаєте цілий JAR після випуску.
Пітер Лорі

43

На основі Mark Reinhold «s програмній промові на Devoxx Бельгії , проект Jigsaw збирається вирішити дві основні больові точки:

  1. Шлях до класу
  2. Масивний монолітний JDK

Що не так із Classpath?

Ми всі знаємо про пекло JAR . Цей термін описує всі різні способи, якими процес завантаження класів може закінчитися непрацюючим. Найвідомішими обмеженнями шлях до класу є:

  • Важко сказати, чи є конфлікти. інструменти побудови, такі як maven, можуть виконати досить хорошу роботу на основі імен артефактів, але якщо самі артефакти мають різні імена, але однаковий вміст, може виникнути конфлікт.
  • Основна проблема файлів jar полягає в тому, що вони не є компонентами. Це просто купа файлових контейнерів, які будуть шукати лінійно. Classpath - це спосіб пошуку класів незалежно від того, в яких компонентах вони знаходяться, в яких пакетах вони перебувають або за призначенням.

Масивний монолітний JDK

Велика монолітність JDK викликає кілька проблем:

  • Він не підходить для невеликих пристроїв. Незважаючи на те, що невеликі пристрої типу IoT мають процесори, здатні запускати віртуальну машину класу SE, але вони не обов'язково мають пам'ять для зберігання всього JDK, особливо, коли програма використовує лише невелику його частину.
  • Це навіть проблема в хмарі. Cloud - це все для оптимізації використання апаратного забезпечення, якщо у вас є тисячі зображень, що містять цілий JDK, але додатки використовують лише невелику його частину, це було б марнотратством.

Модулі: загальне рішення

Для вирішення вищезазначених проблем ми розглядаємо модулі як фундаментальний новий вид програмного компонента Java. Модуль - це іменована самоописана колекція коду та даних. Його код організований у вигляді набору пакетів, що містять типи, тобто класи Java та інтерфейси; його дані включають ресурси та інші види статичної інформації.

Щоб контролювати, як його код посилається на типи в інших модулях, модуль оголошує, які інші модулі йому потрібні для компіляції та запуску. Щоб контролювати, як код в інших модулях посилається на типи в своїх пакетах, модуль оголошує, який із цих пакетів він експортує.

Система модулів знаходить необхідні модулі і, на відміну від механізму шляху до класу, гарантує, що код у модулі може посилатися лише на типи в модулях, від яких це залежить. Механізми контролю доступу мови Java та віртуальної машини Java заважають коду отримувати доступ до типів у пакетах, які не експортуються за допомогою їх визначальних модулів.

Окрім надійності, модульність може покращити продуктивність. Коли код у модулі посилається на тип у пакеті, тоді цей пакет гарантовано буде визначений або в цьому модулі, або точно в одному з модулів, прочитаних цим модулем. Тому, шукаючи визначення конкретного типу, немає необхідності шукати його в декількох модулях або, що ще гірше, по всьому шляху до класу.

JEP, яких слід дотримуватися

Jigsaw - це величезний проект, який триває вже кілька років. У ньому є вражаюча кількість JEP, які є чудовими місцями для отримання більше інформації про проект. Деякі з цих JEP є такими:

  • JEP 200: Модульний JDK : Використовуйте модульну систему платформи Java (JPMS) для модуляції JDK
  • JEP 201: Модульний вихідний код : Реорганізуйте вихідний код JDK у модулі, вдосконаліть систему збірки для компіляції модулів та застосуйте межі модулів під час побудови
  • JEP 261: Модульна система : Впровадити Модульну систему платформи Java, як зазначено в JSR 376, разом із відповідними змінами та вдосконаленнями, специфічними для JDK
  • JEP 220: Модульні образи часу роботи : реструктуризуйте зображення часу виконання JDK та JRE для розміщення модулів та підвищення продуктивності, безпеки та ремонтопридатності
  • JEP 260: Інкапсулюйте більшість внутрішніх API : зробіть більшість внутрішніх API JDK недоступними за замовчуванням, але залиште доступними кілька критичних, широко використовуваних внутрішніх API, доки не будуть підтримувані заміни для всієї або більшості їх функціональних можливостей
  • JEP 282: jlink: Java Linker : Створіть інструмент, який зможе зібрати та оптимізувати набір модулів та їх залежностей у власне зображення часу виконання, як визначено у JEP 220

Заключними зауваженнями

У початковій редакції звіту "Стан модульної системи " Марк Рейнгольд описує конкретні цілі модульної системи таким чином:

  • Надійна конфігурація для заміни крихкого, схильного до помилок механізму шляху до класу засобом для програмних компонентів, які оголошують явні залежності один від одного, а також
  • Сильна інкапсуляція , щоб дозволити компоненту оголосити, які з його загальнодоступних типів доступні для інших компонентів, а які ні.

Ці функції принесуть користь розробникам додатків, розробникам бібліотек та реалізаторам самої платформи Java SE безпосередньо, а також опосередковано, оскільки вони забезпечать масштабовану платформу, більшу цілісність платформи та покращену продуктивність.


3
Марк Рейнгольд є головним архітектором Java Platform Group в Oracle, і ця відповідь є по суті його прямою відповіддю на саме це питання.
Джей

1
Для вашої кількісної оцінки HelloWorld може використовувати 15 МБ замість 553 МБ; youtu.be/rFhhLXcOBsk?t=31m12s
user1133275

14

Для аргументу припустимо, що Java 8 (і раніше) вже має "форму" модулів (банки) та модульну систему (шлях до класу). Але з цим є добре відомі проблеми.

Вивчаючи проблеми, ми можемо проілюструвати мотивацію Jigsaw. (Далі передбачається, що ми не використовуємо OSGi, модулі JBoss тощо, що, безсумнівно, пропонує рішення.)

Проблема 1: громадськість теж публічна

Розглянемо наступні класи (припустимо, що обидва є загальнодоступними):

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

На Foo.com ми можемо вирішити, що наша команда повинна використовувати, UserDaoа не використовуватиUserDaoImpl безпосередньо. Однак немає можливості застосувати це на шляху до класу.

У Jigsaw модуль містить module-info.javaфайл, який дозволяє нам чітко вказати, що є загальнодоступним для інших модулів. Тобто, публіка має нюанси. Наприклад:

// 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;
}

Проблема 2: рефлексія нестримна

З огляду на класи в №1, хтось все ще міг зробити це в Java 8:

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

Тобто: відображення є потужним і важливим, але якщо його не встановити, він може бути використаний, щоб потрапити до внутрішніх елементів модуля небажаними способами. Марк Рейнгольд має досить тривожний приклад . (Повідомлення SO тут .)

У Jigsaw, сильна інкапсуляція пропонує можливість заборонити доступ до класу, включаючи роздуми. (Це може залежати від налаштувань командного рядка, до перегляду технічних специфікацій для JDK 9.) Зверніть увагу: оскільки Jigsaw використовується для самого JDK, Oracle стверджує, що це дозволить команді Java швидше впровадити внутрішні компоненти платформи.

Проблема 3: шлях до класу стирає архітектурні взаємозв'язки

Команда, як правило, має ментальну модель відносин між банками. Наприклад, foo-app.jarможе використовувати foo-services.jarякий використовує foo-db.jar. Ми можемо стверджувати, що класи в foo-app.jarне повинні обходити "рівень обслуговування" і використовувати foo-db.jarбезпосередньо. Однак немає можливості застосувати це через шлях до класу. Марк Рейнгольд згадує про це тут .

Для порівняння, Jigsaw пропонує чітку, надійну модель доступності для модулів.

Завдання 4: монолітний час роботи

Час роботи Java є монолітним rt.jar. На моїй машині це 60+ МБ з класами 20k! У епоху мікросервісів, пристроїв IoT тощо небажано мати на диску бібліотеки Corba, Swing, XML та інші, якщо вони не використовуються.

Jigsaw розбиває сам JDK на безліч модулів; Наприклад, java.sql містить знайомі класи SQL. У цього є кілька переваг, але інструментом є нова jlink. Припускаючи, що програма повністю модулюється, jlinkгенерується розподільне зображення під час виконання, яке обрізано, щоб містити лише вказані модулі (та їх залежності). Забігаючи вперед, Oracle передбачає майбутнє, коли модулі JDK компілюються заздалегідь у власний код. Незважаючи на те jlink, що компіляція AOT є експериментальною, вони є основними ознаками того, куди рухається Oracle.

Проблема 5: встановлення версій

Загальновідомо, що шлях до класу не дозволяє нам використовувати кілька версій однієї і тієї ж jar: наприклад bar-lib-1.1.jarі bar-lib-2.2.jar.

Jigsaw не вирішує цю проблему; Обгрунтування тут викладає Марк Рейнгольд . Суть полягає в тому, що Maven, Gradle та інші інструменти представляють велику екосистему для управління залежністю, а інше рішення буде більше шкідливим, ніж корисним.

Слід зазначити, що інші рішення (наприклад, OSGi) справді вирішують цю проблему (та інші, крім №4).

Нижня лінія

Це деякі ключові моменти для Jigsaw, мотивовані конкретними проблемами.

Зверніть увагу, що пояснення суперечки між Jigsaw, OSGi, JBoss Modules тощо - це окрема дискусія, яка належить до іншого веб-сайту Stack Exchange. Існує набагато більше відмінностей між рішеннями, ніж описано тут. Більше того, було достатньо консенсусу для затвердження виборчого бюлетеня з перегляду громадських прав за JSR 376.


3

У цій статті детально пояснюються проблеми, які намагаються вирішити OSGi та JPMS / Jigsaw:

«Java 9, OSGi та майбутнє модульності» [22 вересня 2016 р.]

Він також детально описує підходи OSGi та JPMS / Jigsaw. На даний момент, схоже, автори майже не вказали жодних практичних плюсів для JPMS / Jigsaw у порівнянні зі зрілими (16 років) OSGi.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.