Spring Boot: используй CommandLineRunner, чтобы выполнять логику при старте приложения.
CommandLineRunner это интерфейс Spring Boot. Его можно реализовать, чтобы запускать код после того, как контекст приложения полностью инициализирован.
Некоторые сценарии, где это уместно:
Заполнение БД начальными данными
Запуск health-check’ов при старте
Бутстрап внешних сервисов/ресурсов
Пример:
👉 Java Portal
CommandLineRunner это интерфейс Spring Boot. Его можно реализовать, чтобы запускать код после того, как контекст приложения полностью инициализирован.
Некоторые сценарии, где это уместно:
Заполнение БД начальными данными
Запуск health-check’ов при старте
Бутстрап внешних сервисов/ресурсов
Пример:
@Component
public class StartupRunner implements CommandLineRunner {
@Override
public void run(String... args) {
System.out.println("Приложение запущено! Дальнейшая настройка");
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
Please open Telegram to view this post
VIEW IN TELEGRAM
❤34🔥11👍4🤣2🏆1
Spring Boot: чтобы при сериализации в Jackson исключать любые поля, у которых значение null, можно использовать аннотацию
Все пустые поля исключаются автоматически.
👉 Java Portal
@JsonInclude(Include.NON_NULL)@JsonInclude(JsonInclude.Include.NON_NULL)
public class UserDTO {
private Long id;
private String name;
private String email;
private String phone;
...
}
Все пустые поля исключаются автоматически.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤3🤔2
Spring Boot: на этапе разработки используй spring.main.lazy-initialization=true, чтобы ускорить старт приложения.
По умолчанию Spring Boot жадно инициализирует все бины на старте. В дев-окружении это значит:
1. Дольше стартует, особенно в больших проектах
2. Приходится ждать загрузки бинов, которые тебе прямо сейчас не нужны
Чтобы этого избежать, в
Но в проде важно оставить дефолтное поведение, потому что:
1. Ошибки старта ловятся раньше
2. Все компоненты сразу готовы принимать запросы
👉 Java Portal
По умолчанию Spring Boot жадно инициализирует все бины на старте. В дев-окружении это значит:
1. Дольше стартует, особенно в больших проектах
2. Приходится ждать загрузки бинов, которые тебе прямо сейчас не нужны
Чтобы этого избежать, в
application.properties поставь:spring.main.lazy-initialization=true
Но в проде важно оставить дефолтное поведение, потому что:
1. Ошибки старта ловятся раньше
2. Все компоненты сразу готовы принимать запросы
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤3
This media is not supported in your browser
VIEW IN TELEGRAM
Сommand completion (..) расширяет обычный code completion. Помимо автодополнения API и postfix completion, автодополнение кода теперь включает и команды. Чтобы отфильтровать список только до команд, используйте
👉 Java Portal
.. Список поддерживает поиск, чтобы быстрее находить нужное.Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Java tip : старайся не шарить данные между потоками.
✅ Используй immutable-объекты
✅ Или пусть потоки общаются сообщениями, не лезя напрямую в общий state и не мутируя его
👉 Java Portal
// With immutable objects:
record Book(String title, int price) {} //Immutable
public class BookJob implements Runnable {
private final Book book;
....//constructor
@Override
public void run() {
System.out.println(book.title() + " " + book.price());
}
}
// Exchanging messages:
...
new Thread(() -> {
try {
queue.put("mess1");
} catch (InterruptedException e) {}
}).start();
...
new Thread(() -> {
try {
String mess = queue.take();
} catch (InterruptedException e) {}
}).start();
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
10 золотых правил чистого кода:
1. Избегай магических чисел и строк
2. Используй осмысленные, говорящие имена
3. Предпочитай ранние
4. Избегай длинных списков параметров
5. Делай функции маленькими и сфокусированными
6. Соблюдай DRY (Don’t Repeat Yourself) — не дублируй код
7. Применяй принцип KISS (Keep It Simple, Stupid) — делай проще
8. Отдавай предпочтение композиции, а не наследованию
9. Комментируй только там, где это действительно необходимо
10. Пиши хорошие сообщения к коммитам
Какие еще правила чистого кода ты бы добавил в этот список?
👉 Java Portal
1. Избегай магических чисел и строк
2. Используй осмысленные, говорящие имена
3. Предпочитай ранние
return вместо глубокой вложенности4. Избегай длинных списков параметров
5. Делай функции маленькими и сфокусированными
6. Соблюдай DRY (Don’t Repeat Yourself) — не дублируй код
7. Применяй принцип KISS (Keep It Simple, Stupid) — делай проще
8. Отдавай предпочтение композиции, а не наследованию
9. Комментируй только там, где это действительно необходимо
10. Пиши хорошие сообщения к коммитам
Какие еще правила чистого кода ты бы добавил в этот список?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19🔥6
Совет по Java: если нужна максимально хорошая производительность в общем случае, бери HashMap как реализацию Map.
✅
🪲 Он не потокобезопасный (если нужна thread-safety, используй
Пример:
👉 Java Portal
HashMap внутри реализован как хеш-таблица, и в среднем put(), get() и remove() работают за O(1).ConcurrentHashMap).Пример:
Map<String, Integer> ages = new HashMap<>();
// Добавляем данные
ages.put("Michael", 31);
ages.put("Lisa", 25);
ages.put("Alice", 42);
// Поиск
System.out.println("Возраст Lisa: " + ages.get("Lisa"));
// Удаление
ages.remove("Alice");
// Итерация
for (Map.Entry<String, Integer> entry : ages.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤4💊1
This media is not supported in your browser
VIEW IN TELEGRAM
Если ты изучаешь Java или хочешь прокачать навыки, обрати внимание на JBook — это интерактивная книга по Java, доступная прямо на GitHub.
Что внутри:
🔸 Подробное объяснение основ языка Java;
🔸 Примеры кода с пояснениями;
🔸 Упражнения для закрепления знаний;
🔸 Поддержка Jupyter Notebook + Java (IJava kernel) — можно запускать код прямо в браузере
GitHub: https://github.com/qcha/JBook
👉 Java Portal
Что внутри:
GitHub: https://github.com/qcha/JBook
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9🔥4
Java-совет: начиная с Java 14 можно использовать switch-выражения, чтобы писать многоветвистую логику короче и чище.
👉 Java Portal
// Old way:
String season;
switch (month) {
case 12:
case 1:
case 2:
season = "Winter";
break;
case 3:
case 4:
case 5:
season = "Spring";
break;
default:
season = "Invalid";
}
// New switch expression:
String season = switch (month) {
case 12, 1, 2 -> "Winter";
case 3, 4, 5 -> "Spring";
default -> "Invalid";
};
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17❤7
This media is not supported in your browser
VIEW IN TELEGRAM
Batch Processing vs Stream Processing: в чем разница?
Batch processing (пакетная обработка)
▪️ Обрабатывает данные большими порциями (батчами) по расписанию.
▪️ Отлично подходит для исторических данных, хранилищ (DWH) и аналитики.
▪️ Примеры: расчёт зарплаты, периодические отчёты, ETL/ELT джобы.
Плюсы: эффективно на больших объёмах, дешевле по ресурсам, хорошо оптимизируется под throughput
Минусы: высокая задержка (latency), не подходит для задач, где нужно “прямо сейчас”
⚙️ Инструменты: Apache Hadoop, Apache Spark, AWS Glue
Stream processing (потоковая обработка)
▪️ Обрабатывает данные непрерывно, по мере поступления.
▪️ Используется для real-time аналитики, антифрода, мониторинга “вживую”.
▪️ Примеры: мониторинг биржи, рекомендации в реальном времени, IoT-датчики.
Плюсы: низкая задержка, инсайты в реальном времени, реактивные системы
Минусы: сложнее в реализации и поддержке, требует высокой доступности и масштабируемости
⚙️ Инструменты: Apache Kafka, Apache Flink, Apache Storm, Spark Streaming
Во многих современных системах делают гибрид: batch для хранения и аналитики, stream для реакций и real-time сигналов.
👉 Java Portal
Batch processing (пакетная обработка)
Плюсы: эффективно на больших объёмах, дешевле по ресурсам, хорошо оптимизируется под throughput
Минусы: высокая задержка (latency), не подходит для задач, где нужно “прямо сейчас”
Stream processing (потоковая обработка)
Плюсы: низкая задержка, инсайты в реальном времени, реактивные системы
Минусы: сложнее в реализации и поддержке, требует высокой доступности и масштабируемости
Во многих современных системах делают гибрид: batch для хранения и аналитики, stream для реакций и real-time сигналов.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3🔥3
Spring Boot: лучше не использовать wildcard-исключения для транзитивных зависимостей в POM-файлах, потому что они могут прятать проблемы.
Wildcard-исключения просто убирают симптом и маскируют реальную причину: несовпадение версий.
👉 Java Portal
Wildcard-исключения просто убирают симптом и маскируют реальную причину: несовпадение версий.
<!-- Так лучше НЕ делать: wildcard-исключение (фактически “вырубаем всё”) -->
<exclusions>
<exclusion>
<!-- * = любой groupId -->
<groupId>*</groupId>
<!-- * = любой artifactId -->
<artifactId>*</artifactId>
</exclusion>
</exclusions>
<!-- Лучше: исключать конкретную транзитивную зависимость явно -->
<exclusion>
<!-- точный groupId зависимости, которую исключаем -->
<groupId>org.apache.tomcat.embed</groupId>
<!-- точный artifactId зависимости, которую исключаем -->
<artifactId>tomcat-embed-websocket</artifactId>
</exclusion>
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍3
Project Panama: как Java научилась говорить на C! (Часть 1)
Как безопасно и эффективно вызывать C-функции из Java? Благодаря Project Panama — новому API из OpenJDK — это стало возможно без использования JNI.
👉 Java Portal
Как безопасно и эффективно вызывать C-функции из Java? Благодаря Project Panama — новому API из OpenJDK — это стало возможно без использования JNI.
Please open Telegram to view this post
VIEW IN TELEGRAM
Хабр
Project Panama: как Java научилась говорить на C! (Часть 1)
Как безопасно и эффективно вызывать C-функции из Java? Благодаря Project Panama — новому API из OpenJDK — это стало возможно без использования JNI. В новом переводе от команды Spring АйО познакомимся...
🤯4❤2
This media is not supported in your browser
VIEW IN TELEGRAM
Защищаю своё Spring Boot Java-приложение, которое использует 64 ГБ оперативной памяти, чтобы вернуть { "status": "ok" }
👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
😁31
Spring Boot: держи контроллеры тонкими, логику выноси в сервисы.
Главная задача контроллера, по сути, только разрулить HTTP-часть.
Плохой пример: бизнес-правила запихнуты в контроллер, типа проверки остатков и лимита заказа:
👉 Java Portal
Главная задача контроллера, по сути, только разрулить HTTP-часть.
Плохой пример: бизнес-правила запихнуты в контроллер, типа проверки остатков и лимита заказа:
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private OrderRepository orderRepository;
@Autowired
private ProductRepository productRepository;
@PostMapping
public ResponseEntity<?> createOrder(@RequestBody CreateOrderRequest request) {
// Validation logic
if (request.getProductId() == null || request.getQuantity() <= 0) {
return ResponseEntity
.badRequest()
.body("Invalid request");
}
// Business logic
Product product = productRepository.findById(request.getProductId())
.orElse(null);
if (product == null) {
return ResponseEntity
.status(HttpStatus.NOT_FOUND)
.body("Product not found");
}
if (product.getStock() < request.getQuantity()) {
return ResponseEntity
.badRequest()
.body("Not enough stock");
}
BigDecimal totalPrice = product.getPrice()
.multiply(BigDecimal.valueOf(request.getQuantity()));
if (totalPrice.compareTo(new BigDecimal("10000")) > 0) {
return ResponseEntity
.badRequest()
.body("Order limit exceeded");
}
// Persistence + transaction logic
product.setStock(product.getStock() - request.getQuantity());
productRepository.save(product);
Order order = new Order();
order.setProduct(product);
order.setQuantity(request.getQuantity());
order.setTotalPrice(totalPrice);
order.setCreatedAt(LocalDateTime.now());
orderRepository.save(order);
return ResponseEntity
.status(HttpStatus.CREATED)
.body(order.getId());
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6
Как снизить хвостовые задержки в Java с помощью ZGC: читать
Он заметно снижает хвостовые задержки (p999/p9999) по сравнению с G1 за счет микропауз, но платит за это повышенным CPU и при нехватке процессора может упираться в allocation stalls, поэтому включать его стоит только после замеров на своей нагрузке.
👉 Java Portal
Он заметно снижает хвостовые задержки (p999/p9999) по сравнению с G1 за счет микропауз, но платит за это повышенным CPU и при нехватке процессора может упираться в allocation stalls, поэтому включать его стоит только после замеров на своей нагрузке.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6
Rate limiting в системном дизайне: один пользователь или сервис не должен слишком часто дергать API и завалить его.
В Spring Boot для этого можно использовать библиотеку Bucket4j и сделать Rate Limit Filter.
Она умеет:
▪️ защищать от примитивных DDoS-атак
▪️ отсеивать кривых клиентов, которые шлют запросы в цикле
▪️ ограничивать число запросов за единицу времени
▪️ делать доступ чуть более честным: понемногу всем, а не все одному
Очень просто, быстро и потокобезопасно.
▪️ На каждый запрос проверяет, есть ли в кэше ключ клиента (например IP). Если нет, создает для него bucket с токенами.
▪️ Каждый раз пытается забрать из bucket один токен, то есть право выполнить запрос.
▪️ Если токен в bucket есть, проходишь. Если токены закончились, получаешь HTTP 429 и ждешь пополнения.
Заметки:
-> request.getRemoteAddr() ищет корректный способ получить IP клиента, возможно через request.getHeader("X-Forwarded-For")
-> new ConcurrentHashMap<>() сам по себе не чистится, продумай, как долго хранить данные и как их вычищать, если запросов много
-> лимит задается одинаковый для всех эндпоинтов. Часто у разных API разная нагрузка, поэтому логично ставить разные лимиты (по URL, HTTP-методу или типу операции)
-> refillGreedy() это всего лишь один из вариантов пополнения токенов. Есть и другие стратегии (плавное пополнение, фиксированные интервалы), которые дают более точный контроль нагрузки
-> вынеси все настройки в application.yaml, чтобы менять лимиты без правок кода
Простая реализация, чтобы понять, как работает библиотека, приложена
👉 Java Portal
В Spring Boot для этого можно использовать библиотеку Bucket4j и сделать Rate Limit Filter.
Она умеет:
Очень просто, быстро и потокобезопасно.
Заметки:
-> request.getRemoteAddr() ищет корректный способ получить IP клиента, возможно через request.getHeader("X-Forwarded-For")
-> new ConcurrentHashMap<>() сам по себе не чистится, продумай, как долго хранить данные и как их вычищать, если запросов много
-> лимит задается одинаковый для всех эндпоинтов. Часто у разных API разная нагрузка, поэтому логично ставить разные лимиты (по URL, HTTP-методу или типу операции)
-> refillGreedy() это всего лишь один из вариантов пополнения токенов. Есть и другие стратегии (плавное пополнение, фиксированные интервалы), которые дают более точный контроль нагрузки
-> вынеси все настройки в application.yaml, чтобы менять лимиты без правок кода
Простая реализация, чтобы понять, как работает библиотека, приложена
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8🔥4
This media is not supported in your browser
VIEW IN TELEGRAM
Совет для IntelliJ: Alt+Enter можно использовать, чтобы быстро чинить ошибки и предупреждения, но список вариантов там довольно ограничен.
Вместо этого используй автодополнение команд (..), чтобы выполнять нужные действия прямо в редакторе.
👉 Java Portal
Вместо этого используй автодополнение команд (..), чтобы выполнять нужные действия прямо в редакторе.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤3🔥2
Spring Boot: не используй
✗ Помечая связь как
✗ В этом примере каждый раз, когда ты загружаешь
✗ И ещё: если не делать явный fetch, получаешь классический эффект N+1:
1. Один запрос на все
2. По одному запросу на каждый
👉 Java Portal
FetchType.EAGER, если реально нет необходимости.✗ Помечая связь как
EAGER, ты говоришь ORM подгружать её каждый раз вместе с сущностью, даже если ты вообще не обращаешься к этой связи (не вызываешь геттер/метод отношения).✗ В этом примере каждый раз, когда ты загружаешь
Order, ORM автоматически подтянет и Customer:@Entity
class Order {
@ManyToOne(fetch = FetchType.EAGER)
private Customer customer;
}
✗ И ещё: если не делать явный fetch, получаешь классический эффект N+1:
1. Один запрос на все
Orders2. По одному запросу на каждый
Order для CustomersPlease open Telegram to view this post
VIEW IN TELEGRAM
👍7❤2