О проекте модуляризации Java мы слышим из года в год. Каждый раз ждём, следим за анонсами. Нам говорят, что Jigsaw практически готов, но каждый раз переносят срок выхода. Может быть, это не такой простой проект, как видится многим? Возможно, что изменения в нем повлияют на разработку в корне? Может быть, модулярная система — это только верхушка айсберга? Ответить на вопросы, связанные с проектом Jigsaw, мы попросили Ивана Крылова.

Иван занимается разработкой виртуальных машин Java и компиляторов более 10 лет, в настоящее время развивает компиляторную инфраструктуру в виртуальной машине Zing в Azul Systems. Регулярный докладчик на конференциях JUG.ru и других европейских Java-конференциях.

Что такое Jigsaw, и как он повлияет на мир Java?


— Иван, добрый день. Расскажите, пожалуйста, какое влияние проект Jigsaw окажет на экосистему Java?

— Добрый. Для объяснения моего взгляда на Java и модулярность стоит немного рассказать о моей деятельности. Коммерческим программированием я занимаюсь примерно двадцать лет. Последние одиннадцать из них — разработкой виртуальных машин. Работал в команде HotSpot Runtime в Sun. Потом компания была куплена Oracle. Далее было несколько изменений деятельности, и последние три с половиной года работаю в компании Azul Systems, где занимаюсь разработкой виртуальных машин.

Всё это я рассказал к тому, чтобы вы понимали, что мой взгляд на функциональность является взглядом разработчика JVM, человека, который достаточно далёк от мира «кровавого энтерпрайза», от проблем, с которыми сталкиваются разработчики высокого уровня абстракции.

Возвращаясь к вопросу о влиянии Jigsaw на экосистему Java, я бы сказал, что изначально это влияние не так велико, как может показаться. Начнём с того, что если разработчик не хочет переходить на парадигму модулей, он может не переходить. Старые способы взаимодействия с кодом и областями видимости в целом будут работать. Проблемы начнутся тогда, когда разработчик пытается перенести свой код в модули, а другой код еще не перенесён в модульную инфраструктуру.

Другие проблемы начнутся при использовании механизма OSGi, когда захотят перейти на механизм зависимостей Jigsaw, то поддерживать два способа написания этих зависимостей может оказаться затруднительным, но это различные частные случаи. В целом, для некоторого количества разработчиков проект Jigsaw пройдёт достаточно незаметно, поэтому оценить глобально для всех, наверное одного универсального ответа не будет.

— В Java 8 ключевыми нововведениями стали лямбда-выражения и Stream API. С какими значимыми изменениями можно сравнить Jigsaw?

— Модули проекта Jigsaw не оказывают большого влияния на написание кода и на функциональную последовательность действия кода. Jigsaw отвечает за то, как прописывается взаимодействие между различными компонентами, как мы заворачиваем код в единицы абстракции. В Java 9 и не планируются новые API, которые были бы революционными или сильно меняли то, как разработчики пишут свой код сегодня.

Есть определенные эволюционные изменения: например, в Java 8 появился Optional, в Java 9 в Optional добавится несколько методов, таких, как конвертер в Stream, метод or, но это инкрементальные изменения. Почувствовали необходимость добавить — добавили. Большие приятные изменения в Process API, которые позволят узнать pid виртуальной машины, получение дерева процессов, управления процессами. Process API позволит избавиться от некоторого количества хаков, которые нужно было наворачивать: например, вызовов shell с парсингом output или другие способы, уйдёт еще одна необходимость залезать в native. Такие инкрементальные изменения разбросаны по коду class libraries, но нет одного кода в API или одного мощного синтаксического изменения.

Все семантические изменений собраны в Milling Project Coin. Самое заметное — это, наверное, появление приватных (default) интерфейсных методов. Представим ситуацию, когда два приватных интерфейсных метода содержат общий код. Раньше такой код можно было вынести только в public метод, но такой метод может не иметь смысла с точки зрения публичного API, предлагаемого данным интерфейсом. Теперь такой метод может быть объявлен private. Этот метод не будет виден как часть API этого интерфейса, зато его реализацию можно спокойно использовать внутри этих дефолтных методов. Данное изменение позволит сделать чище тот API, который вы предлагаете с помощью интерфейса и, в частности, предлагая дефолтные реализациями методов этого интерфейса.

— Проект модуляризации существует давно, около девяти лет, сроки выхода переносились не один раз. На конференции JavaOne 2015 эта тема была удостоена вниманием нескольких докладчиков (Alan Bateman, Alex Buckley, Mark Reinhold). Такой ажиотаж вокруг показывает важность проекта?

— Проект Jigsaw потянул за собой определенные изменения. Я рассматриваю Jigsaw как некие две составные части, первая — это изменение в языке модели видимости, декларации модулей, синтаксис. Вторая часть — это то, как модель модулей была применена непосредственно к class libraries в jdk. Часть классов переехала, другие стали deprecated или перестали быть видимы снаружи.

Большие дебаты были про механизм reflection. Раньше он позволял достучаться до любого приватного класса и метода. Были возможны изменения полей на лету через reflection и их приватности. То есть были доступны, я бы сказал, эксплойты, которые использовались большим количеством библиотек. В конечном итоге это бы отразилось на пользователях. Перечисленные вами архитекторы языка вышли к сообществу, чтобы рассказать о том, какие изменения будут, почему они произойдут, зачем нужно делать эти болезненные изменения. Болезненность заключается в том, что некоторое количество библиотек сразу автоматически стало несовместимым. Перевод кода на более совместимую версию у них занимает время, что, как обычно, сопровождается шумом, например, таким: «переход на девятую версию ломает всё». Эти объяснения были необходимы.

