Однажды на Joker мы собрали BOF под названием "Java EE vs Spring". Дуэль была оформлена по всем правилам, сообщество Spring пришло в полном составе... а вот второй дуэлянт предпочел не появиться. Точней, Java EE была представлена одним-единственным оракловским евангелистом с французской фамилией. Даже понятно, почему так произошло. Несмотря на то, что пользователей Java EE куча, это не та аудитория, которая измеряет свой успех в количестве вышедших за последнюю неделю пре-альфа-версий и настроена на серьезных щах обсуждать такие темы.
Получается, у нас есть куча каких-то фреймворков, которые есть, которые на хайпе, но кто их использует и как их увидеть вживую? Quarkus, Micronaut, Helidon, вся эта тема со сборкой через Native Image. Кого ни спроси — у всех или Spring Boot, или Java EE, которая даже еще не Jakarta. И вот, выходит свежий Helidon, а на нем на Хабре даже пока не написали, как будто это шутка какая-то. А ведь там исправили больше двух сотен тикетов на Гитхабе. Держите пруфы:
Те, кто использует Helidon в проде, наверняка точно знают, зачем им это нужно. Что делать остальным? Основная задача хомячка — объяснить детям концепцию смерти. Кажется, точно так же, основная задача Helidon для широких народных масс — посмотреть на самые новые фишки Java и понять, нужно вам это или нет.
Что не так со Spring?
Огромное сообщество и экосистема сделали Spring и Spring Boot выбором по-умолчанию. Напиши код, обмажь магическими аннотациями — и дальше Spring сделает всё по красоте, твое приложение почему-то запустится и будет достаточно хорошо работать.
Эти же преимущества одновременно можно считать проблемами. Огромное сообщество ежедневно рождает новые версии каких-то библиотек, хорошо проверить работоспособность и совместимость между которыми - адский труд. Каждую неделю уходят поезда, направление движения которых изестно только тем, кто тратит на их отслеживание кучу времени (большинство этой ерундой не занимаются). У Spring Boot есть проблемы совместимости даже с Hibernate. А вот тут, кстати, вышла свежая Spring Statemachine 4.0.0-M1 - успехов понять, стоит ли это вообще даже тестировать.
Тонны магии на аннотациях очень сложно отлаживать. Не редки ситуации, когда у разработчика залогирована неделя на то, что он нажимает F8 в отладчике, в тщетных попоытках понять, почему одна какая-то фигня не работает с другой. Просто понять, какие аннотации имеются, и как их использовать совместно — это достойная задачаю. Кроме того, магия аннотаций не всегда самая быстрая штука. Конечно, самая частая проблема с медленным стартом приложений — это накатывание миграций и иниациализация хибернейтов, и на фоне этого ужаса тормоза приложения видны не сразу. Но стоит только копнуть внутрь, как это работает, становится страшно. (Если вы помните, когда-то, когда деревья были выше, Женя Борисов хорошо взлетел на этом с докладами серии Spring-потрошитель).
Как всегда в таких случаях, предлагается сделать ультра-простой фреймворк, который будет лишен ненужной сложности. По той же причине на нем можно будет тестировать все новые ништяки (типа виртуальных тредов и GraalVM Native Image) без угрозы что-нибудь сломать. В данном случае, таким фреймворком является Helidon, а тестирует новые модные игрушки на нем не какой-то нунейм из сообщества, а целая корпорация Oracle. И версия у него 4.0.0, что намекает, что на нем можно попытаться писать в продакшен.
SE vs MP
Если зайти на первую страницу документации, то первое, что привлекает внимание — она делится на два раздела, SE и MP.
Это два варианта поставки. Helidon SE — это облачный микрофреймворк, идеалогия которого в минимизации магии. С целью ультра-производительности, упрощения отладки и тестирования новых ништяков. Helidon MP отвечает за Microprofile.
Код на Helidon SE:
Routing routing = Routing.builder()
.get("/hello",
(req, res) -> res.send("Hello World"))
.build();
WebServer.create(routing)
.start();
Как видим, Helidon SE вам нужен, если хочется выжать весь перформанс по максимуму, и вы готовы пожертвовать для этого фреймворками для dependency injection и прочей магией.
Код на Helidon MP выглядит более привычно глазу пользователя Spring Boot:
@Path("hello")
public class HelloWorld {
@GET
public String hello() {
return "Hello World";
}
}
Если вы вдруг не использовали Microprofile, и вероятно, не планируете — пара слов, что это такое. Проект MicroProfile начался в 2016 году, когда Oracle решили окончательно закопать передать в сообщество Java EE. Несколько компаний (включая IBM и RedHat) собрались и вместе запилили некую работающую реализацию подмножества фичей EE, на которых можно было продолжать пилить веб-сервисы.
С тех пор многое произошло - в том числе, и Jakarta, и MicroProfile, отправились развиваться в Eclipse. Как все это будет дальше развиваться — неясно, учитывая что в мире Jakarta больше нет проблемы, с которой они боролись во времена Оракла - тормоза в развитии. Последний блог-пост с виженом в блоге Себастиана Дашнера по этому поводу — за 2019 год, с тех пор прошла вся жизнь. Если кто-то знает актуальное (совсем актуальное) состояние вопроса — пожалуйста, расскажите в комментариях!
Возвращаясь к Helidon, у нас есть маленькая удобная реализация Microprofile. Она всего на десяток мегабайт больше, чем SE версия Helidon, и позволяет писать с использованием привычной парадигмы, с использованием внедрения зависимостей и стандартов типа CDI, JAX-RS, JSON-P, JSON-B, итп.
В свежей версии Helidon 4.0.0 появилась возможность использовать новинки из MicroProfile 6.0. А что это такое, лучше почитать на их официальном сайте: https://microprofile.io.
Переобуваемся в Virtual Threads
На протяжении развития Helidon, разработчики строили его SE реализацию поверх асинхронного API. Рассказывали, как это круто и замечательно, и всё теперь точно будет работать быстро. Но выход Java 21 и виртуальных тредов заставил их резко переобуться.
В секретных лабораториях Оракла некоторое время назад начал вариться веб-сервер Nima, который изначально создан для работы с виртуальными тредами. Только с ними — без них он просто не заработает. И вот, в Helidon 4.0.0, Netty с асинхронщиной были выброшены на свалку истории и заменены на эту свежую реализацию. Теперь всё это назвается просто Helidon Web Server, слово Nima в суе не используется.
Одно из самых крутых (но не заметных глазу прикладного разработчика) эффектов такого перехода в том, что код на виртуальных тредах выглядит на порядки проще, чем асинхронщина. Значит, код современного Helidon стал намного более простым, понятным и поддерживаемым, что в будуем сэкономит массу головной боли его пользователям на продакшене.
Каждый новый запрос обслуживается в отдельном виртуальном треде. Это позволяет выдерживать нагрузку, кратно большую, чем предыдущие реализации. Так как внутри Helidon MP основан на том же самом SE, всё это привело к интересному эффекту: наибольшую выгоду от использования виртуальных тредов мы получаем именно в MP, что видно на графике.
Если интересно погрузиться в тему, то Митя Александров какое-то время назад написал статью про сравнение Helidon 4 со свежим Spring Boot и вложил тестовый скрипт на GitHub.
Графики внушают уважение!
Время до первого ответа:
Использование оперативной памяти:
Количество бессмысленной траты дисков на зависимости:
Выводы
Похоже, если бы не готовая экосистема Spring Boot, Helidon мог бы потягаться за звание лучшего фреймворка для микросервисов. Он очень новый, построенный с нуля на самых свежих технологиях, очень хорошо оптимизированный. И разрабатывается большой, уважаемой компанией.
Но даже если вы никогда не планировали использовать Helidon, его успехи - это показатель того, какие можно получить преимущества от использования свежей Java 21, в особенности — виртуальных потоков. Ждем, когда Spring Boot и его интеграцию с Virtual Threads отполируют до такого же зеркального блеска, как это сделано в Helidon!
Кстати, в России у нас есть специальный российский дистриубтив Java: Axiom JDK. Недавно вышла свежая версия Axiom JDK с поддержкой Java 21. Если вы используете Аксиому, попробуйте запустить на ней Helidon и поделитесь результатами!
Подписывайтесь на два моих Telegram-канала:
⇛ Javawatch. Анонсы по Java: новости, митапы.
⇛ Откровения от Олега. Личный канал + чат практически без цензуры, где можно встретить ребят типа Баруха и всё это обсудить.
Комментарии (7)
arkaev
09.11.2023 05:09+2Вообще не понимаю, почему вдруг DI стал проблемой, когда есть annotation processors на этапе компиляции. Micronaut тому пример
sergey-gornostaev
09.11.2023 05:09+2Проблема не в DI, а в том, что в большинстве java-фреймворков, и в частности в Spring, почти всё делается с помощью рефлексии и прокси-объектов. Микронавт - редкое исключение, но и он опирается на пока не стандартизированный Java Compiler API, что несколько настораживает.
Shatun
09.11.2023 05:09+1Проблема не в DI, а в том, что в большинстве java-фреймворков, и в частности в Spring, почти всё делается с помощью рефлексии и прокси-объектов
Большинство это видимо спринг и ныне живущие больше в виде легаси apllication serverа со своим DI?
По-моему за пределами спринга большинство популярных DI уже живут в compile time-микровант, кваркус, даггерHivemaster
09.11.2023 05:09+2Упомянутый в статье microprofile - это CDI с рефлексией. Dagger стоит сравнивать с Guice по частоте и области применения, окажется, что первый применяют в основном в Android, где на рефлексию не хватает ресурсов. Аналогично стоит сравнивать долю рынка кваркуса и микронавта со спрингом, разрыв впечатляет. У Java печально мало работы происходит во время компиляции по сравнению даже с другими языками на той же платформе, не говоря уж о каком-нибудь там Rust.
Shatun
09.11.2023 05:09+1Упомянутый в статье microprofile - это CDI с рефлексией
Как раз для этого был выпущен CDI lite, который легко реализуется без рефлексии.
Dagger стоит сравнивать с Guice по частоте и области применения, окажется, что первый применяют в основном в Android, где на рефлексию не хватает ресурсов.
Ну например при использовании в авс лямбде даггер достаточно дефолтный DI на текущий момент. Я его как раз упоменул именно потому что периодически всетрчал в бэке за последние годы.
Аналогично стоит сравнивать долю рынка кваркуса и микронавта со спрингом, разрыв впечатляет
Да, спринг к сожалению слишком популярен.
У Java печально мало работы происходит во время компиляции по сравнению даже с другими языками на той же платформе, не говоря уж о каком-нибудь там Rust.
Да пожалуй нет, в джаве в целом нет с этим проблем, выше упомянутые кваркусы и микронавты тому пример. Проблемы у спринга, который очень популярен, но не у джавы в целом.
tessob
Выбор Спринга в большинстве проектов обусловлен развитой экосистемой, кучей обучающих материалов и компактным набором паттернов. Это вообще не про перфоманс ни разу, а про возможность нанять на проект 2-3 сотни одинаково посредственных разработчиков, которые в одинаковой манере пишут код. Просто, бизнес так устроен. Большая часть энтерпрайза — это унылые однотипные crud микросервисы, где 90% серверного времени сервис тупо ждёт сеть.
Те у кого есть возможность выбирать стек скорее возьмут Rust, чем очередной прорывной жаба-фреймворк.
trix
скорее антипаттернов. если бы спринг остался на уровне core DI framework, к нему было бы сильно меньше претензий :)) однако он оброс тонной библиотек повторяющих одни и те же плохие подходы и жестко завязанных на spring core, вместо развития творчества людей огромную часть индустрии перегнали из ящика j2ee в ящик спринга.