Comments 75
Под модульностью понимают контейнеры с кодом и ресурсами, причем из таких модулей будут состоять не только приложения, но и сами JRE/JDK. Что это даёт:
- Вы можете собрать образ (runtime image) типа приложение+JRE только с теми модулями из JRE, которые использует ваше приложение. Это сильно уменьшает размер пакета с самодостаточным приложением (если конечно не все модули использованы)
- Более строгие отношения между модулями. Первое, что бросается в глаза — требование открывать пакеты модулям, так как по умолчанию они не видны (из под полноценной модульной системы). Это значит, что можно делать интернал апи публичным в рамках модуля, раскидать его по разным пакетам и не переживать, что кто-то его начнёт использовать — компилятор рукам за такое даст.
- Может что-то ещё упустил..
Hello World занял 22 мегабайта. Hello World с Java FX буть больше сорока
Лично я так и не получил толкового ответа на то "зачем мне jigsaw". Jar-hell проблему она так и не решает, а вывод докладчик "ваш код станет строже" не убеждает — для этого модули девятки не нужны.
Насколько я понимаю, проект Jigsaw никогда не претендовал решать проблему Jar-hell в вашем проекте. В лучшем случае это еще один инструмент, но не готовое решение — да и с какой бы стати?
Одним из источников Jar-hell, к примеру, является использование зависимостей, взятых черти где — скачанных с непонятных сайтов, без явно указанных версий, короче — разработка без использования maven/gradle/etc для управления зависимостями. И это лечится только правильной постановкой работы в своем проекте. С другими типами проблем чуть иначе — но вывод примерно тот же.
Неверно. Именно о решение проблемы Jar hell, версионировании модулей и о разделении rt.jar на самостоятельные части говорили как о планах на Java 7. Это был 2009 год, Sun Tech Days в Питере.
Maven и Gradle эту проблему не решают. Потому что у вас в проекте может быть явно указана библиотека и она же, но другой версии, попадает через транзитивные зависимости от других библиотек.
Как вы себе сегодня представляете решение проблемы в своем проекте при помощи модуляризации JRE и разбиения rt.jar? Ну т.е. у вас две версии одной библиотеки, которые притащил maven (или вы их притащили вручную, как я выше описывал). Зато у вас rt.jar модульный. И какая связь?
ошибка компиляции, в проекте не должно быть библиотек разных версий.
А можно показать пальцем, с какой стати и где 9-ка выдаст вам такую ошибку компиляции? Насколько я помню, версионирование и контроль версий поддерживаются для модулей, а не для jar, а во-вторых, возможность контроля на предмет только одной поддерживаемой версии одного модуля обсуждалась, и однозначного ответа, как оно в итоге будет, я лично не видел (ну т.е. были разговоры, что можно успешно получить module hell вместо jar hell).
Ну и если у вас существующий проект — то модулей в нем само собой нет, а чтобы они были — надо рефакторить. Так что в итоге все равно получается, что это не решение, а лишь инструмент, еще один.
У меня допустим в OSGI никакого jar hell в обычном смысле и не было никогда. В проекте не только можно, но и реально имеется несколько версий одного и того же, и все это работает, при одном простом условии — что вы пропишете у себя, какие именно версии зависимостей где нужны. А попросту говоря — наведете в зависимостях порядок. И да, OSGI контейнер ругнется в определенный момент, если не сможет однозначно разрешить зависимости какого-то бандла. Но опять же — это не решение, это инструмент. Оно само ничего не сделает. Оно только помогает порядок наводить.
А можно показать пальцем, с какой стати и где 9-ка выдаст вам такую ошибку компиляции?
Перечитайте свой вопрос выше, вы спрашивали не о том как есть в java 9, а как на мой взгляд должна решаться проблема с одной и той же библиотекой в classpath разных версий.
Вы же сами писали ранее:
Насколько я понимаю, проект Jigsaw никогда не претендовал решать проблему Jar-hell
именно на это я высказал возражение, что нет, такая задача стаяла. Я лично присутствовал на докладе где об этом говорили (на обычной конференции). Jigsaw ставил несколько задач и Jar hell, и разбиение rt.jar были одними из пунктов. Jar hell вычеркнули.
А можно показать пальцем, с какой стати и где 9-ка выдаст вам такую ошибку компиляции?
Будет ошибка компиляции об использовании пакета, открытого в двух модулях.
И да, OSGI контейнер ругнется в определенный момент
Определённый момент это в рантайме? А 9-ка может ругнуться во время компиляции.
Пардон, откуда у вас в существующем проекте возьмутся модули?
9-ка может ругнуться во время компиляции.
Я это понимаю. И в общем-то, это пожалуй единственная серьезная разница между подходами. Но дело в том, что проблема может возникнуть и в райнтайме, ничего этому не мешает по большому счету.
Кроме того, я лично не знаю ответа на вопрос, что будет, если два модуля захотят две разные версии зависимости. На мой взгляд, это вполне возможная ситуация (модули могут быть написаны разными людьми или командами).
Ну т.е. ругнется, при компиляции, это хорошо, тут вряд ли стоит спорить. Но решение-то в чем будет состоять? Все равно кто-то должен будет понять, зачем и кому нужны две разные версии, и как их свести к одной. Это будет чисто человеческое, и возможно нетривиальное решение.
Пардон, откуда у вас в существующем проекте возьмутся модули?
В 9-ке теперь всё в модулях как ни крути, даже ваш class-path.
Кроме того, я лично не знаю ответа на вопрос, что будет, если два модуля захотят две разные версии зависимости
Подробно описал эту проблему в своей единственной статье, можете почитать :)
Но решение-то в чем будет состоять?
Если проект с нуля — правильно строим иерархию модулей, если существующий — автоматические модули в руки с доступом в class-path и постепенный рефакторинг в полноценные модули.
Так об этом и речь. Если нужен рефакторинг, то это инструмент, а не решение.
Ну и кстати, судя по вашей статье, вы не видели нормального OSGI. Felix и Equinox — это низкий уровень, на самом деле надо начинать скажем с Karaf. Тогда никаких проблем входа возможно не будет, а решение вы получите просто и штатно.
Про OSGi я теперь думаю только «упаси боже связаться», как и с такой проблемой в принципе.
Ну и зря. Вот прикиньте — система из порядка 100 модулей, сделанных разными людьми. Зависимости — какие попало, т.е. никто об этом не думает. Все это устанавливается в Karaf (в виде Jboss Fuse, но это не важно), и работает. Так что то что Оракл считает решением, уже много лет существует, и успешно используется, именно в виде OSGI.
Лично у меня ушло где-то с месяц на то, чтобы начать полноценно работать, и это совсем немного. При этом в сравнении например со Spring, то что есть в OSGI (Spring DM либо Blueprint) — это по сути тоже самое, когда поймешь простую вещь — что зависимости, которые в Spring статические, тут могут быть динамическими, появляться и пропадать, и работать с этим надо немного иначе.
К тому же, целью не было убийство OSGi. Все его юзают и получают профит, а в джаве до сих пор правят монолитный код? Разработчикам тоже хочется упростить себе разработку и поддержку самой платформы.
Поймите меня правильно, я вовсе не против Jigsaw. Я лишь говорил о том, что другими средствами это же самое давно делается. И скажем так — примерно также, т.е. по сути, что такое бандл в терминах OSGI? Это обычный jar, у которого а) прописана версия, обязательно б) прописаны импорты и экспорты, и возможно тоже с версиями. Ну т.е. это все — так или иначе модули, с версионированием.
Я лишь говорил о том, что другими средствами это же самое давно делается
Вы снова упускаете модуляризацию платформы из виду. Вы говорите о средствах для приложений, а что предложите для самой платформы?
Если поставить модуляризацию платформы во главу, то тоже самое неизбежно произойдёт и с рантаймом как следствие. Да, возможно это reinvent the wheel, но, имхо, это не должно быть поводом бить на модули только саму платформу (да и как бы это выглядело).
Суть моих возражений в том, что это не называется "решать". Это не более чем инструмент диагностики ее наличия. И если это вынести на этам компиляции — то в сущности мало что изменится.
Вот смотрите, есть apache commons lang, и она живет в версиях 2 и 3. И никаких ровным счетом проблем при этом не доставляет — потому что авторы это отработали, и назвали пакеты lang и lang3. Даже в одном классе можете использовать, удобств не будет, но работать работает.
А теперь представим, что у вас наоборот, есть две версии jar, где пакеты, классы и сигнатуры методов одинаковые, а логика методов например разная. И тут-то у нас проблема в полный рост...
Вы никогда не видели системы, которую делают скажем 50 человек? Да, разрастается, и да непонимание. Это нормальное состояние для работы, где задействованы несколько разных команд.
И тем не менее, изоляция каждого из модулей (что бы под этим не понимали) в отдельном класслоадере, и возможность для каждого модуля использовать свой набор зависимостей — это вполне себе решение.
Я бы даже сказал, что это проверенное промышленное решение — потому что мы это можем, уже давно. В JavaEE так можно, в OSGI все примерно так же. Если бы это было не так, вы вряд ли смогли бы например задеплоить в один JavaEE коннейнер два сервлета, один 2.x, а второй 3.x — и тем не менее, это не только можно, но и вполне себе используется налево и направо.
Единственное обязательное ограничение — чтобы эти разные версии зависимостей не торчали наружу из модулей.
Вы никогда не видели системы, которую делают скажем 50 человек?
На этом сайте немало людей работают и в бОльших компаниях/проектах. Для обоснования своей позиции не стоит использовать подобные пассажи.
По теме: если система доросла до того, что разные её части начали строго требовать разных зависимостей, то это знак того, что давно пора решать уже архитектурные проблемы. Как вариант: используйте микросервисы.
Про проблемы OSGi очень доходчиво было рассказано Никитой Липских. Он, кстати, есть на хабре — pjBooms
Не зря современные тенденции — использовать разные процессы (причем, иногда и с разными нативными зависимостями, как в docker) и объединять всё уже на уровне локального Nginx сервера. Ведь подобного рода разделение по процессам работает на уровне ОС без каких-то хаках в Java/.Net/и т.д.
По теме: если система доросла до того, что разные её части начали строго требовать разных зависимостей, то это знак того, что давно пора решать уже архитектурные проблемы. Как вариант: используйте микросервисы.
А вот прикиньте — нет у нас этих архитектурных проблем. От слова совсем. Порядка сотни модулей, в четырех OSGI контейнерах. В кластере. И наличие разных зависимостей при этом не создает вообще никаких проблем. Совсем никаких.
Не зря современные тенденции
Ну да, ну да. Хаков на уровне ОС не меньше, а значительно больше, чем в Java.
А вам никто не мешает это делать практически в любой версии Java. Заводите два classloader, в одном используете одну версию, в другом — другую. Даже если пакеты и классы идентичны по названиям — это все равно работает. Вопрос немножко в другом — чтобы сделать это контроллируемо и удобно. Впрочем, OSGI это вполне удобно позволяет делать тоже.
P.S. Сорри, вон там ниже уже ответили ровно это же.
По большому счету, если это compile зависимость — то извините, но вы не можете скомпилировать с двумя ее версиями. Поэтому вторую версию и выкинут. А класслоадер — это рантайм, и сейчас проблема решается только там. Технически два толстых war в одной JVM — это и есть ровно то, чего вы хотите, потому что вы не указали сразу, что JavaEE вам не хочется :)
И что значит не используется? Это везде в JavaEE и OSGI. Этого полно. Это и есть из коробки — но это не значит, что это дается даром. Нужно уметь, но технических проблем тут нет никаких.
Насколько я понимаю, проект Jigsaw никогда не претендовал решать проблему Jar-hell в вашем проекте.
Jigsaw постоянно сравнивают с OSGi, которая тоже претендует на решение именно этой проблемы (но не решает ее).
Одним из источников Jar-hell, к примеру, является использование зависимостей, взятых черти где — скачанных с непонятных сайтов, без явно указанных версий, короче — разработка без использования maven/gradle/etc для управления зависимостями.
Нет, вы не правы. Jar-hell возникает, когда две вполне легальные библиотеки, взятые из maven-central, используют разные версии третьей библиотеки, не поддерживающей обратную совместимость, что встречается сплошь и рядом.
Нет, вы не правы.
Это вам кажется. Сходите в гугль, например, и убедитесь, что в первых же пяти ссылках на эти ключевые слова будет пять разных формулировок проблемы jar hell.
Суть на самом деле очень проста: если у вас нет нормального управления зависимостями, в вашем classpath могут появиться две разные версии одного и того же класса, и класслоадер загрузит ту из них, которая попадется ему первой, а не ту, которую вы ожидали. И транзитивные зависимости — лишь одна из многих причин, почему это бывает.
И кстати, OSGI ее таки решает. В моей практике (3.5 года немаленького проекта) я не могу вспомнить симптомов jar hell на ровном месте.
И даже если допустить, что они бывают — то во всяком случае, инструменты для решения имеются вполне адекватные. Во-первых, в classpath не попадает ничего из неизвестных источников, источник классов — только экспорт из бандлов, а экспорт из бандлов — это то, что прописано как экспортируемое.
Во-вторых, если контейнер не смог однозначно заресолвить какие-то пакеты — то он по крайней мере это четко диагностирует. До того, как мы словим ClassCastException.
И кстати, OSGI ее таки решает. В моей практике (3.5 года немаленького проекта) я не могу вспомнить симптомов jar hell на ровном месте.
Уверен, вы найдете тут массу народа, который и без всякого OSGi в не маленьких проектах jar-hell не встречает :) Потому что бороться с ним и его симптомами можно многими средствами, от усиленного контроля того, что используется в проекте и до распиливания проекта на микросервисы.
О том, что OSGi проблему не решает четко сказано в том самом докладе о котором речь идет в сабже, если мне не изменяет склероз, то примерно такими словами: «проблему не решает, просто переносит ее на другой уровень». Возможно докладчик не прав, тут сказать ничего не могу.
Не, тут все проще. Да, переносит, на такой уровень, где с ней удобнее бороться. По-большому счету это все что нужно.
А решить… ну я вот с удовольствием послушаю, как предлагается радикально раз и навсегда решить проблему, КРОМЕ КАК порезав приложение на части.
Одним из источников Jar-hell, к примеру, является использование зависимостей, взятых черти где — скачанных с непонятных сайтов, без явно указанных версий, короче — разработка без использования maven/gradle/etc для управления зависимостями.
Чего? С каких это пор внедрение maven магически избавляет от jar-hell. Обычно наоборот.
Вы невнимательно прочитали. Тут написано, что работа без средств управления зависимостями это плохо. И моя практика показывает, что это почти всегда так — в руках джуниора такой проект скатывается в говно даже при одной зависмости, когда о конфликтах еще и речи нет.
А вывод который вы делаете, что со средствами управлнения все шоколадно, тут не подразумевался. maven как и gradle не обещали, а тем более магически, полностью избавить от проблем управления зависимостями.
Обычно наоборот.
Опять же — maven или gradle это лишь инструмент. И в неумелых руках они могут творить любые чудеса, отформатировать диск, развязать мировую войну, и так далее. Может у вас они усиливают jar hell на порядок, я не знаю, вполне могу поверить.
Но лично в моей практике, maven с включенным enforcer plugin, в режиме dependency convergence, плюс пара отчетов dependency:tree и dependency:analyze практически на 100% диагностирует проблему дублирования транзитивных зависимостей. А дальше, пардон, в большинстве случаев требуется только применение головы, потому что никакой инструмент за вас не сможет корректно выбрать между двумя разными версиями одной транзитивной зависимости.
Если вы такой инструмент можете назвать — я с удовольствием послушаю.
И в неумелых руках они могут творить любые чудеса, отформатировать диск, развязать мировую войну, и так далее. Может у вас они усиливают jar hell на порядок, я не знаю, вполне могу поверить.
Пример такого усиления любой проект на apache.org. Это просто помойка с кодом, но помойка популярная, ибо BigData. Фактически любой антипатерн, который можно вообразить там есть.
Фактически беда не в самом Maven, а в привычке скачивать полинтернета, чтоб написать Hello World. И в таких условиях maven пасует, не помогая толком работать с действительно большими и сложными проектами.
Хм. Я не работаю на apache.org. Но по опыту знаю, что сегодня у меня 300-500 зависимостей в проекте — норма жизни. Не в смысле, что так надо, а в смысле, что это никаких проблем не вызывает. Подозреваю, что до 1000 можно довести без проблем. И опять же — мавен не решает этой проблемы. Его задача — именно скачать то, что попросили, и проверить, что зависимость А не встречается в двух версиях. Этого вполне достаточно.
Я не знаю, о каких по размеру вы проектах говорите, но реально бОльшие просто надо однозначно дробить, чтобы не иметь дела с тысячами зависимостей вообще. И тут уже как-бы дело уже не столько в мавене — все равно инструмент это за вас не сделает.
В час всё не уложишь, поэтому цель только зацепить, чтобы слушатель пошёл дальше и изучил тему подробнее в сети.
Про "зачем" можно см. комментарий выше, по поводу jar-hell: его частично решили модулями, но чтобы всё это заработало, нужно потанцевать с бубном
Над оператором Элвиса в девятке конечно поиздевались.
Java 9 что ты делаешь прекрати #jokerconf pic.twitter.com/CCcY7OBw15
— Txt Mo (@textmore) November 3, 2017
Оператор от подобной функции будет отличаться тем, что если default_value — на самом деле какое‐то вычисляемое выражение, то оно вычисляться не будет. Судя по картинке выше, называть новые функции «оператором Элвиса» неверно (иначе зачем существует Get версия?), но когда я прочитал про это в статье, то очень удивился: оператор, выглядящий как функция — разработчики Java совсем с ума сошли?
литералы в коллекциях можно использовать с 7 версии
List<Integer> list = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 9];
Set<Integer> set = { 2, 7, 31, 127, 8191, 131071, 524287 };
Я не могу так сделать даже в Java 8, откуда вы это взяли?
2. Внедрение оператора Элвиса — вообще обман, вместо оператора Элвиса с ленивыми вычислениями, дали ту функцию, что любой написать может, лучше уж ничего, теперь будут говорить что мы дали вам почти оператор Элвиса,
9. Самая главная новость — ерунда :),
6. Обработка процессов — специфично, но возможно полезно,
5. IO, Regrexp — readAllBytes и transferTo? Полезно, конечно, но чтож очевидные вещи так долго до продакшена доходят?
3. Class Optional + 4. Streams — самый полезные из всех фич в статье и толком не описанные (особенно Streams)
7. Немного синтаксических изменений — НОООО! За что?! Приватные методы в интерфейсах? Вы серьезно? Завтра вы еще поля с конструктором туда добавите и возможность создавать инстанс интерфейса? Это называется изуродовали ООП в Java как бог черепаху. Золотую малину за такую фичу надо выдавать.
Следите за моими руками — как можно это реализовать даже на версии до 8
public interface SomeInterface {
void exe();
class Default implements SomeInterface {
private Default(){}
@Override
public void exe() {
System.out.println("Default interface implementation");
}
public static SomeInterface getInstance() {
return new Default();
}
}
}
// ... где-то в другом месте
SomeInterface someInterfaceImpl = SomeInterface.Default.getInstance();
someInterfaceImpl.exe();
Полиморфизм создает проблему при множественном наследовании, поэтому можно наследоваться только от одного класса, но реализовывать множество интерфейсов.
Вы зря переживаете :)
Полиморфизм создает проблему при множественном наследовании, поэтому можно наследоваться только от одного класса, но реализовывать множество интерфейсов.
Ну как решается проблема множественного наследования дефолтных методов? Явным указанием какие методы будут использоваться, это очень похоже на то как решается эта проблема для классов других языков.
Объясните какую проблему решают дефолтные методы и приватные методы в интерфейсах, которые невозможно было решить способами 1-7 Java? Очень похоже на попытку протащить множественное наследование в Java.
Ну да. Все что нужно для Элвиса — это ленивость. Ленивость в виде лямбд сделали в прошлом релизе, а без них — можно было всегда, только очень многословно. Мораль — 2. синтаксическая плюшка, даже меньше, потому что синтаксиса как раз и не сделали.
9. Самая главная новость — ерунда :)
А это как посмотреть. Я вот чувствую сколько прод решений отъедет из-за этого :)
Теперь этот код вернет значение «9», а не «1.9.0.».
Ошибочка. «9» возвращала бета-версия, для официальных релизов теперь возвращается в формате «9.0.1».
Ещё Вы забыли упомянуть, что теперь нет официальной 32-битной версии (под Windows), только 64-битные.
Обзор Java 9