Большое количество докладов про Jigsaw в прошлом году было на JavaOne, почти такое же количество на Devoxx в Антверпене. В этом будут такие же доклады, но будут интересные от сторонних людей, например, ребята из IBM рассказывают, есть ли жизнь после перехода на модули. Я с интересом буду ждать видеозаписей с JavaOne 2016.

— Новое понятие — модуль. Как правильно трактовать «составные» части модуля: module name, exports и requires? Хотелось бы поподробней остановиться на «requires» и понять, что же мы в действительности сможем «требовать», например, «requires local» или «requires optional»?

— Давайте начнем с простого книжного примера, ситуации, когда у вас нет существующего кода, вы просто пишете его с нуля. У вас есть классы и вы разместили их в разных пакетах, решили, что у них не должны быть тесной однозначной связи, и они в различных модулях. Когда какому-то классу из первого модуля нужны классы из второго модуля, он говорит, что мне нужен, то есть requires, вот этот модуль два, указывая какие пакету ему нужны. Вся иерархия достаточно строгая, если пакет управляет абстракциями на уровне классов, то модуль управляет иерархией уровня пакет, это выражение requires.

Проверка происходит в обоих случаях: и в момент компиляции и в момент исполнения, как это довольно часто происходит и с другими элементами языка Java. JVM не может гарантировать, что все проверки были пройдены, скажем так, честно, на уровне компиляции, байткод может приходить откуда угодно, поэтому во многом проверки дублируются и в javac, и на уровне JVM Runtime. Requires проверяет, что необходимые для работы этого модуля пакеты доступны, эти пакеты находятся каком то модуле два или модуле три. Если тем, в свою очередь, нужны ещё какие-то модули, то строится такая транзитивная цепочка с тем, чтобы проверить буквально в самом начале работы, что все необходимые пакеты из соответствующих модулей нам доступны.

Затем, exports — это механизм видимости. Он говорит о том, что этот модуль предоставляет такие-то пакеты другим модулям. Можно указать, что всем сразу — это условная "*", которая показывает, что все другие модули, все, кто хочет пользоваться этим модулем, могут пользоваться пакетами. Это означает не то, что абсолютно все классы доступны пользователям, а лишь те, которые задекларированы public, т.е. те, которые ескейпятся, становятся доступны другим модулям через этот механизм. Можно указать export to когда вы хотите проэкспортировать непосредственно указанному модулю и никому больше и этот механизм статической декларации.

Кроме того, есть определенные рантайм флаги, которые позволяют в момент вызова для уже скомпилированного модуля поменять эти области видимости, с тем, чтобы не требовалось пересобирать модуль. Если бы у него не хватало экспортов для успешной работы, то можно их добавить в командной строке, но это видится как промежуточный этап, потому что, по идее, все декларации должны быть в модуле. Т.е. модуль — некая законченная единица с декларацией того, что нужно и что нет этому модулю и что он предоставляет другим модулям для использования.

В принципе сама jdk перестроена таким образом, чтобы весь набор библиотек jdk представлял набор модулей с понятными зависимостями. Результат такой, что мы можем построить некий subset jre, в которой будут только те модули, которые нам необходимы. В этой связи появилась утилита jlink, которая позволяет собрать Run-Time Image только лишь из тех модулей, которые нам нужны. Это определенное развитие идеи, которая появилась в Java 8 с профилями. В jdk 8 можно было собрать jdk под разные профили с разным количеством классов и разным количеством функциональности, но это, скажем так, статическая сборка, без проверки того, что уже реально приложению понадобится. А jlink позволит нам собрать некий переносимый Runtime, который будет состоять из виртуальной машины, модуля java.base, еще какого то количества модулей, необходимых приложению.

В одной презентации авторы книги про модули в java 9 Paul Bakker и Sander Mak приводили различные примеры. Собрали вариант программы простого текстового анализатора с необходимым рантаймом — получился дистрибутив примерно в 20 мегабайт. Когда добавили в приложение swing-окошки, то добавились новые модули, размер такого дистрибутива вырос до 50 мегабайт. Границы JDK библиотек при этом размазываются, потому что помимо модулей, которые находятся внутри jdk и которые будут поставляться вместе с jdk, также можно добавлять модули сторонних библиотек, т.е. такие дистрибутивы совершенно по разному будут скомпонованы. Это позволит по новому распространить программу, не требуется чтобы заказчик пошел и скачал новую версию jdk, а поставлять непосредственно собранным Runtime`ом.

— О проблеме "Dependency hell" можно забыть навсегда?

— Довольно часто в реальных продакшн-системах можно увидеть очень длинную строчку classpath, где перечислено большое количество jar, или каталогов, где находится скомпилированный код. Зачастую оказывается так, что в классах задекларированы одни и те же классы одних и тех же пакетов, и тогда Runtime берет тот, который раньше появился в classpath. В связи с этим очень много людей отмечали такую проблему, когда от перемены мест jar в class-пути менялось поведение программы, вот это с помощью модулей решается на корню.

Происходит это следующим образом: если у нас классы разложены по пакетам, то определённый пакет может декларировать один-единственный модуль. Поэтому если, например, у нас находятся два модуля в двух jar и оба они включают элементы пакета, то такая ситуация невозможна, потому что предполагается, что теперь пакет принадлежит одному из модулей, т.к. каждый модуль декларирует пакет однозначно. При этом Jigsaw не решает проблему версионного контроля, т.е. соответствие версий в том понимании, в которым мы привыкли видеть в package manager-ах, например, в Linux.

Задача версионного контроля модулей изначально стояла в более ранних версиях, но потом её сняли, единственное, что можно сделать — записать версию в метаданные. Можно извлечь эти метаданные, но непосредственно механизм загрузки классов никаких дополнительных проверок не делает, это отдано на откуп другим пакет менеджеров, например OSGi, которые могут быть положены поверх. Это сделано по причине вычислительных сложностей. Это достаточно сложная задача, которую не хотели отдавать classloader`у, поэтому её передали внешнему инструментарию.

