Java Portal | Программирование
12.9K subscribers
1.22K photos
103 videos
37 files
1.16K links
Присоединяйтесь к нашему каналу и погрузитесь в мир для Java-разработчика

Связь: @devmangx

РКН: https://clck.ru/3H4WUg
Download Telegram
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
😁33
Spring Boot: держи контроллеры тонкими, логику выноси в сервисы.

Главная задача контроллера, по сути, только разрулить 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());
}
}


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6
Как снизить хвостовые задержки в Java с помощью ZGC: читать

Он заметно снижает хвостовые задержки (p999/p9999) по сравнению с G1 за счет микропауз, но платит за это повышенным CPU и при нехватке процессора может упираться в allocation stalls, поэтому включать его стоит только после замеров на своей нагрузке.

👉 Java Portal
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
Please open Telegram to view this post
VIEW IN TELEGRAM
9🔥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
👍83🔥3
Spring Boot: не используй FetchType.EAGER, если реально нет необходимости.

✗ Помечая связь как EAGER, ты говоришь ORM подгружать её каждый раз вместе с сущностью, даже если ты вообще не обращаешься к этой связи (не вызываешь геттер/метод отношения).

✗ В этом примере каждый раз, когда ты загружаешь Order, ORM автоматически подтянет и Customer:

@Entity
class Order {
@ManyToOne(fetch = FetchType.EAGER)
private Customer customer;
}


✗ И ещё: если не делать явный fetch, получаешь классический эффект N+1:

1. Один запрос на все Orders
2. По одному запросу на каждый Order для Customers

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍72
HTTP/2 через TCP против HTTP/3 через QUIC

▪️HTTP/2

Мультиплексирование на уровне HTTP, сериализация на уровне TCP
Общий порядок доставки и контроль перегрузки (TCP)

Одна TCP-сессия

HTTP/2 фреймы (мультиплексированные)

* HEADERS (поток 1)
* HEADERS (поток 3)
* HEADERS (поток 2)
* DATA (поток 1)
* DATA (поток 3)
* DATA (поток 2)

TCP-пакеты: P1, P2, P3, P4, P5

TCP-пакеты смешивают данные из разных потоков
HoL-блокировка в TCP (Head-of-Line): потеря одного пакета блокирует все потоки

Клиент -> Сервер


▪️HTTP/3

Мультиплексирование на транспортном уровне (QUIC)

* Независимые потоки
* Независимый порядок доставки и восстановление

QUIC-соединение (поверх UDP)
QUIC Stream 1: QUIC Packet, QUIC Packet, QUIC Packet
QUIC Stream 2: QUIC Packet, QUIC Packet
QUIC Stream 3: QUIC Packet, QUIC Packet

Нет HoL-блокировки: потеря пакета влияет только на один поток

Клиент -> Сервер


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
Java tip: для точных расчетов времени используй Duration и Instant.

Instant представляет конкретный момент времени в UTC с точностью до наносекунд. Получить можно так: Instant.now().

Duration показывает временной интервал между двумя Instant (в секундах, миллисекундах, наносекундах).

Вот пример:

Instant start = Instant.now();
...
Instant end = Instant.now();

Duration elapsed = Duration.between(start, end);


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Изучение Spring Boot у новичков часто вызывает перегруз 😵‍💫

Поэтому автор сделал Spring Boot Self Learning Guide: короткий гайд с упором на примеры, который покрывает самые часто используемые фичи Spring Boot.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍86🔥4🌚1
Java: с CompletableFuture.allOf(...) можно дождаться завершения сразу нескольких асинхронных задач, без ручной возни с join() по каждой.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Осознанная стоимость абстракций: Autoboxing в современной Java

Мы живём во времена, когда на оперативной памяти для heap Java-приложений почти не экономят, а архитектурные решения, которые ещё недавно можно было назвать расточительными, всё чаще воспринимаются как best practices.

Но не все коту масленица. Благодаря AI-буму, облачным вычислениям и микросервисной архитектуре с сотнями одновременно работающих инстансов, мы можем воочию наблюдать неукротимый рост стоимости оперативной памяти, что обязывает вернуться к рассмотрению принципов её экономии.

В этих условиях привычные абстракции требуют переоценки.

Сегодня я хочу напомнить об одной из самых распространенных в Java — autoboxing — механизме автоматической упаковки примитивных типов в соответствующие объекты-обертки.

Приглашаю вас посмотреть на знакомый Java-код не глазами разработчика, а глазами JVM, сборщика мусора и процессора, и разобраться, как незаметные на уровне синтаксиса решения превращаются в аллокации, давление на GC и раздувание heap.


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8
Совет по Java: используйте List.copyOf(list), чтобы сделать безопасную, неизменяемую копию и избежать случайных изменений.

// До Java 10, чтобы получить независимую неизменяемую копию, приходилось писать так:
List<String> copy = Collections.unmodifiableList(new ArrayList<>(originalList));

// Начиная с Java 10 это можно сделать короче:
List<String> copy = List.copyOf(originalList);

// Любая попытка добавить/удалить элемент выбросит UnsupportedOperationException:
List<String> original = new ArrayList<>();
original.add("A");
original.add("B");
List<String> copy = List.copyOf(original);
copy.add("C"); // UnsupportedOperationException


👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍2
В Spring Boot лучше заменять @Value на @ConfigurationProperties, если хочешь больше контроля и нормальную тестируемость.

▪️Когда ты используешь @Value для кучи параметров, конфиг расползается по проекту: настройки оказываются разбросаны по разным классам, их сложнее поддерживать и тестировать.
▪️@ConfigurationProperties собирает связанные параметры в один класс, позволяет навесить валидацию и делает структуру кода аккуратнее.

Разница по сути такая:

▪️С @Value это строковая инъекция свойств без валидации.
▪️С @ConfigurationProperties это type-safe конфиг с возможностью валидации.

Плюсы:

▪️автокомплит в IDE
▪️валидация
▪️проще тестировать
▪️чище структура кода

В тестах можно просто замокать объект с настройками, вместо того чтобы возиться с отдельными @Value аннотациями на каждом поле.

👉 Java Portal
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10👍2