Java Portal | Программирование
前往频道在 Telegram
Присоединяйтесь к нашему каналу и погрузитесь в мир для Java-разработчика Связь: @devmangx РКН: https://clck.ru/3H4WUg
显示更多📈 Telegram 频道 Java Portal | Программирование 的分析概览
频道 Java Portal | Программирование (@java_iibrary) 俄语 语言赛道中的 是活跃参与者。目前社区聚集了 12 130 名订阅者,在 技术与应用 类别中位列第 10 402,并在 俄罗斯 地区排名第 54 525 位。
📊 受众指标与增长动态
自 невідомо 创建以来,项目保持高速增长,吸引了 12 130 名订阅者。
根据 07 六月, 2026 的最新数据,频道保持稳定运转。过去 30 天订阅人数变化为 -138,过去 24 小时变化为 2,整体触达仍然可观。
- 认证状态: 未认证
- 互动率 (ER): 平均受众互动率为 11.37%。内容发布后 24 小时内通常能获得 6.26% 的反应,占订阅者总量。
- 帖子覆盖: 每篇帖子平均可获得 1 379 次浏览,首日通常累积 760 次浏览。
- 互动与反馈: 受众积极参与,单帖平均反应数为 4。
- 主题关注点: 内容集中在 boot, string, void, архитектура, resttemplate 等核心主题上。
📝 描述与内容策略
作者将该频道定位为表达主观观点的平台:
“Присоединяйтесь к нашему каналу и погрузитесь в мир для Java-разработчика
Связь: @devmangx
РКН: https://clck.ru/3H4WUg”
凭借高频更新(最新数据采集于 08 六月, 2026),频道始终保持新鲜度与高覆盖。分析显示受众积极互动,使其成为 技术与应用 类别中的关键影响点。
12 130
订阅者
+224 小时
-287 天
-13830 天
帖子存档
Spring Boot: можно добавить глобальные метаданные OpenAPI с помощью аннотации
@OpenAPIDefinition.
Размести её на главном классе приложения Spring Boot или в отдельном конфигурационном классе.
@SpringBootApplication
@OpenAPIDefinition(
info = @Info(
title = "Product Management API",
version = "v1.0",
description = "Product API Example",
termsOfService = "https://www.example.com/terms",
contact = @Contact(
name = "API Support",
email = "support@example.com",
url = "https://example.com/support"
),
license = @License(
name = "Apache 2.0",
url = "https://www.apache.org/licenses/LICENSE-2.0"
)
)
)
public class ApiApplication {
}Если у тебя Spring Boot приложение подключено как вложенный модуль и оно использует поддержку Docker Compose, то в IntelliJ IDEA нужно задать MODULE_WORKING_DIRECTORY, чтобы среда смогла корректно определить, где лежит файл compose.yaml.
👉 Java Portal
Spring Boot: для новых приложений выбирайте WebClient вместо RestTemplate
~ Реактивный и неблокирующий
~ Работает на event-loop, а не на модели один поток на запрос
~ Отлично подходит для микросервисной архитектуры
❌ RestTemplate (blocking)
@Service
public class ItemService {
private final RestTemplate restTemplate;
public ItemService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public Item getItem(Long id) {
return restTemplate.getForObject(
"https://api.example.com/items/{id}",
Item.class,
id
);
}
}
✅ WebClient (non-blocking)
@Service
public class ItemService {
private final WebClient webClient;
public ItemService(WebClient webClient) {
this.webClient = webClient;
}
public Mono<Item> getItem(Long id) {
return webClient.get()
.uri("/items/{id}", id)
.retrieve()
.bodyToMono(Item.class);
}
}
👉 Java PortalСоздаём первый Minecraft мод и подробно разбираем Mixin. Просто и понятно
Эта статья была написана из-за отсутствия адекватных русскоязычных руководств по моддингу, особенно для новых версий Minecraft. То, что описано в статье, будет применимо для таких загрузчиков модов, как Fabric и Forge, а также для реализации различных функций.
👉 Java Portal
🔴 Завтра тестовое собеседование с Java-разработчиком
24 декабря(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика.
Как это будет:
📂 Сергей Чамкин, старший разработчик из Uzum, ex-WildBerries, будет задавать реальные вопросы и задачи разработчику-добровольцу
📂 Cергей будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью
📂 В конце можно будет задать любой вопрос Сергею
Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы.
Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot
Реклама.
О рекламодателе.
Java-совет: избегайте глубоко вложенных if/else.
Используйте guard clauses (ранние выходы из метода) вместо этого.
❌ Вложенные if-else:
public void processOrder(Order order) {
if (order != null) {
if (order.isPaid()) {
if (order.getItems().size() > 0) {
// Обработка заказа
System.out.println("Заказ обработан");
} else {
System.out.println("В заказе нет позиций");
}
} else {
System.out.println("Заказ не оплачен");
}
} else {
System.out.println("Заказ равен null");
}
}
✅ Использование guard clauses (читается проще):
public void processOrder(Order order) {
if (order == null) {
System.out.println("Заказ равен null");
return;
}
if (!order.isPaid()) {
System.out.println("Заказ не оплачен");
return;
}
if (order.getItems().isEmpty()) {
System.out.println("В заказе нет позиций");
return;
}
// Обработка заказа
System.out.println("Заказ обработан");
👉 Java PortalKubernetes-совет:
Java-приложения обычно требуют больше CPU на старте, чем во время обычной работы ☕️
Эта политика Kyverno:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: resize-pod-policy
spec:
mutateExistingOnPolicyUpdate: false
rules:
- name: resize-pod-policy
match:
any:
- resources:
kinds:
- Pod/status
- Pod
preconditions:
all:
- key: "{{request.object.status.containerStatuses[0].ready}}"
operator: Equals
value: true
mutate:
targets:
- apiVersion: v1
kind: Pod.resize
name: "{{request.object.metadata.name}}"
patchStrategicMerge:
spec:
containers:
- (name): sample-app-on-kubernetes
resources:
limits:
cpu: 0.5
- отслеживает момент завершения старта pod’а
- обновляет ресурсы pod’а прямо на месте
- снижает CPU-лимиты после старта
Итог: более быстрый запуск и меньшие затраты
Вот моя статья об этом
👉 Java PortalSpring Boot наконец получил нативную поддержку gRPC
Забудьте о сторонних стартерах и костылях — Spring gRPC 1.0 GA уже здесь. Теперь можно строить высокопроизводительные RPC-сервисы с Protocol Buffers прямо из коробки, без плясок с бубном.
👉 Java Portal
Когда ты уже не джун и даже не мидл, на собеседованиях по Java почти не задают вопросы в стиле «что такое HashMap». В ход идут сценарии из реальной жизни.
Разберём типичный кейс.
Твой сервис — оркестратор. Он дергает несколько downstream-сервисов, чтобы обработать запрос.
Один из них проблемный: медленный и периодически отвечает 503 Service Unavailable.
1. Как сделать сервис устойчивым к ненадёжному downstream
Первое, что здесь просится » Circuit Breaker.
Идея простая: если зависимый сервис начинает фейлиться, мы перестаём его дёргать, чтобы:
- не тратить ресурсы,
- не увеличивать латентность,
- не убивать весь сервис каскадными таймаутами.
Реализация с Resilience4j:
Подключаем зависимость и оборачиваем вызов проблемного сервиса в CircuitBreaker.
Ключевые состояния:
Всё нормально. Запросы проходят. Ошибки считаются.
Порог ошибок превышен. Все вызовы сразу фейлятся, downstream даже не вызывается.
Пробный режим. Ограниченное число запросов, чтобы проверить — ожил сервис или нет.
Пример:
@CircuitBreaker(name = "inventoryService", fallbackMethod = "inventoryFallback")
public InventoryResponse getInventory(String productId) {
return inventoryClient.getInventory(productId);
}
Конфиг обычно задаётся через application.yml:
- процент ошибок
- sliding window
- waitDurationInOpenState
- permittedNumberOfCallsInHalfOpenState
2. Что делать, когда circuit открыт (fallback)
Тут нет универсального ответа » зависит от бизнеса.
Типовые варианты:
🔹Кэш
Если данные не критичны к свежести:
- Redis
- локальный cache
- stale-данные лучше, чем 503
private InventoryResponse inventoryFallback(String productId, Throwable ex) {
return cacheService.getInventory(productId);
}
🔹Дефолтный ответ
Если можно вернуть «безопасное» значение:
- пустой список
- available = false
- статус UNKNOWN
🔹Очередь
Если запрос важен, но не срочный:
- кладём событие в Kafka / Rabbit
- обрабатываем асинхронно
- отвечаем клиенту 202 Accepted
На практике часто комбинируют:
кэш + деградация функциональности.
3. Глобальная обработка ошибок через @RestControllerAdvice
Чтобы не размазывать try/catch по всему коду, делаем централизованный обработчик.
Пример бизнес-исключения
public class ProductNotFoundException extends RuntimeException {
public ProductNotFoundException(String id) {
super("Product not found: " + id);
}
}
Глобальный handler
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ProductNotFoundException.class)
public ResponseEntity<ErrorResponse> handleProductNotFound(ProductNotFoundException ex) {
ErrorResponse error = new ErrorResponse(
"PRODUCT_NOT_FOUND",
ex.getMessage()
);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
}
JSON-ответ
{
"code": "PRODUCT_NOT_FOUND",
"message": "Product not found: 123"
}
Плюсы подхода:
- чистые контроллеры
- единый формат ошибок
- нормальная мапа бизнес-ошибок на HTTP-статусы
Итог
На таком вопросе проверяют не знание аннотаций, а мышление:
- понимаешь ли ты отказоустойчивость
- умеешь ли деградировать сервис
- разделяешь ли бизнес-ошибки и технические фейлы
Это уже разговор не про «Java», а про архитектуру продакшн-сервисов
👉 Java PortalJava Tip: Начиная с Java 14 можно использовать record для создания компактных неизменяемых объектов, которые просто переносят данные.
» Они короче обычных POJO
» У них из коробки есть equals(), hashCode() и toString()
» По умолчанию они неизменяемые
Классический POJO:
public class Book {
private final String title;
private final int price;
public Book(String title, int price) {
this.title = title;
this.price = price;
}
// геттеры, toString, equals и hashCode
}
Вместо этого можно создать record:
public record Book(String title, int price) {}
Смысл ровно тот же, но без бойлерплейта.
👉 Java PortalКогда всё живёт в одной базе данных, с транзакциями всё просто.
BEGIN → COMMIT → ROLLBACK.
Но в распределённых системах всё резко усложняется.
В чём реальная проблема ???
В распределённых системах нельзя сделать одну транзакцию на всё сразу по нескольким причинам:
- несколько сервисов
- несколько баз данных
- множество возможных отказов
Классического rollback больше не существует.
И тут появляется паттерн Saga.
Saga это последовательность локальных транзакций, которые координируются между собой.
Каждый шаг:
- выполняет своё изменение
- фиксируется
- и определяет, как себя компенсировать, если дальше что-то пойдёт не так
Глобальной транзакции нет.
Есть eventual consistency.
Простой пример » Создание заказа может включать:
1. Создать заказ
2. Зарезервировать товар
3. Провести оплату
Если на шаге 3 происходит сбой, глобального rollback нет.
Выполняются компенсирующие действия:
- освободить резерв
- пометить заказ как отменённый
Это и есть Saga.
Два способа реализации Saga -
Хореография:
- сервисы реагируют на события
- центрального координатора нет
- слабая связность
- сложнее проследить общий поток
Оркестрация:
- есть компонент-координатор
- поток шагов явно описан
- проще рассуждать о логике
- выше связность
Ни один подход не является универсально лучшим. Всё зависит от системы и контекста.Частая ошибка » Считать, что Saga — это замена ACID-транзакциям. Это не так. Saga меняет сам контракт: - допускаются промежуточные состояния - компенсации проектируются явно - принимается факт, что система может упасть на середине процесса Когда Saga действительно имеет смысл - долгоживущие процессы - несколько сервисов - реальные побочные эффекты: платежи, доставки, резервы - ситуации, где технического rollback не существует Если всё находится в одной базе данных, Saga не нужна. Здесь легко уйти в оверинжиниринг. Ключевая мысль:
Saga не убирает сложность. Она делает её явной.Явная сложность лучше, чем спрятанная за предположениями, которые больше не работают. В распределённых системах сбои — это не исключение, а часть нормального потока. Паттерн Saga не избавляет от всех проблем, но помогает избежать беспорядка. А в продакшене это уже большая разница. ☃️ 👉 Java Portal
Этот проект показывает систему отслеживания местоположения курьера в реальном времени, похожую на то, как это реализовано в Zomato или Swiggy, и построенную на Spring Boot и Apache Kafka.
👉 Java Portal
Spring Boot 4 теперь полностью безопасен по работе с null — большой плюс для Kotlin-разработчиков.
С поддержкой JSpecify в Kotlin 2.2 наконец-то можно избавиться от платформенных типов и получить корректную работу с null даже в обобщённых типах.
Подробнее и попробовать Spring с Kotlin ☺️
👉 Java Portal
Сегодня в рубрике crazy Java: этот код работает (на Java 25):
<T extends Integer> void test(T t) {
t++;
// t += 1;
IO.println(t);
}
void main() {
test(10);
}
Но если заменить t++ на t += 1, всё ломается.
Ошибка:
Main.java:3: error: incompatible types: int cannot be converted to T
👉 Java PortalВ JDK 26 появилась новая фича: HttpClient, который входит в Java SE ещё со времён JDK 11, теперь поддерживает HTTP/3 😱
HttpClient client = HttpClient.newBuilder()
.version(HttpClient.Version.HTTP_3)
.build(); // создать экземпляр HttpClient с HTTP/3 в качестве предпочтительной версии
URI reqURI = new URI("https://www.google.com/");
HttpRequest req = HttpRequest.newBuilder()
.uri(reqURI)
.build(); // создать экземпляр запроса
final HttpResponse.BodyHandler<String> bodyHandler =
BodyHandlers.ofString(StandardCharsets.UTF_8);
HttpResponse<String> resp = client.send(req, bodyHandler);
// отправить запрос и получить ответ в виде строки
System.out.println(
"status code: " + resp.statusCode() +
" HTTP protocol version: " + resp.version()
); // вывести код ответа и используемую версию HTTP
Подробнее
👉 Java PortalСовет по Spring Boot: используйте TaskScheduler для реализации лёгких динамических задач. Для более сложных сценариев лучше смотреть в сторону Quartz.
Инжектим и используем:
@Autowired
TaskScheduler scheduler;
scheduler.schedule(
() -> System.out.println("Hello!"),
new CronTrigger("0 */5 * * * *") // каждые 5 минут
);
Инжектируемый бин — это ThreadPoolTaskScheduler, встроенная реализация сразу TaskScheduler и ScheduledExecutorService
При необходимости конфигурацию можно кастомизировать:
@Configuration
@EnableScheduling
public class SchedulerConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(5);
scheduler.setThreadNamePrefix("my-scheduler-");
scheduler.initialize();
return scheduler;
}
}
👉 Java PortalСлучайные UUID убивают производительность базы данных.
Ты перешел с целочисленных ID (1, 2, 3…) на UUID (a1b2-3c4d-…) ради безопасности или распределенной генерации.
И вдруг записи в БД стали медленнее. Иногда намного.
Вот почему.
Фрагментация индексов.
Большинство индексов в БД это B-Tree (сбалансированные отсортированные деревья). Физическое расположение данных имеет значение.
1. Последовательные ID
Когда ты вставляешь последовательные числа (1, 2, 3), новые записи всегда попадают в самый правый лист индекса.
Записи предсказуемые и последовательные.
Максимальные cache hit’ы.
Страницы индекса остаются заполненными на 100%.
Это максимальная скорость, на которую способна твоя база.
2. Случайные UUIDv4
UUIDv4 равномерно случайные. Это значит, что каждая новая вставка может попасть в любое место дерева.
Из-за этого:
-» База постоянно подгружает случайные страницы с диска в память (random I/O).
-» Page split. Если целевая страница заполнена, БД вынуждена делить ее пополам, в итоге получаются две полупустые страницы.
-» Эффект швейцарского сыра. Индекс раздувается и заполняется дырками, зря тратя RAM и место на диске.
-» Когда размер индекса превышает объем доступной памяти, пропускная способность на запись может просесть на 20–90%.
3. UUIDv7
Перестань использовать UUIDv4 в качестве primary key. Используй UUIDv7 (стандартизирован в RFC 9562).
UUIDv7 содержит таймстемп в начале ID, поэтому он сортируемый.
В итоге ты получаешь лучшее из двух миров:
-» Распределенная генерация, без центрального счетчика.
-» Монотонные вставки. В B-Tree они ведут себя почти как последовательные числа, без фрагментации.
-» Безопасность. Нельзя просто угадать ID (атакующий не узнает, что пользователь 101 идет сразу после 100), хотя стоит учитывать, что время создания записи становится видно.
Итог простой: ты сохраняешь удобство UUID и избавляешься от перфоманс-потерь.
👉 Java Portal
Реальная история:
Дизайнерское агентство разработало интерфейс приложения в сервисе Figma, но из-за того, что карты Visa и Mastercard оказались заблокированы, не смогли выгрузить проект.
Осложнялось всё тем, что они могли олатить сервис только с корпоративной карты.
Читпей организовали оплату в течение 10 минут. Ребята оплатили подписку, и выгрузили проект. Интерфейс приложения был спасён!
Что делает CheatPay:
🔘Помогает оплатить зарубежные сервисы российскими картами, в том числе Visa и Mastercard.
🔘Восстанавливают доступ к аккаунту
🔘Работают прозрачно с оплатой на ИП и всеми закрывающими документами
Например:
Потеряли доступ к Zoom, Airtable, Atlassian, Canva и другим программам для управления IT-проектами? Простаивают проекты в Adobe Photoshop, Premiere Pro и After Effects? Другие сервисы? Помогут.
Обращаться в https://t.me/cheatpay_ru
Тема Islands теперь используется по умолчанию во всех IDE от JetBrains.
Более мягкий и сбалансированный внешний вид, рассчитанный на комфорт и концентрацию во время работы.
Посмотреть подробнее 👉 https://jb.gg/discover-the-islands
👉 Java Portal
WebFlux часто вызывает путаницу, потому что его обычно объясняют со стороны инструмента, а не со стороны проблемы.
Поэтому начнем с базы.
Сначала: блокирующий vs неблокирующий код
-» Блокирующий код:
Поток встает и ждет, пока операция не завершится.
Пока ждет, он ничего больше делать не может.
-» Неблокирующий код:
Поток делегирует ожидание и остается свободным для других задач.
Когда результат готов, выполняется продолжение.
Это не быстрее.
Это просто более эффективное использование потоков.
Еще одно ключевое понятие перед тем как идти дальше:
Backpressure. Это способность системы регулировать поток данных, чтобы не перегружать потребителя.
Представь так:
потребитель может сказать продюсеру: «присылай только столько, сколько я успеваю обработать».
Теперь к WebFlux.
WebFlux позволяет строить полностью неблокирующие приложения end-to-end:
-»Неблокирующий сервер (Netty)
-»Неблокирующие API
-»Проброс backpressure без перегрузки потребителя
-»Реактивная модель (Mono, Flux)
Ключевое слово здесь end-to-end.
Если хотя бы одна часть блокирует, весь выигрыш размывается.
Самая частая ошибка при работе с WebFlux
Использовать WebFlux, а потом:
-»Дернуть блокирующую базу данных
-»Использовать SDK без реактивной поддержки
-»Делать .block(), потому что так проще
В итоге:
-»Все равно все становится блокирующим
-»Ты просто добавил сложности
-»Ничего не выиграл
WebFlux не превращает блокирующий код в неблокирующий.
А Virtual Threads разве это не меняют?
Меняют, и это важно.
С Virtual Threads:
-»Блокирующая модель снова становится жизнеспособной
-»Цена ожидания резко падает
-»Необходимость в WebFlux уменьшается
Но есть нюанс.
Virtual Threads не дают:
-»Backpressure
-»Контроль потока
-»Композицию стримов
-»Настоящий стриминг данных
Они меняют tradeoff, но не убирают саму проблему.
Когда WebFlux все еще имеет смысл
WebFlux оправдан, когда:
-»Нужен реальный backpressure
-»Ты работаешь с непрерывными стримами (SSE, WebSockets)
-»Есть fan-out из множества внешних вызовов
-»Нужно явно контролировать поток данных
По необходимости, а не потому что модно.
Когда не стоит использовать WebFlux
-»Классический CRUD
-»Сложная бизнес-логика
-»Команды без реактивного опыта
-»Проекты, где читаемость важнее конкурентности
-»Когда Virtual Threads решают задачу с меньшей когнитивной стоимостью
WebFlux это другая модель исполнения.
Если твоя проблема не в масштабной I/O-конкурентности,
WebFlux тебе не поможет.
А сегодня, с Virtual Threads, многим он уже просто не нужен.
👉 Java Portal
现已上线!2025 年 Telegram 研究 — 年度关键洞察 