— Появятся различные виды модулей: Named Modules, The Unnamed Module, Automatic Modules. Вы можете кратко рассказать о них? В чем состоят их отличия и что каждый привносит в общую структуру?

— Если вы пишите модуль «с нуля», по всем правилам, то есть положите его в каталог верхнего уровня с названием модуля, добавите файл module-info.java, в котором содержится декларация модуля, название, которое должно совпадать с названием каталога, с перечислением exports и requires. Такой модуль — это обычный именованный модуль.

Если вы живете по старинке и у вас есть классы, которые вы просто привыкли закидывать через classpath, они тоже окажутся в модуле, который называется Unnamed Module. Поэтому для модулей, которое вы не назвали, есть безымянное последнее прибежище, так как теперь девятка не сможет работать без модулей.

Есть некая промежуточная стадия, когда у вас, например, jar файл, в нем находятся какие то пакеты, вы его положили не в classpath, а в modulepath, тогда Runtime начинает представлять его себе этот файл как некий модуль, название которого совпадает с названием jar-файла, и с ним дальше можно делать похожие вещи, как с Named модулем, и ссылаться на него.

Например, если вы разрабатываете свой именованный модуль. Вы зависите от какой то библиотеки, которая ещё не была переведена в модульную структуру, то сможете положить jar с этой библиотекой в modulepath. Он станет автоматическим модулем. Теперь вы в module-info.java можете ссылаться: requires и дальше имя модуля, который был назначен ему автоматически.

И наконец, последнее изменение, которое происходит последние недели, и ещё не совсем понятно, будет ли принят это proposal или нет. Я уже сказал чуть раньше, что существует определенная проблема с reflection, если раньше можно было достучаться до чего угодно, то теперь на уровне виртуальной машины существует защита, и появляется новая концепция, которая сейчас идёт в разработке, и, возможно, попадет в стандарт, хотя это не гарантировано — weak модуль.

Weak модуль — это такое промежуточное состояние, в котором код в этом модуле может через reflection достучаться до классов, которые находятся в именованных модулях, и даже тех, которые не экспортированы правильным образом, но при этом сам такой модуль экспортировать свою функциональность наружу не может. Это было сделано специально, чтобы пройти этот переходный период, когда нам надо будет через reflection доставать, достучаться до внутреннего кода, который изначально для этого не предназначался.

Я думаю, что со временем использование weak модулей сойдет на нет, может быть, они останутся в отладочных целях. Как и Automatic модули — это промежуточный механизм, который позволяет пройти путь миграции от немодуляризованного кода к модуляризованному.

OSGi vs Jigsaw: холивара не будет


