Одна идея, на которой я люблю делать акцент, это автобоксинг и анбоксинг в Java.
Java фактически дает нам два параллельных мира:
Примитивы: int, long, double = быстрые, компактные, живут на стеке.
Обертки: Integer, Long, Double = полноценные объекты в heap.
Между этими мирами Java делает одно автоматическое преобразование:
Автобоксинг - превращение примитива в объект
Анбоксинг - обратное преобразование
Работает удобно, пока в какой-то момент не начинает мешать.
Почему это может быть проблемой?
Потому что при каждой конверсии у Java появляется лишняя работа:
Создаются новые объекты
Увеличивается нагрузка на GC
CPU делает больше операций
Срываются JIT-оптимизации
В циклах с высокой нагрузкой появляются скрытые задержки
В большинстве приложений это незаметно, но если проявится, то обычно довольно резко.
Типичный пример - коллекции:
Очевидно, что пример синтетический, но суть в том, что в этом цикле i упаковывается в Integer миллион раз.
Перенеси этот сценарий на реальные участки твоего кода.
Каждая конверсия создает объект, нагружает GC и сбивает процессорный кеш.
Из-за этого приложение начинает подвисать, когда GC активируется.
Коллекции - не единственный источник проблем. Есть и сравнения:
При работе с обертками оператор == сравнивает ссылки, а не значения.
Если происходит неявный анбоксинг, оба значения сначала превращаются в int и только потом сравниваются.
Такое смешение поведения местами непредсказуемо и приводит к трудноуловимым багам.
Есть еще и лямбды:
Если работаете с числами, лучше брать примитивные стримы:
IntStream
LongStream
DoubleStream
Они экономят память, убирают боксинг и работают быстрее.
Худший сценарий - структуры подсчета:
Каждая операция делает:
Анбоксинг существующего значения
Сложение как примитива
Обратный автобоксинг результата
Масштабируется это плохо и убивает производительность при высокой конкуренции.
Хорошие варианты:
- AtomicInteger
- LongAdder
- Хранить счетчик как примитив и конвертировать только при выдаче наружу
Значит ли это, что обертки плохие? Нет.
Проблема не в них, а в случайном использовании.
Обертки используют, когда:
Нужны null-значения
API требует объектные типы
Есть доменная логика, где важна идентичность или отсутствие значения
Примитивы используют, когда:
Есть большие циклы
Много повторных вычислений
Важно избегать лишнего GC
Нужна стабильная производительность
Автобоксинг удобен, но у него есть подводные камни.
Обычно он не мешает, но когда все-таки мешает, его эффекты сложно отследить.
Хорошая новость: исправляется это просто.
Используй примитивы в вычислениях
Используй примитивные стримы
Не применяй обертки в счетчиках
Проверь циклы, создающие лишние объекты
Пара мелких правок может убрать тысячи лишних объектов и заметно снизить нагрузку на приложение.
👉 Java Portal
Java фактически дает нам два параллельных мира:
Примитивы: int, long, double = быстрые, компактные, живут на стеке.
Обертки: Integer, Long, Double = полноценные объекты в heap.
Между этими мирами Java делает одно автоматическое преобразование:
Автобоксинг - превращение примитива в объект
Анбоксинг - обратное преобразование
Работает удобно, пока в какой-то момент не начинает мешать.
Почему это может быть проблемой?
Потому что при каждой конверсии у Java появляется лишняя работа:
Создаются новые объекты
Увеличивается нагрузка на GC
CPU делает больше операций
Срываются JIT-оптимизации
В циклах с высокой нагрузкой появляются скрытые задержки
В большинстве приложений это незаметно, но если проявится, то обычно довольно резко.
Типичный пример - коллекции:
List<Integer> numeros = new ArrayList<>();
for (int i = 0; i < 1_000_000; i++) {
numeros.add(i);
}
Очевидно, что пример синтетический, но суть в том, что в этом цикле i упаковывается в Integer миллион раз.
Перенеси этот сценарий на реальные участки твоего кода.
Каждая конверсия создает объект, нагружает GC и сбивает процессорный кеш.
Из-за этого приложение начинает подвисать, когда GC активируется.
Коллекции - не единственный источник проблем. Есть и сравнения:
Integer a = 1000;
Integer b = 1000;
if (a == b) { ... }
При работе с обертками оператор == сравнивает ссылки, а не значения.
Если происходит неявный анбоксинг, оба значения сначала превращаются в int и только потом сравниваются.
Такое смешение поведения местами непредсказуемо и приводит к трудноуловимым багам.
Есть еще и лямбды:
Stream<Integer> s = IntStream.range(0, 1_000_000)
.boxed(); // миллион автобоксингов
Если работаете с числами, лучше брать примитивные стримы:
IntStream
LongStream
DoubleStream
Они экономят память, убирают боксинг и работают быстрее.
Худший сценарий - структуры подсчета:
Map<String, Integer> counter = new HashMap<>();
counter.put(key, counter.getOrDefault(key, 0) + 1);
Каждая операция делает:
Анбоксинг существующего значения
Сложение как примитива
Обратный автобоксинг результата
Масштабируется это плохо и убивает производительность при высокой конкуренции.
Хорошие варианты:
- AtomicInteger
- LongAdder
- Хранить счетчик как примитив и конвертировать только при выдаче наружу
Значит ли это, что обертки плохие? Нет.
Проблема не в них, а в случайном использовании.
Обертки используют, когда:
Нужны null-значения
API требует объектные типы
Есть доменная логика, где важна идентичность или отсутствие значения
Примитивы используют, когда:
Есть большие циклы
Много повторных вычислений
Важно избегать лишнего GC
Нужна стабильная производительность
Автобоксинг удобен, но у него есть подводные камни.
Обычно он не мешает, но когда все-таки мешает, его эффекты сложно отследить.
Хорошая новость: исправляется это просто.
Используй примитивы в вычислениях
Используй примитивные стримы
Не применяй обертки в счетчиках
Проверь циклы, создающие лишние объекты
Пара мелких правок может убрать тысячи лишних объектов и заметно снизить нагрузку на приложение.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍5🔥2
This media is not supported in your browser
VIEW IN TELEGRAM
Похоже, это претендент на TUI года ⭐️
gitlogue — инструмент для «кинематографичного» воспроизведения Git-коммитов прямо в терминале.
Смотри, как коммиты развертываются с анимацией ввода, подсветкой синтаксиса и живым обновлением дерева файлов.
Буквально наблюдай, как твой репозиторий пишет себя сам.
Написан на Rust
GitHub: https://github.com/unhappychoice/gitlogue
👉 Java Portal
gitlogue — инструмент для «кинематографичного» воспроизведения Git-коммитов прямо в терминале.
Смотри, как коммиты развертываются с анимацией ввода, подсветкой синтаксиса и живым обновлением дерева файлов.
Буквально наблюдай, как твой репозиторий пишет себя сам.
Написан на Rust
GitHub: https://github.com/unhappychoice/gitlogue
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8
Часто мы пишем
Но за этим стоит довольно сложная и интересная система , а именно ClassLoader’ы.
Именно они отвечают за то, чтобы находить, проверять и загружать каждый класс, который использует твоё приложение.
Без ClassLoader’ов нет JVM, нет Spring, нет плагинов, вообще ничего нет.
Что такое ClassLoader?
Это компонент JVM, который отвечает за:
- Поиск определения класса (файлы .class, JAR’ы, модули).
- Загрузку его в память.
- Проверку байткода на валидность и безопасность.
- Определение класса в изолированном пространстве.
Проще говоря, он превращает байткод в то, что JVM может исполнять.
Иерархия держит хаос под контролем
В Java используется модель делегирования вверх {parent delegation}
Это защищает от конфликтов, дублирования и неожиданных подмен классов.
Основные загрузчики:
- Bootstrap ClassLoader
Написан на C++, загружает базовые классы языка (java.lang.*, java.util.* и так далее).
Живёт прямо внутри JVM.
- Platform / Extension ClassLoader
Загружает библиотеки самого JDK и системные модули.
- Application ClassLoader
Загружает твои классы, зависимости и весь прикладной код.
Типичный поток загрузки выглядит так:
Когда ClassLoader пытается загрузить класс, он сначала делегирует запрос родителю.
Если родитель не находит класс, тогда уже текущий загрузчик пытается загрузить его сам.
Это не даёт тебе случайно переопределить String, List, Object и другие базовые классы.
Как загружается твой код?
Когда ты запускаешь JAR:
Твой код загружает Application ClassLoader. Процесс простой:
- Проходит по classpath
- Открывает JAR’ы
- Находит .class
- Загружает их по мере необходимости
Загрузка классов происходит по требованию.
Если у тебя 200 классов, а реально используются только 10, будут загружены только эти 10.
Почему это реально важно?
Потому что всё, что мы используем поверх Java, строит свою работу на ClassLoader’ах:
Spring Boot создаёт собственный ClassLoader для загрузки fat JAR’ов.
Модульные приложения используют загрузчики для изоляции компонентов.
Веб-контейнеры вроде Tomcat создают отдельный ClassLoader на каждое приложение.
Плагины (IDEA, Jenkins, Minecraft, OSGi) работают через отдельные загрузчики.
Инструменты hot reload (Spring DevTools, JRebel) зависят от динамической перезагрузки классов.
Зачем это понимать на практике?
Рано или поздно ты столкнёшься с ошибками вида
Самые частые проблемы:
ClassNotFoundException — класс отсутствует в classpath текущего загрузчика.
NoClassDefFoundError — класс был доступен, но возникла ошибка при загрузке или верификации.
“Невозможный” ClassCastException — объект вроде бы нужного типа, но Java считает иначе. Обычно это означает, что один и тот же класс был загружен разными ClassLoader’ами.
Memory leak в веб-приложениях — Tomcat некорректно выгружает ClassLoader при redeploy.
Последнее происходит значительно чаще, чем кажется.
ClassLoader’ы это как кровеносная система Java ( их не видно, но без них ничего не работает. )
Понимание того, как Java загружает классы это не пустая теория. Это делает тебя сильнее в отладке, увереннее при разборе сложных багов и даёт чёткое понимание среды, в которой реально работает твоё приложение.
И когда в продакшене что-то падает с
👉 Java Portal
public static void main и просто предполагаем, что Java сама «делает свою работу».Но за этим стоит довольно сложная и интересная система , а именно ClassLoader’ы.
Именно они отвечают за то, чтобы находить, проверять и загружать каждый класс, который использует твоё приложение.
Без ClassLoader’ов нет JVM, нет Spring, нет плагинов, вообще ничего нет.
Что такое ClassLoader?
Это компонент JVM, который отвечает за:
- Поиск определения класса (файлы .class, JAR’ы, модули).
- Загрузку его в память.
- Проверку байткода на валидность и безопасность.
- Определение класса в изолированном пространстве.
Проще говоря, он превращает байткод в то, что JVM может исполнять.
Иерархия держит хаос под контролем
В Java используется модель делегирования вверх {parent delegation}
Это защищает от конфликтов, дублирования и неожиданных подмен классов.
Основные загрузчики:
- Bootstrap ClassLoader
Написан на C++, загружает базовые классы языка (java.lang.*, java.util.* и так далее).
Живёт прямо внутри JVM.
- Platform / Extension ClassLoader
Загружает библиотеки самого JDK и системные модули.
- Application ClassLoader
Загружает твои классы, зависимости и весь прикладной код.
Типичный поток загрузки выглядит так:
Когда ClassLoader пытается загрузить класс, он сначала делегирует запрос родителю.
Если родитель не находит класс, тогда уже текущий загрузчик пытается загрузить его сам.
Это не даёт тебе случайно переопределить String, List, Object и другие базовые классы.
Как загружается твой код?
Когда ты запускаешь JAR:
java -jar app.jar
Твой код загружает Application ClassLoader. Процесс простой:
- Проходит по classpath
- Открывает JAR’ы
- Находит .class
- Загружает их по мере необходимости
Загрузка классов происходит по требованию.
Если у тебя 200 классов, а реально используются только 10, будут загружены только эти 10.
Почему это реально важно?
Потому что всё, что мы используем поверх Java, строит свою работу на ClassLoader’ах:
Spring Boot создаёт собственный ClassLoader для загрузки fat JAR’ов.
Модульные приложения используют загрузчики для изоляции компонентов.
Веб-контейнеры вроде Tomcat создают отдельный ClassLoader на каждое приложение.
Плагины (IDEA, Jenkins, Minecraft, OSGi) работают через отдельные загрузчики.
Инструменты hot reload (Spring DevTools, JRebel) зависят от динамической перезагрузки классов.
Зачем это понимать на практике?
Рано или поздно ты столкнёшься с ошибками вида
ClassNotFoundException. Понимание ClassLoader’ов даёт отличную точку старта для отладки.Самые частые проблемы:
ClassNotFoundException — класс отсутствует в classpath текущего загрузчика.
NoClassDefFoundError — класс был доступен, но возникла ошибка при загрузке или верификации.
“Невозможный” ClassCastException — объект вроде бы нужного типа, но Java считает иначе. Обычно это означает, что один и тот же класс был загружен разными ClassLoader’ами.
Memory leak в веб-приложениях — Tomcat некорректно выгружает ClassLoader при redeploy.
Последнее происходит значительно чаще, чем кажется.
ClassLoader’ы это как кровеносная система Java ( их не видно, но без них ничего не работает. )
Понимание того, как Java загружает классы это не пустая теория. Это делает тебя сильнее в отладке, увереннее при разборе сложных багов и даёт чёткое понимание среды, в которой реально работает твоё приложение.
И когда в продакшене что-то падает с
ClassNotFoundException, ты точно будешь рад, что разобрался в этом заранее.Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤9
This media is not supported in your browser
VIEW IN TELEGRAM
Учись разрабатывать API с нуля! 🤓
Этот ресурс бесплатный и включает:
✓ Пошаговый курс по REST API и GraphQL
✓ Как добавить безопасность в свои API
✓ Как монетизировать API
→ http://rapidapi.com/learn
👉 Java Portal
Этот ресурс бесплатный и включает:
✓ Пошаговый курс по REST API и GraphQL
✓ Как добавить безопасность в свои API
✓ Как монетизировать API
→ http://rapidapi.com/learn
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍2
Java-совет : вместо HashSet для enum-типов лучше использовать EnumSet. Он работает быстрее и потребляет меньше памяти.
👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18❤4
Статья на вечер: где автор сделал свой Spring Boot Starter для разработки Telegram-ботов на Java, чтобы больше не копипастить одни и те же настройки и логику.
Он обернул работу с java-telegram-bot-api в удобный фреймворк с маршрутизацией апдейтов, хендлерами, обработкой ошибок и простым подключением к Spring-приложению.
👉 Java Portal
Он обернул работу с java-telegram-bot-api в удобный фреймворк с маршрутизацией апдейтов, хендлерами, обработкой ошибок и простым подключением к Spring-приложению.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤13👍3
Совет по Java: возвращайте Collections.emptyList(), List.of() или Set.of() вместо null, чтобы не плодить проверки на null в вызывающем коде.
👉 Java Portal
// ❌ Нужен null-check:
public List<String> findUsers() {
if (!dataAvailable()) {
return null; // заставляет вызывающий код проверять на null
}
return loadUsers();
}
List<String> users = findUsers();
if (users != null) {
users.forEach(System.out::println);
}
// ✅ Без null-check:
public List<String> findUsers() {
if (!dataAvailable()) {
return Collections.emptyList(); // или List.of()
}
return loadUsers();
}
// Вызывающая сторона:
List<String> users = findUsers();
users.forEach(System.out::println); // проверка на null не нужна
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍4
Изоляция рунета ближе, чем ты думаешь
Роскомнадзору дали карт-бланш на блокировки, а «белые списки» сайтов тестируют уже в десятках регионов. И гайки будут закручиваться только сильнее.
Чтобы в одночасье не лишиться доступа к свободному Интернету, просто сохрани Only Hack.
Тут профессиональный хакер делится фишками, с которыми доступ к глобальной сети у тебя будет даже в случае ядерного апокалипсиса.
Не жди момента «Х». Перестрахуйся подпиской.
Loading …
██████████████] 99%
Роскомнадзору дали карт-бланш на блокировки, а «белые списки» сайтов тестируют уже в десятках регионов. И гайки будут закручиваться только сильнее.
Чтобы в одночасье не лишиться доступа к свободному Интернету, просто сохрани Only Hack.
Тут профессиональный хакер делится фишками, с которыми доступ к глобальной сети у тебя будет даже в случае ядерного апокалипсиса.
Не жди момента «Х». Перестрахуйся подпиской.
💊9❤1😁1
Вышел релиз IntelliJ IDEA 2025.3!
В этой версии завезли несколько заметных обновлений – все они подробно описаны и показаны в демках на странице “Что нового”.
Зацени
👉 Java Portal
В этой версии завезли несколько заметных обновлений – все они подробно описаны и показаны в демках на странице “Что нового”.
Зацени
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6
Java-совет: когда нужно наполнять значения в Map, например списки, удобно использовать computeIfAbsent().
Классический способ:
С использованием computeIfAbsent:
👉 Java Portal
Классический способ:
Map<String, List<String>> map = new HashMap<>();
if (!map.containsKey("key")) {
map.put("key", new ArrayList<>());
}
map.get("key").add("listValue");
С использованием computeIfAbsent:
map.computeIfAbsent("key", k -> new ArrayList<>())
.add("listValue");Please open Telegram to view this post
VIEW IN TELEGRAM
👍15
Твой Dockerfile не "простой". Он просто недописан.
Большинство девов за всю жизнь используют всего 5 инструкций Dockerfile:
FROM, COPY, RUN, EXPOSE, CMD, ну и иногда ENV, если уж прям заморочились.😱
Вот почему твоя команда Ops и пользователи молча тебя ненавидят.
Вот несколько инструкций, про которые ты, скорее всего, не знаешь:
- HEALTHCHECK: контейнер не становится здоровым только потому, что он запущен.
Нет, Kubernetes сам не поймет, что приложение внутри уже сдохло.
Скажи ему, как это проверять. Или дай Ops’ам удовольствие дебажить цикл перезапусков контейнеров в проде.
- SHELL:
По умолчанию это /bin/sh -c. Хочешь другое, используй SHELL.
Меньше экранирования, меньше проблем с кроссплатформой.
- STOPSIGNAL: не оставляй приложение подвисшим.
Задает сигнал, который Docker отправляет при остановке контейнера.
Используй тот сигнал, который твое приложение реально обрабатывает.
Больше никаких зомби-контейнеров и сломанной "корректной остановки".
- ONBUILD
Хочешь сделать базовые образы умнее, используй это.
Хочешь развалить чужой пайплайн, используй неправильно.
- ARG vs ENV: перестань путать "во время сборки образа" и “во время запуска контейнера”,
ARG: существует только во время сборки
ENV: остается в финальном образе
Если ты не понимаешь разницу, не удивляйся, когда приложение ведет себя по-разному на dev и в prod.
- LABEL: метаданные не опциональны.
Это не для красоты. Это нужно инструментам, CI и аудиторам. Потом сам себе спасибо скажешь.
Dockerfile это не шелл-скрипт.
Это продовый код.
Он описывает систему, которую ты поставляешь.
Ты же не выкатываешь наполовину сделанное API, так перестань выкатывать наполовину сделанные образы.
Научись писать Dockerfile, который не отстой.💩
👉 Java Portal
Большинство девов за всю жизнь используют всего 5 инструкций Dockerfile:
FROM, COPY, RUN, EXPOSE, CMD, ну и иногда ENV, если уж прям заморочились.
Вот почему твоя команда Ops и пользователи молча тебя ненавидят.
Вот несколько инструкций, про которые ты, скорее всего, не знаешь:
- HEALTHCHECK: контейнер не становится здоровым только потому, что он запущен.
Нет, Kubernetes сам не поймет, что приложение внутри уже сдохло.
Скажи ему, как это проверять. Или дай Ops’ам удовольствие дебажить цикл перезапусков контейнеров в проде.
- SHELL:
По умолчанию это /bin/sh -c. Хочешь другое, используй SHELL.
Меньше экранирования, меньше проблем с кроссплатформой.
- STOPSIGNAL: не оставляй приложение подвисшим.
Задает сигнал, который Docker отправляет при остановке контейнера.
Используй тот сигнал, который твое приложение реально обрабатывает.
Больше никаких зомби-контейнеров и сломанной "корректной остановки".
- ONBUILD
Хочешь сделать базовые образы умнее, используй это.
Хочешь развалить чужой пайплайн, используй неправильно.
- ARG vs ENV: перестань путать "во время сборки образа" и “во время запуска контейнера”,
ARG: существует только во время сборки
ENV: остается в финальном образе
Если ты не понимаешь разницу, не удивляйся, когда приложение ведет себя по-разному на dev и в prod.
- LABEL: метаданные не опциональны.
Это не для красоты. Это нужно инструментам, CI и аудиторам. Потом сам себе спасибо скажешь.
Dockerfile это не шелл-скрипт.
Это продовый код.
Он описывает систему, которую ты поставляешь.
Ты же не выкатываешь наполовину сделанное API, так перестань выкатывать наполовину сделанные образы.
Научись писать Dockerfile, который не отстой.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤1😁1
Java tip: используй Files.walk(), чтобы рекурсивно пройтись по файлам в каталоге.
👉 Java Portal
public static void main(String[] args) {
Path startPath = Paths.get("src");
try (Stream<Path> paths = Files.walk(startPath)) {
paths
.filter(Files::isRegularFile)
.filter(path -> path.toString().endsWith(".java"))
.forEach(System.out::println);
} catch (IOException e) {
e.printStackTrace();
}
}Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤2
Больше десяти лет
Прямолинейный. Синхронный. Простой.
С выходом Spring Framework 6 и Spring Boot 3 пришла современная замена:
- RestClient
❓ Чем обычно характеризуется
- API на методах (getForObject, postForEntity и т.д.)
- Очень явные вызовы под каждую HTTP-операцию
- Мало “цепочек”: часто один вызов укладывается в одну строку
- Настройки раскиданы по разным местам (interceptors, error handlers, converters)
- Синтаксис исторически нарастал кусками годами
Типичный пример:
Работает, но когда запрос усложняется (headers, auth, ошибки, таймауты), читаемость начинает страдать.
❓ RestClient меняет подход к API
- Флюентный, декларативный синтаксис
- Четкое разделение между сборкой request и чтением response
- Лучше читается, когда есть headers, params, auth и т.п.
- Единый, консистентный API для всех HTTP-методов
- Централизованный builder для общей конфигурации
Типичный пример:
Это та же идея, что у RestTemplate, но API яснее, расширяемее и проще поддерживать.
❓ Зачем RestClient, если уже есть WebClient
WebClient реактивный и неблокирующий (под другую задачу)
RestClient работает как RestTemplate: обычный (не реактивный) и с ожиданием ответа, просто это его современная замена.
Многим нужен современный API, но без перехода на реактивный стек.
Spring не пытается всех загнать в WebFlux. Он просто обновил классический HTTP-клиент.
Нет, он не умер, просто его только поддерживают: багфиксы и совместимость, без новых фич.
То есть новых возможностей не будет. Только апдейты совместимости.
А развитие будет происходить в RestClient.
Причем RestClient можно создать на базе RestTemplate:
❓ Что использовать сегодня:
Используй RestTemplate, если:
- приложение легаси
- миграция слишком дорогая
- завязан на библиотеки, которые работают только с RestTemplate
Используй RestClient, если:
- ты на Boot 3 / Spring 6+
- хочешь современный и чистый API
- хочешь остаться в императивном стиле
- не хочешь или не можешь использовать WebFlux
RestTemplate это классика, почти любой Java-разработчик на Spring хотя бы раз с ним сталкивался.
Но RestClient задает точку старта для нового.
Это не про реактивность и не про переделку архитектуры.
Это просто современный HTTP-клиент, который делает код понятнее и проще в сопровождении.
Похоже на подход многих других модулей Spring, где builder упрощает создание объектов и использование классов.
И в мире, где сервисы постоянно дергают внешние API, хороший HTTP-клиент реально важен.
👉 Java Portal
RestTemplate был главным вариантом для HTTP-запросов в Spring.Прямолинейный. Синхронный. Простой.
Он больше не развивается: новых фич и улучшений не будет, плюс есть ограничения по ошибкам и расширяемости.
С выходом Spring Framework 6 и Spring Boot 3 пришла современная замена:
RestTemplate- API на методах (getForObject, postForEntity и т.д.)
- Очень явные вызовы под каждую HTTP-операцию
- Мало “цепочек”: часто один вызов укладывается в одну строку
- Настройки раскиданы по разным местам (interceptors, error handlers, converters)
- Синтаксис исторически нарастал кусками годами
Типичный пример:
RestTemplate rest = new RestTemplate();
ResponseEntity<User> response =
rest.exchange(url, HttpMethod.GET, request, User.class);
Работает, но когда запрос усложняется (headers, auth, ошибки, таймауты), читаемость начинает страдать.
- Флюентный, декларативный синтаксис
- Четкое разделение между сборкой request и чтением response
- Лучше читается, когда есть headers, params, auth и т.п.
- Единый, консистентный API для всех HTTP-методов
- Централизованный builder для общей конфигурации
Типичный пример:
User user = client.get()
.uri(url)
.header("Authorization", token)
.retrieve()
.body(User.class);
Это та же идея, что у RestTemplate, но API яснее, расширяемее и проще поддерживать.
WebClient реактивный и неблокирующий (под другую задачу)
RestClient работает как RestTemplate: обычный (не реактивный) и с ожиданием ответа, просто это его современная замена.
Многим нужен современный API, но без перехода на реактивный стек.
Spring не пытается всех загнать в WebFlux. Он просто обновил классический HTTP-клиент.
❓ RestTemplate “мертв”
Нет, он не умер, просто его только поддерживают: багфиксы и совместимость, без новых фич.
То есть новых возможностей не будет. Только апдейты совместимости.
А развитие будет происходить в RestClient.
Причем RestClient можно создать на базе RestTemplate:
RestTemplate oldRestTemplate;
var restClient = RestClient.create(oldRestTemplate);
Используй RestTemplate, если:
- приложение легаси
- миграция слишком дорогая
- завязан на библиотеки, которые работают только с RestTemplate
Используй RestClient, если:
- ты на Boot 3 / Spring 6+
- хочешь современный и чистый API
- хочешь остаться в императивном стиле
- не хочешь или не можешь использовать WebFlux
RestTemplate это классика, почти любой Java-разработчик на Spring хотя бы раз с ним сталкивался.
Но RestClient задает точку старта для нового.
Это не про реактивность и не про переделку архитектуры.
Это просто современный HTTP-клиент, который делает код понятнее и проще в сопровождении.
Похоже на подход многих других модулей Spring, где builder упрощает создание объектов и использование классов.
И в мире, где сервисы постоянно дергают внешние API, хороший HTTP-клиент реально важен.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍4