Java Portal | Программирование
12.6K subscribers
1.08K photos
86 videos
35 files
936 links
Присоединяйтесь к нашему каналу и погрузитесь в мир для Java-разработчика

Связь: @devmangx

РКН: https://clck.ru/3H4WUg
Download Telegram
Многие начинают с Java и используют static повсюду.

Кажется, что это «упрощает код», например при вызове методов, но на самом деле static — это довольно точное понятие, которое стоит хорошо понимать.

В Java static означает, что что-то принадлежит классу, а не экземпляру. То есть:

- Статическое поле существует в памяти только один раз и шарится между всеми объектами этого класса.
- Статический метод можно вызвать без создания экземпляра.
- Жизненный цикл статических сущностей начинается при загрузке класса в память и заканчивается только при завершении JVM.

Для чего используется? 🤔

- Для объявления констант (public static final), которые никогда не меняются.
- Для утилитарных методов (например, Collections.sort()), которые не зависят от внутреннего состояния объекта.

Где начинаются проблемы?

- Когда используешь static для переменных, которые на самом деле должны быть частью состояния объекта.
- Когда превращаешь его в «глобальную зависимость», и код становится тяжело тестировать, плюс возникает сильная связность.

static — это не шорткат. Это способ сказать:
«это уникально и шарится по всему приложению».


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
7👍3
Java Streams Cheat Sheet

Пример кода со всеми базовыми приёмами работы со Stream API:

преобразование коллекций

flatMap, mapMulti, peek

сортировка, min/max, distinct

проверки (allMatch, anyMatch)

объединение (reduce, joining)

группировка и разбиение (groupingBy, partitioningBy)


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
12
CQRS — один из самых популярных вопросов на собеседованиях Java/backend-разработчиков, связанных с взаимодействием микросервисов.

При этом обычно не задают вопрос в формате «Дайте определение CQRS», а формулируют его через реальный сценарий.

Сценарий:

Сервис заказов на e-commerce платформе в данный момент обрабатывает все операции (массовое создание и обновление заказов, поиск заказов клиентов, формирование сложных отчётов по продажам) через одну общую реляционную базу данных.
Во время пиковых нагрузок тяжёлые отчётные запросы вызывают серьёзные замедления транзакционных операций, что ухудшает пользовательский опыт. Кроме того, сама модель данных заказов становится чрезмерно сложной, пытаясь одновременно удовлетворить разные потребности.


Вопросы:

Определите проблему: Какую ключевую архитектурную проблему этот пример демонстрирует в части работы с данными и почему единая модель данных не справляется?

Предложите решение: Как вы бы переработали этот сервис, чтобы устранить проблемы с производительностью и избыточной сложностью? Назовите архитектурный паттерн и его основной принцип.

Ответ:

CQRS решает эту задачу за счёт разделения моделей и баз данных для записи и чтения.

Запись (заказы): команды обновляют выделенную нормализованную базу для записи (оптимизированную под транзакции).

Чтение (отчёты): события записи асинхронно обновляют отдельную денормализованную базу для чтения (оптимизированную под быстрые запросы и отчётность).

CQRS чаще всего реализуется с использованием брокера сообщений.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Проект JDBG от roger1337 позволяет подключаться к JVM во время выполнения и исследовать внутреннее состояние Java-программы.

Инструмент использует JNI + JVMTI + DLL-инъекцию, поддерживает просмотр классов, байткода, стека вызовов, локальных переменных и экземпляров объектов.

Создан для исследовательских и образовательных целей, под лицензией Apache 2.0.

https://github.com/roger1337/JDBG

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍63🔥3
В Spring Boot ProductController нужно обработать два разных случая:

1. Вернуть простой 404 Not Found, если продукт не найден.

2. Вернуть 201 Created с динамическим заголовком Location при успешном создании.

Какие механизмы Spring вы бы использовали для реализации каждого из этих требований и почему?

Два основных способа управлять HTTP-ответом, отправляемым клиенту:

@ResponseStatus: простой статический вариант

- Можно навесить на исключение или метод контроллера.

- Всегда возвращает один и тот же HTTP-статус.

- Подход "fire-and-forget": быстро и лаконично в случаях, когда ответ всегда одинаковый.

- Лучше всего подходит для простой обработки ошибок. Например, ResourceNotFoundException, аннотированный @ResponseStatus(HttpStatus.NOT_FOUND), всегда будет возвращать 404.

- Нельзя добавить кастомные заголовки или динамическое тело ответа.

ResponseEntity: кастомный инструмент

- Даёт полный программный контроль над формированием HTTP-ответа во время выполнения.

- Можно выставить статус, добавить заголовки и собрать тело ответа так, как требуется по логике.

- Лучше всего подходит для сложных ответов. Например, когда нужно добавить заголовок Location после создания ресурса (201 Created) или вернуть детализированный JSON-объект с информацией об ошибке.

- Это основной инструмент, когда ответ должен зависеть от ситуации.

Комбинация подходов:

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

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍65
Учись Git прямо в браузере

Теперь можно тренироваться с командами Git, не устанавливая ничего на свой компьютер.

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

Попробовать можно здесь

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍6
Генерация тестовых данных

Чтобы написать хороший тест, нужны хорошие тестовые данные, приближенные к production. Плохо подготовленные данные = плохо написанный тест.

Поэтому практически все тесты должны состоять из трех основных частей:

- given (подготовка данных и стабов для mock/spy)
- when (вызов тестируемого API)
- then (проверка результата)

Сложно написать хороший тест, полагаясь на данные, которые уже существуют в базе в момент запуска теста (за исключением справочных данных или тех, что были накатаны на production с помощью миграционных фреймворков вроде liquibase и flyway). Обычно на эти данные полагаются другие тесты, а потому часто меняются, что ломает наши тесты или делает их даже flaky.

Поэтому каждый тест должен в идеале готовить данные только для себя, на которых он планирует проверить API:


@Test
void findAll() {
// given
// Все компактно, содержит только необходимую информацию для программиста
User user1 = userDao.save(getUser("test1@gmail.com"));
User user2 = userDao.save(getUser("test2@gmail.com"));
User user3 = userDao.save(getUser("test3@gmail.com"));

// when
List<User> actualResult = userDao.findAll();

// then
// Легко получить доступ к id объектов, т.к. накатывание данных было в самом тесте
assertThat(actualResult).hasSize(3);
List<Integer> userIds = actualResult.stream()
.map(User::getId)
.toList();
assertThat(userIds).contains(user1.getId(), user2.getId(), user3.getId());
}


А чтобы не испортить состояние базы во время проверки, то:

- открываем транзакцию ПЕРЕД выполнением теста (@BeforeEach)
- накатываем данные, вызываем API и проверяем результат (@Test)
- откатываем транзакцию в конце (@AfterEach)

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍2
JEP 511 в Java добавляет возможность краткого импорта всех пакетов, экспортируемых модулем. Это облегчает повторное использование модульных библиотек без необходимости помещать импортирующий код в модуль.

Подробнее: https://openjdk.org/jeps/511

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Одна из самых частых тем на собеседованиях Java/backend-разработчиков ⇒ Проблема N+1 в JPA

→ 1 первичный запрос: получение N родительских сущностей.
→ Затем N дополнительных запросов: для каждой из этих N сущностей выполняется отдельный запрос, чтобы загрузить связанные дочерние данные.
→ В итоге выполняется 1 + N запросов к БД, что приводит к снижению производительности и замедлению отклика.

Пример:
Получаем 100 авторов (1 запрос), а затем в цикле вызываем author.getBooks() для каждого (N=100) — в итоге 101 запрос.

⇒ Как решить проблему N+1 в JPA

⇆ Цель — загрузить связанные данные за меньшее количество запросов, желательно за один проход к базе.

1. JPQL/HQL JOIN FETCH (рекомендуется для конкретных связей)
Позволяет явно указать JPA, что ассоциации нужно подгружать через JOIN в запросе.

Пример:

@Query("SELECT a FROM Author a JOIN FETCH a.books")
List<Author> findAllWithBooks();


Плюсы: один эффективный запрос.
Важно: при джойне нескольких коллекций можно получить декартово произведение.

2. Batch Fetching
(@BatchSize или hibernate.default_batch_fetch_size)
Вместо одного запроса на каждого родителя, связанные коллекции загружаются пакетами — по нескольким ID за один запрос.

Пример:

@BatchSize(size = 10)
@OneToMany(...)
private List<Book> books;


Плюсы: уменьшает количество запросов с 1 + N до 1 + (N / batch_size), избегая проблемы декартовых произведений.

3. Entity Graphs
(@EntityGraph — Spring Data JPA / JPA 2.1+)
Позволяет декларативно определить, какие связи нужно подгружать eagerly для конкретного метода репозитория.

Пример:

@EntityGraph(attributePaths = "books")
List<Author> findAll();


Плюсы: гибкая и переиспользуемая стратегия загрузки без явных JPQL JOIN’ов.

Всегда используйте явные стратегии загрузки (такие как JOIN FETCH, @BatchSize или @EntityGraph), чтобы избежать проблемы N+1 и обеспечить эффективное взаимодействие с базой данных.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍94😁1
Распространённые Алгоритмы Балансировки Нагрузки

Статические алгоритмы

1. Круговой Алгоритм

Клиентские запросы отправляются в различные экземпляры сервисов в последовательном порядке. Сервисы обычно должны быть без сохранения состояния.

Недостаток:

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

2. Закреплённый Круговой Алгоритм

Усовершенствование кругового алгоритма. Если первый запрос Алисы отправляется в сервис A, следующие запросы также отправляются в сервис A.

3. Взвешенный Круговой Алгоритм

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

4. Хэш IP/URL

Применяет хеш-функцию к IP или URL входящих запросов. Запросы направляются в соответствующие экземпляры на основе результата хеш-функции.

Преимущества:

- Постоянство сессии – алгоритм гарантирует, что запросы от одного клиента всегда попадают на один и тот же сервер.
- Облегчает кеширование данных на стороне сервера для конкретных клиентов.

Недостатки:

- Если много пользователей приходят из одного диапазона IP, один сервер может быть перегружен.
- Неэффективен в средах, где IP клиентов часто меняются (мобильные сети).
- Может привести к неравномерной нагрузке, если некоторые клиенты генерируют больше трафика.


Динамические алгоритмы

5. Наименьшее Количество Соединений

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

Преимущества:

- Более мощные серверы естественным образом будут обрабатывать больше запросов и, следовательно, иметь больше соединений. И напротив, менее мощные серверы будут получать меньше запросов, что предотвращает их перегрузку.
- Гибкость – если один сервер начинает работать медленнее, он будет получать меньше новых запросов.

Недостатки:

- Алгоритм считает все соединения одинаковыми, не учитывая, что некоторые запросы могут быть более ресурсоёмкими.
- Вновь добавленный сервер может получить слишком много запросов, т.к. изначально у него 0 соединений.

6. Наименьшее Время Ответа

Новый запрос отправляется в экземпляр сервиса с самым быстрым временем ответа. Аналогичный алгоритм - Наименьший объем трафика

Преимущества:

- Учёт текущей производительности серверов и динамическая адаптация обеспечивают оптимальный баланс и наилучший пользовательский опыт.
- Хорошо работает с серверами разной мощности и приложениями с разными характеристиками.

Недостаток:

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


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Полный Roadmap для Spring Boot разработчика

Много разработчиков ищут структурированный путь от новичка до продвинутого уровня в Spring Boot. Ниже представлен 3-фазный roadmap, который поможет освоить все ключевые концепции и инструменты.

PHASE 1

- Создание Spring Boot проекта через Spring Initializer
- Maven и Gradle
- Основные аннотации
- Профили и конфигурации для разных окружений
- @GetMapping, @PostMapping, @PutMapping, @DeleteMapping
- Path variables и request parameters
- Настройка баз данных (H2, MySQL, PostgreSQL)
- Использование JpaRepository и CrudRepository
- Spring Boot DevTools и hot reloading
- Spring Batch, Scheduling и Cron выражения

PHASE 2

- @ControllerAdvice и @ExceptionHandler
- Кастомные ошибки и глобальная обработка исключений
- Базовая аутентификация и настройка безопасности API
- JWT для stateless аутентификации
- HATEOAS и версионирование REST API (URI, параметры, headers)
- Unit-тесты с JUnit и Mockito
- Интеграционные тесты с Spring Boot Test и MockMvc
- Actuator endpoints и кастомные health indicators

PHASE 3

- @Profile и настройка бинов для разных окружений
- Spring Cloud: Eureka Server, Service Discovery, API Gateway
- Spring Cloud Config Server для централизованного управления конфигурациями
- Настройка Spring Boot приложений для работы с Config Server

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

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
5🔥5🏆1
В статье разбираем, почему graceful shutdown важен и как настроить плавное завершение работы Spring Boot приложения, которое работает с Kafka.

Ты узнаешь, как корректно завершать обработку сообщений, чтобы не потерять данные и избежать ошибок при остановке сервиса. Практичные советы и примеры кода помогут сделать твое приложение более стабильным и надежным.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
1