— Почему не была одобрена OSGi для модуляризации Java? Вы согласны со словами Mark Reinhold: «The OSGi module layer is not operative at compile time; it only addresses modularity during packaging, deployment, and execution. As it stands, moreover, it’s useful for library and application modules but, since it’s built strictly on top of the Java SE Platform, it can’t be used to modularize the Platform itself»? Существует проект Penrose для взаимодействия OSGi/Jigsaw. (Модульный слой OSGi не действует в момент компиляции; обращается к модулярности только во время архивации, развёртывания или выполнения. Кроме того, в том виде, в каком он (OSGi) есть, он полезен для библиотек и модулей приложений, но поскольку он создаётся строго на основе Java SE Platform и не может быть использован для модуляризации своей платформы (прим. перевод автора).

— Я специально изучил OSGi, и у меня появилось определённое мнение на счёт того, почему всё-таки не OSGi стал Jigsaw. Первый ответ на поверхности, его обозначил Mark Reinhold: сам механизм написан поверх спецификации Java SE, если мы хотим делать поставку Java SE фрагментами, то есть модулями, то механизм OSGi нам не поможет, нам необходимо что-то на более низком уровне. В целом OSGi работает через механизм class loading`а, то есть появляется сначала один общий OSGi environment classloader, потом на каждый bundle OSGi появляется по своему classloader'у, и благодаря этому происходит некое разграничение видимости классов.

Механизм Jigsaw делает аналогичную функциональность, но уже на уровне виртуальной машины, что, в свою очередь, достаточно существенно для производительности самой виртуальной машины. Не секрет, что внутри виртуальной машины класс адресуется через последовательность: classloader и дальше пакет и имя класса, через вот эту пару. И если пакета и имя класса — это конкретные строковые литералы, которые ему соответствует, то classloader — это просто референс на объект class loading'a. Таким образом проанализировать в случае persist'a, когда мы завершили виртуальную машину и потом эти данные пытаемся восстановить при следующей загрузки, этот референс теряет какой либо смысл, у classloader'а нет собственного строкового литерала. Это накладывает ограничения на оптимизацию работы вот в таком ahead of time стиле. Поэтому разработчики Jigsaw решили отказаться от базирования этого механизма видимости на механизм class loading'a, как это было сделано в OSGi. В OSGi так сделали, потому что это было единственное, что им доступно из того, что предоставляет виртуальная машина, они не могли вмешаться в механизм class resolution.

— Получается, что фактически реализация у OSGi и Jigsaw на разных уровнях.

— Да, совершенно верно. Jigsaw реализован на более низком уровне. К счастью или несчастью. Наверное, к некоторому несчастью для тех, кто уже успел задействовать OSGi. Теперь придётся как-то взаимодействовать, поддерживать два параллельных описания зависимостей, или использовать проект типа Penrose, который позволяет синхронизировать. Описание задаётся с помощью JSON-скрипта, из которого можно сгенерировать модульное описание, Jigsaw-описание зависимостей и OSGi-описание. Придётся скрещивать эти два мира, и у тех пользователей, которые используют OSGi в настоящее время, жизнь станет немножко сложнее.

— Какие изменения произойдут в работе classloader'ов?

— Изменения на самом деле не такие уж и большие. Раньше у нас был механизм, состоящий из трех ступеней, это Bootstrap classloader, Extension classloader и Application classloader, который раньше был instance of URL classloader. Изменения в Java 9 состоит в том, что Extension classloader преобразуется в Platform classloader и связано это с тем, что если раньше Extension использовался для загрузки определённого вида классов, дополнений к jdk, их было немного. В Java 9 провели определённую работу и поняли, что у большого количества модулей можно понизить привилегию, чтобы перенести загрузку из Bootstrap classloader, и делать это с помощью Platform classloader. Наконец, Application classloader, если раньше он был instance of URL classloader, теперь это instance некого внутреннего класса. Это, в частности, в определённый момент сломало Gradle, который использовал это знание, он искал instance of URL classloader — это было неправильно. Вроде как Gradle уже поддерживает Jigsaw и эта проблема там решена.

С точки зрения пользователя, если приложение не использует эти знания, представления, как это делал Gradle, ничего сильно не изменится. В противном случае необходимо будет пересмотреть механизм, как вы работаете с Application classloader'ом. Для большинства людей эти изменения пройдут незаметно.

На уровне виртуальной машины, конечно же, есть определённые изменения, проверки видимости классов — появляется новый класс ошибок.

Область, которая получает развитие — это дополнительные оптимизации, которые связаны с тем, что если класс не выходит за пределы модуля, т.е. он не экспортируется через пакет наружу, у нас появляется возможность делать Whole Program Optimization, которые раньше были недоступны, т.к. раньше класс мог появиться в неожиданный момент, целый пласт jit-оптимизации был нам недоступен. Вплоть до того, что есть определённая информация, что Oracle работает над интегрированием ahead of time компиляции и упаковки уже бинарно скомпилированного кода в jmod, это ещё один формат для хранения модулей для более быстрого старта кода, который заключён в эти модули. Но по этому поводу информации я видел пока очень мало, посмотрим, возможно, что работа еще не доведена до какого то момента.

Решаем головоломку: ошибки, предупреждения и предостережения


— Какое мнение у вас сложилось о системе предупреждений и ошибок во время компиляции?

— Не могу сказать, что у меня пока огромный опыт в разработке Jigsaw модулей, я попробовал различные примеры. Могу рекомендовать читателям взять хрестоматийный вариант с двумя модулями, где один экспортирует, а второй что-то requires. Далее попробовать скомпилировать и проверить, что всё работает, получить, например, «Hello World». А потом стоит взять и поменять что-то: убрать requires или exports. Поменять название модуля, чтобы он не совпадал с названием каталога в котором он лежит, поменять название на кириллицу, вставить символ в название, например, подчёркивание или цифры и посмотреть, что случится.

Я бы предложил попробовать вот в таком режиме, на совершенно изолированном проекте, прежде чем это сделать на своем продуктовом коде. Аналогично можно попробовать работу с IDE, сначала собрать и запустить хороший пример, а потом его сломать и посмотреть, какие ошибки появляются.

По моим представлениям ошибки фазы компиляции будут сродни таковым, когда вы пытаетесь достучаться внутри пакета к private классу откуда-то, у вас ошибка видимости. Такую диагностику javac компилятор делает для модулей, когда вы пытаетесь достучаться до класса, который не видим. В части диагностики я не вижу больших изменений, правила, конечно же, меняются, потому что поменялись правила видимости и class resolution, я не думаю, что будет сильная разница с ошибками, которые встречаются при ошибках видимости, связанные с пакетами. Т.е. это ещё один уровень абстракции, но категория ошибок точно такая же.

— В основной массе, IDE уже имеют возможность выбора языкового уровня «Jigsaw». Возможно, что часть проверок и контроля будет сделана за пользователя. Что вы думаете по этому поводу?

— Самая большая связанная с модулями сложность, как мне кажется, заключается в том, что проект идёт очень долго, само слово module очень многозначно, и попытки найти ответы на StackOverflow или в Google зачастую приводят на устаревшие тексты, поэтому очень внимательно нужно смотреть на дату ответов.

Аналогично с IDE: например, полтора года назад я открыл IDEA, и там уже встречалось слово «модуль», но подразумевались другие модули, не имеющие отношение к Jigsaw. Поэтому, если вы планируете разработку модулей в IDE, то нужно убедиться, что IDE свежая, т.к. можно нарваться на другое прочтение слова «модуль».

— Одно из определений Jigsaw — «головоломка». Насколько сложной стала разработка, на ваш взгляд?

— Если бы у меня был бы багаж знаний о модулях в других языках, или богатый опыт с OSGi, я бы, наверное, хватался за голову и говорил, почему они его так сделали, а не эдак. У меня такого опыта нет, и принять концепцию модулей, вот это новый уровень абстракции, как декларируются зависимости было достаточно просто.

В Java 8 появилась утилита jdep, она входит в стандартную поставку jdk, которая позволяет посмотреть на зависимости между пакетами и в Java 9 появляется возможность натравить вот эту утилиту на jar файл и сгенерировать module-info.java в файл, так что на него можно посмотреть глазами, подредактировать и увидеть, что какие то requires нам на самом деле не нужны или их можно заменить. Jdep дает полностью готовый module-info.java, и можно посмотреть и привести в такое состояние, в каком вы хотите его видеть, т.е. не нужно писать с нуля, анализировать все свои зависимости, jdep прекрасно с этим справляется и очень сильно в этом помогает.

Я не думаю, что работа по созданию модуля будет такой сложной, инструментарий достаточно неплохо написан, чтобы помочь разработчикам перейти на модули.



О модулярности Java 9 на Joker 2016 расскажет Sander Mak, который сейчас готовит книгу Java 9 Modularity для O'Reilly, в своём докладе Java 9 Modularity in Action.

Если вы любите «кишочки» JVM и ждете Java 9 так же, как мы, то рекомендуем вам посмотреть следующие доклады Joker 2016:

Полная программа конференции – на сайте.
Поделиться с друзьями
-->

Комментарии (33)


  1. h31
    21.09.2016 18:45
    +1

    Это позволит по новому распространить программу, не требуется чтобы заказчик пошел и скачал новую версию jdk, а поставлять непосредственно собранным Runtime`ом.

    А что тогда делать с обновлениями безопасности? Например, вышла новая версия JRE с исправлениями серьезных ошибок, а разработчик не хочет пересобирать приложение с новой версией (например, прекратил разработку продукта). С учетом того, сколько находят дыр в JRE — это очень важный вопрос.


    1. sunless
      21.09.2016 18:52
      +2

      а разработчик не хочет пересобирать приложение с новой версией

      "Перед смертью" надо разработчику оставить завещание зарелизить приложение как stand-alone модуль. Не смотрел, можно ли jmod бандл "разобрать" на составляющие модули и выдрать, собственно, уникальный код. Всё-таки, это не zip архив. Думаю, поставка приложений в виде jimage будет малораспространённым яалением.


    1. slavca
      21.09.2016 19:28
      +1

      Вот было бы здорово, если б дошли до системы поставки:
      распространяют голую JRE (ядро + java.base), остальное загружается из репозитория с проверкой обновлений.
      Я бы и сам не отказался так распространять свой продукт — когда отдаешь пользователю один модуль, где только регистрируется репозиторий, а в нем уже функциональные модули.


      1. Saffron
        21.09.2016 22:49

        Ну вот SBT точно так работает.


      1. pjBooms
        22.09.2016 07:38
        +2

        Было такое — называлось Java Kernel aka Consumer JRE в Java 6 Update 10. Как-то пользователей этой вещи не нашлось и к 8-ке выкинули. Хотя по правде скзазать работало не очень


      1. guai
        23.09.2016 14:42

        в цейлоне так сделали


    1. pjBooms
      22.09.2016 09:01
      +4

      Если внимательно смотреть какие ошибки безопасности испавляются в JRE, то можно обратить внимание, что большинство из них относятся к Java апплетам и Java Web Start, которые по сути — всё. То есть дыр в JRE много, касаемо того, что если вы заходите на какой-то (случайный) сайт, а там стоит Java апплет (когда вы его последний раз видели?), и ваш браузер умеет их запускать без вашего ведома, то если у вас Java не новая, то этот апплет вполне может получить полный доступ к вашему компьютеру через дыры в JRE (и сделать что-нибудь плохое вам).

      Если же вы ставите себе stand-alone приложение, то оно как правило всегда получает полный доступ к вашему компьютеру (в лучшем случае вас предупредят, что «запуск этого приложения может причинить вред вашему компьютеру).И новые версии Java вас не спасут от этого факта. И если вы ставите приложение из сомнительных мест, то у вас всегда есть риск подхватить что-то. И Java здесь вообще не причем, это приложение может быть написано на чем угодно.

      То есть обновления безопасности Java заботяться о вас как о пользователе компьютера (не разработчика) от несанкционированного доступа к вашему компьютеру посредством запуска Java кода с (подозрительных) интернет сайтов. То есть он защищает вас пользователя от разработчика. Если разработчик не хотел причинить вред вашему компьютеру и перестал ее разрабатывать, то программа сама не захочет причинить вред вашему компьютеру в будущем, обновите вы Java или нет. А если хотел, то ему ее вообще возможно проще было написать на C или ассемблере — в этом случае никакое обновление Java вас не спасет.

      А если Java программа торчит в сеть и обробатывает какие-то запросы, и о чудо нашлась дыра в JRE позволяющая внедрить код в эту программу без ее ведома через посылку запроса (или получить какой-нибудь другой несанкционированный доступ), то если в этот момент разработчик прекратил разрабатывать эту программу, то я как пользователь этой программы скорей всего бы снес ее тут же, потому что точно такая же дыра может тогда обнаружится не только в JRE, но и в коде самой этой программы. И опять никакое обновление Java меня тогда не спасет.

      Недавно знакомый не программист, узнав что я занимаюсь Java, пожаловался мне что Java у него постоянно моргает, просит обновится, и он не знает нужно ли ее обновлять. И знаете что я ему посоветовал? Снести Java! И это при том, что я делаю Java последнии 20 лет. Java — на десктопных компьютерах обычных пользователей со всеми ее обновлениями — это какой-то артифакт из 90-х, по моему мнению. К сожалению я разработчик и мне нужна Java на всех компьютерах, что я исспользую, для разработки. Поэтому провести чистый эксперимент — снести Java и посмотреть, потребуется ли она мне в непрограмиисткой жизни — не могу. Но я пробовал запускать специально апплеты в своих браузерах и они нигде сейчас не работают, даже аплеты-примеры с Ораклового сайта. Нужны какие-то специальные настройки, чтобы они заработали, ведомые только админам интранетов, где есть копоративный клиентский софт на Java, запускаемый из браузера или через Java Web Start. И у меня нет приложений на Java запускающихся на „дефолтной“ JRE, то есть, той которая постоянно требует обновленний. Все вменяемые разработчики клиентского софта на Java уже давно бандлят JRE вместе со своими приложениями. И опять же клиентский десктопный софт на Java все меньше и меньше пишут. А на серваках, если у вас сервер запускается на JRE, а эта JRE обновляется по клику на system tray (кем?), то я бы не назвал способ деплоя вашего приложения хорошим.


      1. SirEdvin
        22.09.2016 11:27

        Minecraft? Ну еще есть банки, или вот тестер на сайте Nvidia тоже на java написан.


        1. pjBooms
          22.09.2016 11:40

          Говорят (сам не знаю), что Майнкрафт переписали в Микрософте на C++, а до этого Микрософт его распространял с забандлиной Java. Интернет-банки на Java апплетах честно гояворя не видел, правда есть такие? Последнее, что видел на аплетах — это покупку билетов в один из театров. Не работал, хотя Java понятно стояла. Быстро потом с этого сайт пропал аплет. А Nvidiа да, когда ставил винду с нуля, Java у меня появилась именно из-за Nvidia. Но Nvidia, можно доверять и без обновлений Java. И опять же как часто пользователи тестят что-то подобное? Короче весьма сомнительна сейчас необходимость Java на десктопах обычных пользователей.


          1. SirEdvin
            22.09.2016 11:43

            Говорят (сам не знаю), что Майнкрафт переписали в Микрософте на C++, а до этого Микрософт его распространял с забандлиной Java.

            Пока не рискнули и вряд ли сделают, так как моды. + Помимо майкрософтов есть куча других лаученров, типа FTB, которые не поставляют java (не знаю, поставляют ли майки).


            Интернет-банки на Java апплетах честно гояворя не видел, правда есть такие?

            В Украине пока есть) Правда, некоторые предлагают альтернативы, но часть сервисом все ще на java (у ПриватБанка на java сервис создания електронных подписей).


          1. leventov
            27.09.2016 03:42

            В банке авангард подпись джава апплетом. Приходится запускать из IE11, последнего браузера из которого это еще можно сделать. А ведь считается довольно прогрессивным банком.


  1. m0nstermind
    22.09.2016 13:42

    Главная тема про jigsaw имхо не раскрыта — какие фичи он дает разработчикам программ на java? Очевидно, что если мне зачем-то (зачем?) захочется распилить программу на модули смогу это сделать еще и через jigsaw.
    OSGi правда для этой цели есть давно, по его популярности нельзя сказать что желание распилисть что то на модули возникает у многих.

    И еще страньше то, что эту тему старательно обходят все, говорящие о jigsaw. прямо заговор какой то.


    1. sunless
      22.09.2016 13:51
      +2

      Я вижу 2 основные фичи


      • механизм отслеживания зависимостей между модулями, то есть ClassNotFoundException случится не в момент обращения к этому классу, а при старте приложения (и в другом виде). Аналогично компиляция модулей даже не начнется, если требуемых модулей нет.
      • возможность поставки приложения с сабсетом JRE, а также работа приложения на уже установленном сабсете JRE.
        Тема с автоматической подгрузкой стандартных недостающих модулей с вправду нераскрыта, видимо, этим будут заниматься сторонние менеджеры.


      1. pjBooms
        22.09.2016 18:38

        Я не думаю, что будет возможность ставить subset JRE.
        Распространять с сабсетом — да — это одна из целей. Что касается автоматической подгрузки недостающих модулей, то в подходе Jigsaw — само понятие «недостающих» нет. Все что вашему приложению нужно определяется статически на этапе компиляции и далее вы не можете распространять свое приложение без каких-то модулей, которые нужны. Если у вас приложение с плагинами, то скорей всего вам нужно будет распространять своей приложение либо с полным JRE, либо самому придумывать как доставлять куски платформы требующиеся плагину при его установке (а что нужно опять же статически известно в модульном подходе).


    1. Throwable
      22.09.2016 16:20

      Никаких. Если смотреть по аналогии кто пользует OSGi, то это достаточно узкоспециализированная область контейнеров и серверов апликаций. Jigsaw не решает многих проблем, типа версионирования, динамической подгрузки/выгрузки, активации/деакцивации модуля, etc..., что уже умеет OSGi. Например, Jigsaw не умеет из коробки управлять в рантайме разными транзитивными версиями одного модуля (хотя это может быть допилено вручную).
      Модульность должна широко быть принята разработчиками билд тулзов и библиотек. Я думаю, этого не случится, потому как выигрыш очень сомнительный, а зартаты огромны.


      1. doom369
        22.09.2016 17:14
        +1

        Никаких

        Ну как минимум размер памяти потребляемый JVM должен сократится за счет подгрузки только необходимых классов, если я правильно понял. Для некоторых проектов, например, для моего это критично.


        1. sunless
          22.09.2016 17:24
          +2

          Классы в JVM загружаются лениво, так что footprint не поменяется.


          1. doom369
            22.09.2016 17:32

            Есть ядро классов которые 100% загружаются. Благодаря модульности часть из них не нужно будет подгружать если они не используются. Но в этом я не сильно уверен. Если есть какие-то ссылочки на почитать об этом буду благодарен.


            1. sunless
              22.09.2016 17:58
              +1

              Bootstrap классы грузит ВМка всегда, их число меняется от версии к версии. Это т.н. well known классы. Что почитать? Кроме исходников, трудно что-то посоветовать, в статьях и книжках такие детали реализации не приводят. -XX:+TraceClassLoading помогает.


          1. doom369
            22.09.2016 17:47

            В общем провел небольшой тест и похоже мы оба правы. Запустил hello world без единого импорта и получил через jstat

            S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
            10752.0 10752.0  0.0    0.0   64512.0   2580.5   172032.0     0.0     4480.0 774.0  384.0   75.8       0    0.000   0      0.000    0.000
            


            Из интересного

            MC: Metaspace capacity (kB).
            
            MU: Metacspace utilization (kB).
            
            CCSC: Compressed class space capacity (kB).
            
            CCSU: Compressed class space used (kB).
            


            То есть классы в JVM занимают около 1МБ для hello world.


    1. pjBooms
      22.09.2016 20:02
      +2

      А что вы хотите услышать? Jigsaw — это все про модули, которых в явном виде до Jigsaw не было в платформе, и это есть основная фича, дающаяся разработчикам Java.

      По факту все и сейчас пилят свои приложения на модули, используется ли OSGi или нет: редкий проект у которого все исходники порождают единственный артефакт. А если у вашего проекта на выходе много артефактов (жаров), то welcome, you are in Modules club! Только возможно вы до сего момента этого не осознавали. А как только вы осознаете, что ваш проект уже модульный, прямо сейчас, то вам становится довольно очевидно какие плюшки вам дает Jigsaw:

      1. Зависимости между вашими модулями становятся явными. По крайней мере это будет организовывать вас и ваших коллег при написании программы. Циклические зависимости запрещены — гораздо меньше возможностей плодить неконтролируемые зависимости между модулями превращая эти зависимости в спагетти. Результат — более качественная архитектура проекта.

      2. У модуля появляется наконец-то инкапсуляция! Теперь никто и никогда не сможет залезть в кишочки реализации вашего модуля (в том числе через reflection), которые вы не собирались никому открывать, а потом жаловаться, что вы эту реализацию поменяли. Из-за одной этой фишечки, я бы уже рекомендовал как можно чаще использовать модульный подход в проекте. Ранее через reflection можно было достучаться до чего угодно, даже в OSGI.

      3. Даже, если весь ваш проект собирается в один артефакт, то с большой вероятностью вы все равно используете внешние зависимости, aka библиотеки. Всем этим производителям библиотек рано или поздно прийдется перейти на модули. А значит бардака в этой области тоже будет меньше. К примеру не возможна будет ситуация, когда две библиотеки, которую использует ваш проект, используют какую-то третию библиотеку, но разных версий. Что сплошь и рядом встречается сейчас, порождая различные плохо диагностируемые проблемы (что собственно и называется JAR или classpath hell).

      4. Да, возможность распространять приложение с сабсетом платформы — часто важно. Важно в Embedded, и когда приложение само значительно меньше чем JRE и использует лишь малую часть платформы (игры к примеру).

      Ну и в завершение Jigsaw дает возможность эволюции Java платформы как таковой, не нужно держаться за всякое легаси типа CORBA, выделяя его в отдельные (опциональные) модули и идти вперед. Это не дает вам, как разработчику, никаких фич прямо сейчас, однако опосредованно это принесет вам добро в будущем.


      1. Saffron
        22.09.2016 23:09
        +1

        Пункт 2 — это плохо, а рефлексия — это хорошо. Впрочем, остаётся возможность подменять код статически — накладывать патчи прям из билдера или использовать агент для переписывания загружаемого кода.

        > К примеру не возможна будет ситуация, когда две библиотеки, которую использует ваш проект, используют какую-то третию библиотеку, но разных версий.

        Откуда дровишки? Версионного контроля jigsaw не предлагает.


        1. pjBooms
          23.09.2016 09:36

          Откуда дровишки? Версионного контроля jigsaw не предлагает.

          По дизайну. У тебя просто не встанут два разных модуля с одним и тем же именем в module path — http://openjdk.java.net/projects/jigsaw/spec/sotms/#the-module-path

          Пункт 2 — это плохо, а рефлексия — это хорошо.

          Рефлексия сама по себе — хорошо. Но доступ к тому, что не предполагалось быть доступным — плохо. Для внешнего наблюдателя, все что не экспортирует модуль должно интерпретироваться как несуществующее. Потому, что сегодня это одно, а завтра совсем другое. В этом и есть смысл инкапсуляции.


          1. guai
            26.09.2016 11:55

            Куча примеров вспоминается, когда без доступа к кишкам сторонней либы программа бы не существовала. Еще больше — когда код стал бы тяжелее.
            Альтернатива какая?
            Если оперсорс — нафоркает каждый по стопицот раз и опубликует нужные кишки. А если не опенсорс? Клянчить у разрабов изменения в интерфейсах?
            А бывает проект дохл, но еще полезен.
            Костыли, костыли, костыли. Причем гораздо более тяжелые, чем залезть рефлекшеном, изолировать этот кусок и обложить его тестами.
            Считаю, контракт от не-контракта отделять стоит, но вот так прям всё рубить на корню — ни разу не благо.


            1. pjBooms
              26.09.2016 12:39
              +1

              В Java 9 придумали до фига способов, чтобы «менее тяжелые костыли» продолжали работать:

              1. Если либа лежит в classpath и костыльный код, исправляющий ее косяки, тоже, то все будет работать как прежде

              2. Если вы захотели модулиризовать свое приложение и код, зависящий от либы отправить в module path, то либу вы можете спустить в module path как automatic module, который по определению экспортирует все, а значит «костыльный код» будет опять работать.

              3. Если либу успели модулиризировать (добавили module-info), но косяк, исправляющийся костыльным кодом не исправили, то вы ее можете либо демодулизировать, удалив module-info ручками, либо добавив в строку запуска
              -XaddExports:YourEvilModuleThatYouNeedSoMuchAndCantChangeWithoutReflectionHacks

              Надо понимать, что Java 9 модули придумали не для того, чтобы вас в чем-то ограничить, а для того чтобы вы могли делать надежную архитектуру своего приложения со строгой инкапсуляцией (reliable configuration with strong encapsulation). А способов накостылять (aka smooth migration to modular architecture) остается довольно много.


              1. Saffron
                26.09.2016 14:42

                Да просто народ не привык делать final классы и методы, а согласно концепции отрытого мира они могут быть в любой момент наследованы и переписаны, так как ява машина может подхватывать новый байткод на лету. И это очень огорчает оптимизатор, который, например, желает заинлайнить некоторый метод, но не может — вдруг его потом перепишут? А модули — это такой способ провести в отрытом прежде мире границы, и сделать его уже не таким открытым.


                1. sunless
                  26.09.2016 14:45

                  оптимизатор, который, например, желает заинлайнить некоторый метод, но не может — вдруг его потом перепишут?

                  Он, конечно, может, но если что — деопт случится. В в худшем случае — деопт шторм. И да, это беда.


                  1. Saffron
                    26.09.2016 18:30

                    А представляете как хорошо было бы без деоптов? Там и до AOT уже не далеко.


                    1. sunless
                      26.09.2016 20:05

                      Отлично представляю. Как раз про это есть в материале выше.


      1. Throwable
        23.09.2016 09:28

        Пункт 2 порождает глобальные проблемы в совместимости.


        Во-первых, это должно нарушить работу кучи библиотек и API. Пример:


        JAXBContext jc = JAXBContext.newInstance("com.acme.foo");
        

        JAXBContext лежит модуле в java.xml.bind, но доменные классы в com.acme.foo. То есть классы из com.acme.foo должны быть доступны модулю java.xml.bind, даже если он не импортирует модуль com.acme.foo.


        Во-вторых, не позволяет простым способом "патчить" сторонние библиотеки, просто переписав класс в том же пакете. Не понятно, возможен ли будет по желанию "полный" импорт библиотеки со всеми ее приватными классами.


        В-третьих, ни слова об экспортировании ресурсов: ClassLoader.getResource(). Если ресурсы доступны только текущему модулю, то это сломает огромное количество библиотек, в том числе java.util.ServiceLoader. Кстати, тему сервисов jigsaw вообще обходит стороной, тогда как в OSGi это центральная фишка.


        Ну и в-четвертых, приватные классы модулей могут вылезать наружу как содержимое других объектов. Самый простой пример: exception chain, который в getCause() будет содержать внутренний эксепшн модуля или его транзитивных зависимостей. Как будет контролироваться доступ к этим классам — не понятно.


        Вобщем, вопросов много, а вразумительных ответов по тому как работает модульность в jigsaw нет.


        1. pjBooms
          23.09.2016 10:26
          +1

          Пункт 2 порождает глобальные проблемы в совместимости.

          А вы думаете почему проект Jigsaw делают 10 лет и опять отложили на июль? Конечно не все так просто.

          Во-первых, это должно нарушить работу кучи библиотек и API

          Все публичные API Java платформы, обязаны работать как прежде. В частности тот же самый JAXB. Как они этого добились — отдельный вопрос на изучение, не внекал. Сторонние API, могут пострадать и конечно страдают. Особенно, если они затачивались на что-то, что не гарантируется и никогда не гарантировалось Java платформой. sun.misc.Unsafe сообщество отстояло, но заточки могут самые разнообразные. Тот же Javassist, к примеру, все еще переводят на Java 9 (был хороший твит по этому поводу не давно).

          В-третьих, ни слова об экспортировании ресурсов: ClassLoader.getResource()

          Это можно легко поизучать. Я думаю, что с ресурсами должно быть так же. Если ресурс лежит в экспортируемом пакете — то он доступен, иначе нет.

          Кстати, тему сервисов jigsaw вообще обходит стороной,

          Нет, не обходит — http://openjdk.java.net/projects/jigsaw/spec/sotms/#services

          Ну и в-четвертых, приватные классы модулей могут вылезать наружу как содержимое других объектов.

          Разумеется к вам в код может прийти любой объект, в том числе принадлежащий классу, доступа к которому у вас нет. Но доступ к формальному типу этого объекта у вас есть (предку) соответсвенно вы спокойно можете общаться с ним как представителем класса, доступ к которому у вас есть. С тем же getCause() вы можете работать как с Throwable, даже если реальный класс вам не доступен. Но позвать какой-то метод не существующий в Throwable от него уже не сможете.


        1. sunless
          23.09.2016 12:40
          +2

          В-третьих, ни слова об экспортировании ресурсов: ClassLoader.getResource()

          Лучшее, что я нешел по теме — это саммари Марка


          В частности:


          • All existing resource-lookup methods in Class and ClassLoader work as
            they do today for resources on the class path.


          • The new java.lang.reflect.Module::getResourceAsStream method can be
            used to read the resources of any named module, without restriction.

          Ну и в-четвертых, приватные классы модулей могут вылезать наружу как содержимое других объектов

          Я, наверное, сейчас полную глупость скажу, но как это отличается от ситуации, когда мы из некого метода возвращаем объект фактического типа приватного подкласса, отнаследованного от публичного класса? Мы можем работать с этим объектом, мы вот только с приватным классом работать не можем.
          Я вижу, что вы это пример на хабре приводили еще год назад, наверное что-то не понимаю.


  1. pjBooms
    24.09.2016 19:43

    JAXBContext лежит модуле в java.xml.bind, но доменные классы в com.acme.foo. То есть классы из com.acme.foo должны быть доступны модулю java.xml.bind, даже если он не импортирует модуль com.acme.foo.

    Здесь рассказываеется как это работает. Сухой остаток: все что модуль экспортирует доступно по reflection кому-угодно. Соответственно, чтобы JAXB работал вам нужно экспортировать свои доменные классы из модуля. Ну а так как Unnamed Module (все что в classpath) экспортирует все, то все что работает сейчас будет работать на Java 9.

    Во-вторых, не позволяет простым способом «патчить» сторонние библиотеки, просто переписав класс в том же пакете. Не понятно, возможен ли будет по желанию «полный» импорт библиотеки со всеми ее приватными классами.

    Для всего этого есть «старый добрый» classpath. Можете в нем «патчтить» все что угодно, и доступаться до чего угодно. Только опять же все это тоже должно лежать в classpath. Полная анархия и хаос как раньше.