MapStruct: быстрый и безопасный маппинг объектов
⚙️ Как это работает
MapStruct анализирует названия полей в исходном (source) и целевом (target) классах. Если поля совпадают по названию и типу, он автоматически создаёт код для их преобразования.
Когда названия полей не совпадают, нужно явно указать соответствие с помощью аннотации @Mapping:
— source — поле в исходном классе
— target — поле в целевом классе
⌛ Как начать
1. Добавьте зависимости: mapstruct, mapstruct-processor
2. Выберите интерфейс или абстрактный класс и определите методы для преобразования объектов
3. Используйте маппер. В Spring-приложении маппер можно заинжектить как обычный бин.
❓ Абстрактный класс или интерфейс
Документация MapStruct приводит примеры с интерфейсами, но библиотека поддерживает и абстрактные классы. Выбор за вами.
Интерфейс — MapStruct сам создаёт реализацию:
Абстрактный класс — позволяет добавлять кастомную логику:
📌 Имена методов можно задавать любые. MapStruct анализирует типы аргументов и возвращаемых значений, чтобы понять, что куда маппить.
🔥 Интеграция со Spring
При использовании componentModel = "spring" маппер регистрируется как Spring-бин. Что позволяет заинжектить маппер:
💡 Где применять
— Маппинг DTO ↔️ Entity в Spring-приложениях
— Конвертация данных между разными объектами
— Обработка вложенных структур и коллекций
💬 Используете MapStruct в своих проектах? Делитесь опытом
✅ Java библиотека #java
MapStruct анализирует названия полей в исходном (source) и целевом (target) классах. Если поля совпадают по названию и типу, он автоматически создаёт код для их преобразования.
Когда названия полей не совпадают, нужно явно указать соответствие с помощью аннотации @Mapping:
— source — поле в исходном классе
— target — поле в целевом классе
@Mapping(source = "fullName", target = "name")
UserDTO toDTO(User user);
1. Добавьте зависимости: mapstruct, mapstruct-processor
2. Выберите интерфейс или абстрактный класс и определите методы для преобразования объектов
3. Используйте маппер. В Spring-приложении маппер можно заинжектить как обычный бин.
Документация MapStruct приводит примеры с интерфейсами, но библиотека поддерживает и абстрактные классы. Выбор за вами.
Интерфейс — MapStruct сам создаёт реализацию:
@Mapper(componentModel = "spring")
public interface UserMapper {
@Mapping(source = "fullName", target = "name")
UserDTO toDTO(User user);
}
Абстрактный класс — позволяет добавлять кастомную логику:
@Mapper(componentModel = "spring")
public abstract class UserMapper {
@Mapping(source = "fullName", target = "name")
public abstract UserDTO toDTO(User user);
public String mapAgeToString(int age) {
return age + " лет";
}
}
📌 Имена методов можно задавать любые. MapStruct анализирует типы аргументов и возвращаемых значений, чтобы понять, что куда маппить.
При использовании componentModel = "spring" маппер регистрируется как Spring-бин. Что позволяет заинжектить маппер:
@Service
public class UserService {
private final UserMapper userMapper;
public UserService(UserMapper userMapper) {
this.userMapper = userMapper;
}
public UserDTO convertUser(User user) {
return userMapper.toDTO(user);
}
}
— Маппинг DTO ↔️ Entity в Spring-приложениях
— Конвертация данных между разными объектами
— Обработка вложенных структур и коллекций
Please open Telegram to view this post
VIEW IN TELEGRAM
👍29❤9🔥5
Please open Telegram to view this post
VIEW IN TELEGRAM
👍23🔥6❤4
Что такое Virtual Threads
В Java 21 появилась революционная фича — виртуальные потоки (Virtual Threads). Это лёгкие потоки, которые управляются самой JVM, а не операционной системой. Они позволяют создавать тысячи и даже миллионы потоков без значительных затрат ресурсов.
⚙️ Как это работает
Обычные потоки (Thread) привязаны к потокам ОС и работают с тяжёлым контекстным переключением (context switching).
Virtual Threads — это user-mode потоки, управляемые JVM, а не ОС, поэтому они могут эффективно мультиплексироваться на ограниченном количестве платформенных потоков.
🟢 Ключевая особенность
Виртуальные потоки не блокируют платформенные потоки, когда выполняют блокирующие операции ввода-вывода (I/O). Они просто освобождают платформенный поток и продолжают выполнение, когда ресурс снова доступен.
Пример
Этот код создаёт 10 000 потоков, но JVM будет эффективно управлять ими без перегрузки системы.
✔️ Где применять
— Высоконагруженные I/O задачи.
— Обработка веб-запросов без перегрузки ресурсов.
— Микросервисы, которые взаимодействуют с API.
— Асинхронные операции, где ранее использовали CompletableFuture.
❌ Когда НЕ стоит использовать
— При вычислениях на процессоре.
— При работе с кодом, который активно использует synchronized.
— При глубокой интеграции со сторонними библиотеками, которые не оптимизированы под виртуальные потоки.
ℹ️ Преимущества и недостатки
— Плюсы: миллионы потоков без overhead, упрощённый асинхронный код без CompletableFuture, меньше блокировок и выше производительность, полная совместимость со старыми API.
— Минусы: может ломать старый код с synchronized, не даёт преимуществ для CPU-bound задач, требует оптимизации библиотек под Virtual Threads.
Virtual Threads — мощный инструмент, который не заменяет потоки ОС, но отлично подходит для массовых I/O-задач. Если у вас есть сервис, работающий с сетью, базами данных или API — пора внедрять Virtual Threads.
❓ Делитесь опытом работы с виртуальными потоками
✅ Java библиотека #java
В Java 21 появилась революционная фича — виртуальные потоки (Virtual Threads). Это лёгкие потоки, которые управляются самой JVM, а не операционной системой. Они позволяют создавать тысячи и даже миллионы потоков без значительных затрат ресурсов.
Обычные потоки (Thread) привязаны к потокам ОС и работают с тяжёлым контекстным переключением (context switching).
Virtual Threads — это user-mode потоки, управляемые JVM, а не ОС, поэтому они могут эффективно мультиплексироваться на ограниченном количестве платформенных потоков.
Виртуальные потоки не блокируют платформенные потоки, когда выполняют блокирующие операции ввода-вывода (I/O). Они просто освобождают платформенный поток и продолжают выполнение, когда ресурс снова доступен.
Пример
public class VirtualThreadsDemo {
public static void main(String[] args) throws InterruptedException {
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
IntStream.range(0, 10_000).forEach(i ->
executor.submit(() -> {
System.out.println("Task " + i + " running on " + Thread.currentThread());
Thread.sleep(100);
})
);
}
}
}Этот код создаёт 10 000 потоков, но JVM будет эффективно управлять ими без перегрузки системы.
— Высоконагруженные I/O задачи.
— Обработка веб-запросов без перегрузки ресурсов.
— Микросервисы, которые взаимодействуют с API.
— Асинхронные операции, где ранее использовали CompletableFuture.
— При вычислениях на процессоре.
— При работе с кодом, который активно использует synchronized.
— При глубокой интеграции со сторонними библиотеками, которые не оптимизированы под виртуальные потоки.
— Плюсы: миллионы потоков без overhead, упрощённый асинхронный код без CompletableFuture, меньше блокировок и выше производительность, полная совместимость со старыми API.
— Минусы: может ломать старый код с synchronized, не даёт преимуществ для CPU-bound задач, требует оптимизации библиотек под Virtual Threads.
Virtual Threads — мощный инструмент, который не заменяет потоки ОС, но отлично подходит для массовых I/O-задач. Если у вас есть сервис, работающий с сетью, базами данных или API — пора внедрять Virtual Threads.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍27🔥8❤6
Компилируем компилятор или ускоряем javac вдвое
Ну блин короче :-)
Знаете ли вы, куда уходит время и ресурсы при сборке проектов на Java? Сейчас покажем и расскажем, как сберечь время, нервы и кофе.
Мы ускорили javac вдвое и теперь можно экономить на сборке.
Читать статью
Ну блин короче :-)
Знаете ли вы, куда уходит время и ресурсы при сборке проектов на Java? Сейчас покажем и расскажем, как сберечь время, нервы и кофе.
Мы ускорили javac вдвое и теперь можно экономить на сборке.
Читать статью
VK
Компилируем компилятор или ускоряем javac вдвое
Ну, блин, короче :-)
🔥7👍3❤2
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤4🔥2
☄️ Интеграционное тестирование | Spring Boot + Yandex SourceCraft + Amplicode + Docker Compose Starter
В новом видео вы узнаете, как писать интеграционные тесты быстро и эффективно, совмещая сильные стороны нескольких инструментов.
Мы покажем, как использовать генерацию кода от Amplicode учитывающую контекст всего приложения и дополнить её точечной генерацией от Yandex SourceCraft Code Assistant, а также быстро настроить окружение для тестов с помощью не так давно появившегося Docker Compose стартера.
⚡️СМОТРЕТЬ НА YOUTUBE
⚡️СМОТРЕТЬ В VK ВИДЕО
⚡️СМОТРЕТЬ НА RUTUBE
#реклама
О рекламодателе
В новом видео вы узнаете, как писать интеграционные тесты быстро и эффективно, совмещая сильные стороны нескольких инструментов.
Мы покажем, как использовать генерацию кода от Amplicode учитывающую контекст всего приложения и дополнить её точечной генерацией от Yandex SourceCraft Code Assistant, а также быстро настроить окружение для тестов с помощью не так давно появившегося Docker Compose стартера.
⚡️СМОТРЕТЬ НА YOUTUBE
⚡️СМОТРЕТЬ В VK ВИДЕО
⚡️СМОТРЕТЬ НА RUTUBE
#реклама
О рекламодателе
YouTube
Интеграционное тестирование | Spring Boot + Yandex SourceCraft + Amplicode + Docker Compose Starter
#Amplicode #Spring #SpringBoot #SpringData #SpringWeb #JPA #Hibernate #MapStruct #Docker #DockerCompose #IntelliJ #CRUD #REST #REESTful #Java #Kotlin
В новом видео вы узнаете, как писать интеграционные тесты быстро и эффективно, совмещая сильные стороны…
В новом видео вы узнаете, как писать интеграционные тесты быстро и эффективно, совмещая сильные стороны…
🔥5👍4❤3
Лайфхак: оптимизируем DTO с record
Вместо обычных POJO-классов для DTO используйте record (Java 14+). Меньше кода, больше удобства.
Record автоматически создает иммутабельный класс с приватными финальными полями, конструктором, геттерами, а также переопределенными методами toString(), equals() и hashCode().
❌ Избыточно
✔️ Красиво и лаконично
✅ Java библиотека #java
Вместо обычных POJO-классов для DTO используйте record (Java 14+). Меньше кода, больше удобства.
Record автоматически создает иммутабельный класс с приватными финальными полями, конструктором, геттерами, а также переопределенными методами toString(), equals() и hashCode().
public class User {
private final String name;
private final int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
@Override
public String toString() {
return "User{name='" + name + "', age=" + age + "}";
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
User user = (User) obj;
return age == user.age && Objects.equals(name, user.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
} public record User(String name, int age) {}Please open Telegram to view this post
VIEW IN TELEGRAM
1👍34❤7🔥6☃1
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤2🔥2
Паттерн Состояние (State)
State — это поведенческий паттерн, который позволяет объекту менять свое поведение в зависимости от внутреннего состояния. Вместо множества условных операторов (if-else или switch), каждое состояние представляется отдельным классом, а сам объект делегирует управление текущему состоянию.
Когда использовать
🟢 Когда у объекта есть несколько состояний, и его поведение зависит от текущего состояния.
🟢 Когда код с if-else или switch начинает разрастаться и усложняет поддержку.
🟢 Когда необходимо четко разделить логику различных состояний и сделать систему более гибкой.
Преимущества
1️⃣ Избавляет от множества if-else конструкций, делая код более читаемым и поддерживаемым.
2️⃣ Облегчает добавление новых состояний без изменения существующего кода.
3️⃣ Обеспечивает инкапсуляцию логики для каждого состояния, упрощая тестирование и модификации.
Недостатки
1️⃣ Может усложнить код, если состояний слишком мало, а логика простая.
2️⃣ Увеличивает количество классов, так как каждое состояние реализуется отдельно.
3️⃣ Вводит дополнительные связи между классами состояний и контекстом.
State — мощный инструмент, когда объекту нужно динамически изменять свое поведение. Он особенно полезен в конечных автоматах, обработке пользовательских действий и моделировании процессов с четко определенными шагами.
✅ Java библиотека #java
State — это поведенческий паттерн, который позволяет объекту менять свое поведение в зависимости от внутреннего состояния. Вместо множества условных операторов (if-else или switch), каждое состояние представляется отдельным классом, а сам объект делегирует управление текущему состоянию.
Когда использовать
Преимущества
Недостатки
State — мощный инструмент, когда объекту нужно динамически изменять свое поведение. Он особенно полезен в конечных автоматах, обработке пользовательских действий и моделировании процессов с четко определенными шагами.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤8🔥7
Forwarded from Java Guru 🤓
У класса есть два конструктора с разными модификаторами доступа, и один из них помечен @Autowired, какой конструктор будет выбран для инжекта зависимостей?
Anonymous Quiz
5%
Spring вызовет оба конструктора
28%
Spring всегда использует конструктор с @Autowired, независимо от модификатора
22%
Если модификатор доступа конструктора с @Autowired - private, Spring выбросит исключение
32%
Spring выберет тот конструктор, у которого модификатор доступа public, даже если нет @Autowired
12%
Код не скомпилируется
🔥7👍5❤3🤩1
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥4❤3
Что такое микросервисы?
Микросервисы — этоархитектурный стиль, при котором приложение разбивается на небольшие, независимые сервисы. Каждый сервис отвечает за определённую бизнес-логику, имеет собственную базу данных (или логически обособленное хранилище) и взаимодействует с другими сервисами через API (обычно REST или gRPC).
🟢 Ключевые принципы
—Можно обновлять и масштабировать отдельные сервисы без затрагивания всей системы.
—Каждый сервис выполняет свою узкую задачу.
—У сервиса свои изолированные данные, код и зависимости.
—Сервисы общаются через HTTP, AMQP, Kafka и другие механизмы.
✅ Java библиотека #java
Микросервисы — это
—
—
—
—
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19❤3🔥2
Java Streams: Основные методы для чистого и эффективного кода!
Java Streams предлагают множество методов для упрощения манипуляций с данными и повышения читаемости кода.
Вот краткое руководство с примерами:
Освойте эти методы, чтобы писать более чистый и эффективный код на Java!💡
✅ Java библиотека #java
Java Streams предлагают множество методов для упрощения манипуляций с данными и повышения читаемости кода.
Вот краткое руководство с примерами:
Освойте эти методы, чтобы писать более чистый и эффективный код на Java!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤4🔥3
Ядро Vert.x содержит достаточно низкоуровневую функциональность, включая поддержку HTTP, TCP, доступ к файловой системе и различные другие возможности. Можно использовать Vert.x непосредственно в своих приложениях.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤5🔥5
▪️ JDK (Java Development Kit) — это набор инструментов для разработки приложений на Java. Включает компилятор, библиотеки и утилиты, необходимые для написания и сборки кода.
▪️ JRE (Java Runtime Environment) — среда выполнения, которая позволяет запускать Java-приложения. Включает в себя JVM и стандартные библиотеки, но без инструментов разработки.
▪️ JVM (Java Virtual Machine) — виртуальная машина, которая исполняет байт-код, сгенерированный при компиляции. Именно JVM делает Java переносимой, так как позволяет запускать программы на разных платформах.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍4🔥3
Абстракция в Java
Абстракция — это способность выделять существенные характеристики объекта и упускать несущественные.
Абстракция позволяет сосредоточиться на важных свойствах и поведении объекта, скрыв детали реализации.
В Java абстракция реализуется с помощью абстрактных классов и интерфейсов.
Абстрактный класс содержит абстрактные методы без реализации. Подклассы обязаны реализовать эти методы.
Интерфейс задает «контракт», описывая поведение классов без деталей реализации. Классы реализуют интерфейс.
Реализация абстракции требует тщательного анализа предметной области и выделения общих свойств объектов.
✅ Java библиотека #java
Абстракция — это способность выделять существенные характеристики объекта и упускать несущественные.
Абстракция позволяет сосредоточиться на важных свойствах и поведении объекта, скрыв детали реализации.
В Java абстракция реализуется с помощью абстрактных классов и интерфейсов.
Абстрактный класс содержит абстрактные методы без реализации. Подклассы обязаны реализовать эти методы.
Интерфейс задает «контракт», описывая поведение классов без деталей реализации. Классы реализуют интерфейс.
Реализация абстракции требует тщательного анализа предметной области и выделения общих свойств объектов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤5🔥3
Sorted set
SortedSet — это интерфейс в Java Collection Framework, который предоставляет упорядочение элементов в множестве. Элементы упорядочиваются с помощью их естественного порядка или с помощью компаратора, который обычно предоставляется при создании отсортированного множества.
SortedSet имеет несколько дополнительных операций, которые позволяют использовать упорядочение элементов:
— first() и last() возвращают первый и последний элементы в множестве соответственно.
— headSet(), tailSet() и subSet() возвращают подмножества элементов, которые находятся до, после или между заданными элементами соответственно.
В этом примере мы создаем TreeSet (класс, который реализует SortedSet) и добавляем в него несколько строк. Поскольку строки реализуют интерфейс Comparable, они упорядочиваются в алфавитном порядке. Затем мы используем различные методы SortedSet для получения первого и последнего элементов, а также подмножеств элементов.
✅ Java библиотека #java
SortedSet — это интерфейс в Java Collection Framework, который предоставляет упорядочение элементов в множестве. Элементы упорядочиваются с помощью их естественного порядка или с помощью компаратора, который обычно предоставляется при создании отсортированного множества.
SortedSet имеет несколько дополнительных операций, которые позволяют использовать упорядочение элементов:
— first() и last() возвращают первый и последний элементы в множестве соответственно.
— headSet(), tailSet() и subSet() возвращают подмножества элементов, которые находятся до, после или между заданными элементами соответственно.
В этом примере мы создаем TreeSet (класс, который реализует SortedSet) и добавляем в него несколько строк. Поскольку строки реализуют интерфейс Comparable, они упорядочиваются в алфавитном порядке. Затем мы используем различные методы SortedSet для получения первого и последнего элементов, а также подмножеств элементов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤4🔥4
Временное хранение часто используемых данных в памяти для сокращения времени доступа.
- Получение данных из кэша (например, Redis, Memcached) гораздо быстрее, чем запросы к базе данных.
- Кэширование статических ресурсов (изображения, CSS, JS) снижает необходимость многократного запроса их с исходного сервера.
Распределение входящего сетевого трафика между несколькими серверами для предотвращения перегрузки одного сервера.
- Балансировка нагрузки предотвращает перегрузку одного сервера, что может замедлить отклик.
- Обеспечивает отказоустойчивость, гарантируя обработку запросов даже при выходе некоторых серверов из строя.
Обработка задач в фоновом режиме без блокировки основного потока выполнения, что позволяет системе продолжать обработку других запросов.
- Пользователям не нужно ждать завершения длительных задач (например, отправки электронной почты или обработки изображений).
Разделение базы данных на более мелкие части (шарды), которые можно распределить между несколькими серверами.
- Запросы могут выполняться параллельно на нескольких шардах, сокращая время получения данных.
- Распределение нагрузки предотвращает перегрузку одного экземпляра базы данных.
Распределенные сети серверов, которые доставляют веб-контент на основе географического расположения пользователя.
- Контент предоставляется с серверов, находящихся ближе к пользователю, сокращая физическое расстояние, которое данные должны преодолеть.
- Кэширует статический и динамический контент для ускорения его доставки.
Оптимизация работы баз данных через индексацию, оптимизацию запросов и правильное проектирование схемы.
- Ускоряет получение данных, позволяя базе данных находить записи без сканирования всех таблиц.
Сокращение числа промежуточных шагов, через которые проходят данные, и выбор эффективных протоколов связи.
- Каждый сетевой переход добавляет задержку; их минимизация ускоряет передачу данных.
Разделение задач на несколько параллельно выполняемых потоков или процессов для увеличения скорости выполнения операций.
- Параллельное выполнение задач позволяет обрабатывать данные быстрее за счёт разделения работы на несколько потоков.
- Более эффективное использование ресурсов процессора, что снижает задержки при выполнении сложных операций.
Предугадывание будущих запросов данных и их предварительная загрузка.
- Данные уже доступны, когда они запрашиваются, устраняя задержки при получении.
- Особенно эффективно в приложениях с предсказуемыми шаблонами доступа.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤7🔥4
CompletableFuture
CompletableFuture в пакете java.util.concurrent является классом, который предоставляет мощный и гибкий подход к асинхронному программированию. Он позволяет выполнять асинхронные операции и обрабатывать их результаты, комбинировать несколько операций и управлять зависимостями между ними.
Помимо операций, представленных на изображении, CompletableFuture также предоставляет множество других методов для работы с асинхронными операциями, таких как thenApply(), thenCompose(), thenCombine(), exceptionally() и другие, которые позволяют обрабатывать результаты, комбинировать операции, обрабатывать исключения и многое другое. Это делает CompletableFuture мощным инструментом для асинхронного программирования.
✅ Java библиотека #java
CompletableFuture в пакете java.util.concurrent является классом, который предоставляет мощный и гибкий подход к асинхронному программированию. Он позволяет выполнять асинхронные операции и обрабатывать их результаты, комбинировать несколько операций и управлять зависимостями между ними.
Помимо операций, представленных на изображении, CompletableFuture также предоставляет множество других методов для работы с асинхронными операциями, таких как thenApply(), thenCompose(), thenCombine(), exceptionally() и другие, которые позволяют обрабатывать результаты, комбинировать операции, обрабатывать исключения и многое другое. Это делает CompletableFuture мощным инструментом для асинхронного программирования.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥4❤3
Агрегация: что это и когда использовать?
Агрегация — это тип отношения между классами, при котором один класс "владеет" экземпляром другого, но их жизненные циклы не зависят друг от друга. Это «слабое» отношение, так как объект одного класса может существовать независимо от объекта другого.
Пример:
🟢 В этом примере класс Car агрегирует объект Engine, но двигатель может существовать сам по себе, вне машины.
Агрегацию стоит использовать, когда один объект логически принадлежит другому, но их существование не связано напрямую. Например, библиотека и книги, где книги могут существовать без самой библиотеки
✅ Java библиотека #java
Агрегация — это тип отношения между классами, при котором один класс "владеет" экземпляром другого, но их жизненные циклы не зависят друг от друга. Это «слабое» отношение, так как объект одного класса может существовать независимо от объекта другого.
Пример:
class Engine {
void start() {
System.out.println("Двигатель запущен");
}
}
class Car {
private Engine engine;
Car(Engine engine) {
this.engine = engine;
}
void startCar() {
engine.start();
System.out.println("Машина поехала");
}
}
public class Main {
public static void main(String[] args) {
Engine engine = new Engine(); // Двигатель может существовать отдельно
Car car = new Car(engine);
car.startCar();
}
}Агрегацию стоит использовать, когда один объект логически принадлежит другому, но их существование не связано напрямую. Например, библиотека и книги, где книги могут существовать без самой библиотеки
Please open Telegram to view this post
VIEW IN TELEGRAM
👍31❤7🔥5
Разберем новую фичу Java 21 — Scoped Values, которая пришла на замену (а точнее, в дополнение) к старому доброму ThreadLocal. Если вы когда-либо мучились с ThreadLocal в многопоточных приложениях, этот пост для вас.
ThreadLocal — это механизм для хранения данных, привязанных к потоку. Но у него есть недостатки:
— Данные остаются в потоке, даже когда уже не нужны (утечки памяти).
— Передавать данные в дочерние потоки неудобно.
— Нужно очистить данные вручную.
Scoped Values решают эти проблемы без магии и костылей.
Scoped Values (ScopedValue<T>) создаются только один раз и не изменяются после инициализации. Они передаются вглубь стека вызовов через метод ScopedValue.where(), а не через хранение в потоке, как ThreadLocal.
▪️ Пример кода с потоками
Допустим, есть обработчик запросов, который передает идентификатор пользователя.
— С ThreadLocal код выглядел бы так:
public class ThreadLocalExample {
private static final ThreadLocal<String> USER = new ThreadLocal<>();
public static void main(String[] args) {
USER.set("Alice");
new Thread(ThreadLocalExample::process).start();
}
private static void process() {
System.out.println("User: " + USER.get()); // null: поток не видит значение
}
}ThreadLocal привязан к потоку, а не к области выполнения. Значение не наследуется
Теперь переделаем на Scoped Values:
public class ScopedValueExample {
private static final ScopedValue<String> USER = ScopedValue.newInstance();
public static void main(String[] args) {
ScopedValue.where(USER, "Alice").run(() -> {
new Thread(ScopedValueExample::process).start();
});
}
private static void process() {
System.out.println("User: " + USER.get()); // ✅ Видит "Alice"
}
}Scoped Values автоматически передают значение в новые потоки.
🎯 Где использовать Scoped Values
1. Контекст запроса (Request Context)
В веб-приложениях часто нужно передавать ID запроса или текущего пользователя через слои сервиса.
2. Логирование (Tracing & Logging)
Можно автоматически передавать traceId в логи.
3. Конфигурация временных параметров
Можно временно менять настройки для фрагмента кода.
— ScopedValue быстрее и безопаснее, так как нет необходимости очищать значения вручную.
— Отлично подходит для работы с виртуальными потоками.
— Ограничение: они неизменяемые (Immutable).
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤3🔥3☃2