LinkedList: последовательный доступ через цепочку узлов
Архитектурные основы связного списка
LinkedList реализует список на основе двусвязного списка, где каждый элемент хранится в отдельном узле, содержащем ссылки на данные, предыдущий и следующий узлы.
Эта архитектура fundamentally меняет механизм доступа к элементам:
Последовательный доступ вместо прямого
Линейная временная сложность доступа по индексу
Отсутствие преимуществ пространственной локальности
Дополнительные затраты на обход цепочки
Структура узла и организация данных
Каждый узел LinkedList содержит три ключевых компонента:
Детальный процесс выполнения get(index)
Фаза валидации и стратегического выбора
Как и в ArrayList, первым шагом является проверка корректности индекса:
Проверка границ:
Убеждаются, что индекс находится в диапазоне [0, size-1].
Выбор стратегии обхода:
В зависимости от положения индекса выбирается оптимальная точка начала обхода:
Если индекс находится в первой половине списка (index < size / 2), обход начинается с головы (head)
Если индекс находится во второй половине, обход начинается с хвоста (tail)
Эта оптимизация уменьшает среднее количество шагов обхода с n/2 до n/4.
Фаза последовательного обхода
После выбора начальной точки начинается процесс пошагового перемещения по цепочке узлов:
Инициализация обхода:
Создается временная переменная-указатель, которая устанавливается на начальный узел (head или tail).
Последовательное перемещение:
Для каждого шага обхода:
Если движение от головы, указатель перемещается к следующему узлу (node.next)
Если движение от хвоста, указатель перемещается к предыдущему узлу (node.prev)
Счетчик текущей позиции обновляется
Достижение целевой позиции:
Процесс продолжается до тех пор, пока текущая позиция не совпадет с запрошенным индексом.
Фаза извлечения и возврата результата
Когда целевой узел найден:
Извлечение элемента:
Из поля item целевого узла извлекается хранимый объект.
Возврат результата:
Объект возвращается вызывающему коду. Как и в ArrayList, если узел содержит null, возвращается null.
Производительность и характеристики доступа
Временная сложность
Операция get в LinkedList имеет временную сложность O(n) в худшем случае, где n — количество элементов в списке. Однако благодаря двунаправленному обходу средняя сложность составляет O(n/4) = O(n).
Зависимость от паттерна доступа
Худший случай:
Доступ к элементу в середине большого списка требует обхода примерно n/2 узлов.
Лучший случай:
Доступ к первому или последнему элементу требует всего одного шага.
Средний случай:
При равномерном распределении запросов среднее количество шагов составляет n/4.
Влияние на производительность
Отсутствие кэширования:
Из-за разрозненного расположения узлов в памяти отсутствуют преимущества кэширования процессора.
Overhead обхода:
Каждый шаг обхода требует разыменования ссылки и проверки условий, что создает дополнительную нагрузку.
#Java #для_новичков #beginner #List #ArrayList #LinkedList #get
Архитектурные основы связного списка
LinkedList реализует список на основе двусвязного списка, где каждый элемент хранится в отдельном узле, содержащем ссылки на данные, предыдущий и следующий узлы.
Эта архитектура fundamentally меняет механизм доступа к элементам:
Последовательный доступ вместо прямого
Линейная временная сложность доступа по индексу
Отсутствие преимуществ пространственной локальности
Дополнительные затраты на обход цепочки
Структура узла и организация данных
Каждый узел LinkedList содержит три ключевых компонента:
Node {
E item; // хранимый элемент
Node<E> next; // ссылка на следующий узел
Node<E> prev; // ссылка на предыдущий узел
}
Список поддерживает ссылки на первый (head) и последний (tail) узлы, а также счетчик размера.Детальный процесс выполнения get(index)
Фаза валидации и стратегического выбора
Как и в ArrayList, первым шагом является проверка корректности индекса:
Проверка границ:
Убеждаются, что индекс находится в диапазоне [0, size-1].
Выбор стратегии обхода:
В зависимости от положения индекса выбирается оптимальная точка начала обхода:
Если индекс находится в первой половине списка (index < size / 2), обход начинается с головы (head)
Если индекс находится во второй половине, обход начинается с хвоста (tail)
Эта оптимизация уменьшает среднее количество шагов обхода с n/2 до n/4.
Фаза последовательного обхода
После выбора начальной точки начинается процесс пошагового перемещения по цепочке узлов:
Инициализация обхода:
Создается временная переменная-указатель, которая устанавливается на начальный узел (head или tail).
Последовательное перемещение:
Для каждого шага обхода:
Если движение от головы, указатель перемещается к следующему узлу (node.next)
Если движение от хвоста, указатель перемещается к предыдущему узлу (node.prev)
Счетчик текущей позиции обновляется
Достижение целевой позиции:
Процесс продолжается до тех пор, пока текущая позиция не совпадет с запрошенным индексом.
Фаза извлечения и возврата результата
Когда целевой узел найден:
Извлечение элемента:
Из поля item целевого узла извлекается хранимый объект.
Возврат результата:
Объект возвращается вызывающему коду. Как и в ArrayList, если узел содержит null, возвращается null.
Производительность и характеристики доступа
Временная сложность
Операция get в LinkedList имеет временную сложность O(n) в худшем случае, где n — количество элементов в списке. Однако благодаря двунаправленному обходу средняя сложность составляет O(n/4) = O(n).
Зависимость от паттерна доступа
Худший случай:
Доступ к элементу в середине большого списка требует обхода примерно n/2 узлов.
Лучший случай:
Доступ к первому или последнему элементу требует всего одного шага.
Средний случай:
При равномерном распределении запросов среднее количество шагов составляет n/4.
Влияние на производительность
Отсутствие кэширования:
Из-за разрозненного расположения узлов в памяти отсутствуют преимущества кэширования процессора.
Overhead обхода:
Каждый шаг обхода требует разыменования ссылки и проверки условий, что создает дополнительную нагрузку.
#Java #для_новичков #beginner #List #ArrayList #LinkedList #get
👍1
Сравнительный анализ производительности
Количественные характеристики
Время доступа:
ArrayList: 5-10 наносекунд на операцию (не зависит от размера)
LinkedList: 10-50 наносекунд × количество пройденных узлов
Потребление памяти:
ArrayList: ~4 байта на элемент (в плотно заполненном массиве)
LinkedList: ~24-32 байта на элемент (затраты на узел)
Качественные различия
Пространственная локальность:
ArrayList: Отличная — элементы расположены непрерывно
LinkedList: Плохая — элементы разбросаны по куче
Масштабируемость:
ArrayList: Идеальная — постоянное время независимо от размера
LinkedList: Линейная деградация — время растет пропорционально размеру
Специализированные реализации List
CopyOnWriteArrayList
Механизм доступа:
Использует snapshot массив, что обеспечивает thread-safe доступ без блокировок:
Операция get просто обращается к текущему snapshot массива
Отсутствие блокировок и contention между читателями
Гарантированная consistency во время итерации
Производительность:
Сопоставима с ArrayList для операций чтения, но с дополнительным уровнем indirection.
Vector
Устаревший synchronized доступ:
Все операции, включая get, синхронизированы, что создает излишний overhead в single-threaded сценариях.
Многопоточные аспекты доступа
Потокобезопасность операций чтения
Несинхронизированные реализации:
ArrayList и LinkedList не гарантируют корректность при concurrent модификациях:
Возможность чтения устаревших данных
Риск исключений при структурных изменениях во время доступа
Отсутствие happens-before отношений
Thread-safe альтернативы:
CopyOnWriteArrayList: Идеален для read-heavy workloads
Collections.synchronizedList(): Добавляет синхронизацию к стандартным реализациям
Vector: Устаревшая синхронизированная реализация
Практические рекомендации
Критерии выбора реализации
Выбор ArrayList когда:
Преобладает случайный доступ по индексу
Частые операции получения элементов
Известен или может быть оценен конечный размер списка
Критически важна производительность операций чтени
Память является ограниченным ресурсом
Выбор LinkedList когда:
Преобладают операции вставки/удаления в начала/конца списка
Основной паттерн доступа — последовательная итерация
Размер списка сильно варьируется
Операции доступа по индексу редки или предсказуемы
Влияние современных аппаратных архитектур
Иерархия памяти и кэширование
ArrayList:
Отличное использование L1/L2/L3 кэшей
Эффективный prefetching
Минимальные cache misses
LinkedList:
Частые cache misses из-за random access к памяти
Неэффективное использование prefetcher'а
Высокий penalty при промахах кэша
Влияние на реальную производительность
Разрыв в производительности между ArrayList и LinkedList для операций get может достигать 50-100 раз для больших списков и случайного доступа, что делает правильный выбор реализации критически важным для производительности приложения.
#Java #для_новичков #beginner #List #ArrayList #LinkedList #get
Количественные характеристики
Время доступа:
ArrayList: 5-10 наносекунд на операцию (не зависит от размера)
LinkedList: 10-50 наносекунд × количество пройденных узлов
Потребление памяти:
ArrayList: ~4 байта на элемент (в плотно заполненном массиве)
LinkedList: ~24-32 байта на элемент (затраты на узел)
Качественные различия
Пространственная локальность:
ArrayList: Отличная — элементы расположены непрерывно
LinkedList: Плохая — элементы разбросаны по куче
Масштабируемость:
ArrayList: Идеальная — постоянное время независимо от размера
LinkedList: Линейная деградация — время растет пропорционально размеру
Специализированные реализации List
CopyOnWriteArrayList
Механизм доступа:
Использует snapshot массив, что обеспечивает thread-safe доступ без блокировок:
Операция get просто обращается к текущему snapshot массива
Отсутствие блокировок и contention между читателями
Гарантированная consistency во время итерации
Производительность:
Сопоставима с ArrayList для операций чтения, но с дополнительным уровнем indirection.
Vector
Устаревший synchronized доступ:
Все операции, включая get, синхронизированы, что создает излишний overhead в single-threaded сценариях.
Многопоточные аспекты доступа
Потокобезопасность операций чтения
Несинхронизированные реализации:
ArrayList и LinkedList не гарантируют корректность при concurrent модификациях:
Возможность чтения устаревших данных
Риск исключений при структурных изменениях во время доступа
Отсутствие happens-before отношений
Thread-safe альтернативы:
CopyOnWriteArrayList: Идеален для read-heavy workloads
Collections.synchronizedList(): Добавляет синхронизацию к стандартным реализациям
Vector: Устаревшая синхронизированная реализация
Практические рекомендации
Критерии выбора реализации
Выбор ArrayList когда:
Преобладает случайный доступ по индексу
Частые операции получения элементов
Известен или может быть оценен конечный размер списка
Критически важна производительность операций чтени
Память является ограниченным ресурсом
Выбор LinkedList когда:
Преобладают операции вставки/удаления в начала/конца списка
Основной паттерн доступа — последовательная итерация
Размер списка сильно варьируется
Операции доступа по индексу редки или предсказуемы
Влияние современных аппаратных архитектур
Иерархия памяти и кэширование
ArrayList:
Отличное использование L1/L2/L3 кэшей
Эффективный prefetching
Минимальные cache misses
LinkedList:
Частые cache misses из-за random access к памяти
Неэффективное использование prefetcher'а
Высокий penalty при промахах кэша
Влияние на реальную производительность
Разрыв в производительности между ArrayList и LinkedList для операций get может достигать 50-100 раз для больших списков и случайного доступа, что делает правильный выбор реализации критически важным для производительности приложения.
#Java #для_новичков #beginner #List #ArrayList #LinkedList #get
👍1
Что выведет код?
#Tasks
import java.util.ArrayList;
import java.util.List;
public class Task281125 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
List<Integer> subList = list.subList(1, 3);
list.add(4);
System.out.println(subList.get(0));
System.out.println(subList.get(1));
}
}
#Tasks
Вопрос с собеседований
Что такое «слабая ссылка» в Java?🤓
Ответ:
WeakReference позволяет объекту быть удаленным GC, если на него нет сильных ссылок.
Используется в кэшах, чтобы не удерживать память. После очистки можно обнаружить, что объект недоступен.
Это гибкий способ управления памятью без ручного освобождения.
#собеседование
Что такое «слабая ссылка» в Java?
Ответ:
Используется в кэшах, чтобы не удерживать память. После очистки можно обнаружить, что объект недоступен.
Это гибкий способ управления памятью без ручного освобождения.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
История IT-технологий сегодня — 29 ноября
ℹ️ Кто родился в этот день
Магдолна Зиманьи , урожденная Магдолна Дьёрдьи (Будапешт , 29 ноября 1934 — Будапешт, 27 марта 2016) — венгерская математик и информатик, одна из пионеров компьютерной науки в Венгрии, разработала методы и подходы в ранней информатике.
🌐 Знаковые события
1972 — Atari выпустила игру Pong, один из первых коммерчески успешных аркадных видеоигр, что стало важным шагом в развитии индустрии видеоигр. Выпуск Pong считается отправной точкой для массового распространения видеоигр и началом игровой индустрии, которая со временем выросла в крупную отрасль развлечений и технологий.
#Biography #Birth_Date #Events #29Ноября
Магдолна Зиманьи , урожденная Магдолна Дьёрдьи (Будапешт , 29 ноября 1934 — Будапешт, 27 марта 2016) — венгерская математик и информатик, одна из пионеров компьютерной науки в Венгрии, разработала методы и подходы в ранней информатике.
1972 — Atari выпустила игру Pong, один из первых коммерчески успешных аркадных видеоигр, что стало важным шагом в развитии индустрии видеоигр. Выпуск Pong считается отправной точкой для массового распространения видеоигр и началом игровой индустрии, которая со временем выросла в крупную отрасль развлечений и технологий.
#Biography #Birth_Date #Events #29Ноября
Please open Telegram to view this post
VIEW IN TELEGRAM
С 22.11 по 28.11
Предыдущий пост(с 15.11 по 21.11)
Воскресный мотивационный пост:
Кем ты видишь себя в будущем в IT?
Запись встреч/видео:
не было
Обучающие статьи:
Java:
Коллекции в Java
Глава 2. List — списки в Java
Реализации: ArrayList и LinkedList. Сравнение производительности
Метод add
Метод get
GraphQL
Реализация GraphQL на сервере
GraphQL vs REST vs gRPC
Полезные статьи и видео:
Spring без боли: моя шпаргалка для собесов в Java
Можно ли спасти LinkedList? Пишем быстрый List на связном списке
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
Предыдущий пост(с 15.11 по 21.11)
Воскресный мотивационный пост:
Кем ты видишь себя в будущем в IT?
Запись встреч/видео:
не было
Обучающие статьи:
Java:
Коллекции в Java
Глава 2. List — списки в Java
Реализации: ArrayList и LinkedList. Сравнение производительности
Метод add
Метод get
GraphQL
Реализация GraphQL на сервере
GraphQL vs REST vs gRPC
Полезные статьи и видео:
Spring без боли: моя шпаргалка для собесов в Java
Можно ли спасти LinkedList? Пишем быстрый List на связном списке
Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
👍2
История IT-технологий сегодня — 30 ноября
ℹ️ Кто родился в этот день
Питер Ли (родился 30 ноября 1960 года) — американский учёный компьютерных наук, президент и глава Microsoft Research, ранее — руководитель отдела безопасности ПО в DARPA; известен трудами в области компиляторов и программных систем безопасности.
Войцех Заремба (родился 30 ноября 1988 года) — польско-американский компьютерный учёный, сооснователь OpenAI; руководил работами по робототехнике и нейросетям (в том числе Rubik’s Cube-робот) и затем над GPT/вопросами ИИ.
🌐 Знаковые события
1609 — Галилео Галилей составил первую карту лунной поверхности.
2022 — запуск ChatGPT.
#Biography #Birth_Date #Events #30Ноября
Питер Ли (родился 30 ноября 1960 года) — американский учёный компьютерных наук, президент и глава Microsoft Research, ранее — руководитель отдела безопасности ПО в DARPA; известен трудами в области компиляторов и программных систем безопасности.
Войцех Заремба (родился 30 ноября 1988 года) — польско-американский компьютерный учёный, сооснователь OpenAI; руководил работами по робототехнике и нейросетям (в том числе Rubik’s Cube-робот) и затем над GPT/вопросами ИИ.
1609 — Галилео Галилей составил первую карту лунной поверхности.
2022 — запуск ChatGPT.
#Biography #Birth_Date #Events #30Ноября
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Технический разбор: Spring WebFlux Gateway с JWT аутентификацией
Архитектурный контекст:
Это API Gateway сервис, который проксирует запросы к downstream-сервисам
Паттерн: Gateway Aggregation с аутентификацией на уровне шлюза
Детальный разбор компонентов:
Spring Security Integration
Автоматическая проверка ролей из JWT токена
Вызывается до выполнения метода контроллера
JWT Processing
JWT объект предоставляет доступ к claims: jwt.getSubject(), jwt.getClaims()
Токен уже провалидирован на уровне security filter chain
Header Management Strategy
X-User-Id - кастомный header для передачи идентификатора пользователя
Проброс оригинального Authorization header для цепочки аутентификации
Reactive WebClient Configuration
Non-blocking HTTP клиент на основе Reactor Netty
Type-safe десериализация в DTO
Автоматическая обработка connection pooling и retries
Error Handling Pipeline
Сохранение тела ответа из downstream-сервиса
Преобразование в domain-specific исключения
Flow выполнения:
HTTP Request → Spring Security Filter Chain
JWT Validation & Role Checking
Controller Method Invocation
WebClient Request to Downstream Service
Response Processing & Error Mapping
HTTP Response to Client
Преимущества данного подхода:
Централизованная аутентификация в gateway
Сквозная передача контекста пользователя
Реактивная non-blocking архитектура
Единая точка обработки ошибок
Type-safe коммуникация между сервисами
Требуемые конфигурации:
Spring Security с JWT decoder
Настроенный WebClient с connection pooling
Global exception handler для кастомных исключений
Мониторинг и логирование межсервисных вызовов
Данная реализация демонстрирует production-ready подход к построению API Gateway в микросервисной архитектуре с полным циклом аутентификации и обработки ошибок.
Архитектурный контекст:
Это API Gateway сервис, который проксирует запросы к downstream-сервисам
Паттерн: Gateway Aggregation с аутентификацией на уровне шлюза
Детальный разбор компонентов:
Spring Security Integration
@PreAuthorize("hasRole('USER')")
Method-level security с SpEL выражениемАвтоматическая проверка ролей из JWT токена
Вызывается до выполнения метода контроллера
JWT Processing
@AuthenticationPrincipal Jwt jwt
Spring Security автоматически инжектирует парсированный JWT
JWT объект предоставляет доступ к claims: jwt.getSubject(), jwt.getClaims()
Токен уже провалидирован на уровне security filter chain
Header Management Strategy
.headers(h -> {
h.add("X-User-Id", jwt.getSubject()); // User ID для сквозной идентификации
h.add(HttpHeaders.AUTHORIZATION, authHeader); // Оригинальный токен для downstream-сервисов
})X-User-Id - кастомный header для передачи идентификатора пользователя
Проброс оригинального Authorization header для цепочки аутентификации
Reactive WebClient Configuration
return taskWebClient.get()
.uri("/api/v1/tasks/{taskId}", taskId) // URI template с подстановкой
.retrieve() // Выполнение запроса
.bodyToMono(TaskDto.class) // Десериализация ответа
Non-blocking HTTP клиент на основе Reactor Netty
Type-safe десериализация в DTO
Автоматическая обработка connection pooling и retries
Error Handling Pipeline
.onErrorMap(WebClientResponseException.class, ex -> {
if (ex.getStatusCode().is4xxClientError()) {
return new AuthClientException(ex.getResponseBodyAsString(), ex.getStatusCode().value());
} else if (ex.getStatusCode().is5xxServerError()) {
return new AuthServerException(ex.getResponseBodyAsString(), ex.getStatusCode().value());
}
return ex;
})
Дифференциация ошибок по статус-кодамСохранение тела ответа из downstream-сервиса
Преобразование в domain-specific исключения
Flow выполнения:
HTTP Request → Spring Security Filter Chain
JWT Validation & Role Checking
Controller Method Invocation
WebClient Request to Downstream Service
Response Processing & Error Mapping
HTTP Response to Client
Преимущества данного подхода:
Централизованная аутентификация в gateway
Сквозная передача контекста пользователя
Реактивная non-blocking архитектура
Единая точка обработки ошибок
Type-safe коммуникация между сервисами
Требуемые конфигурации:
Spring Security с JWT decoder
Настроенный WebClient с connection pooling
Global exception handler для кастомных исключений
Мониторинг и логирование межсервисных вызовов
Данная реализация демонстрирует production-ready подход к построению API Gateway в микросервисной архитектуре с полным циклом аутентификации и обработки ошибок.
👍1🤯1
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2 1
История IT-технологий сегодня — 01 декабря
ℹ️ Кто родился в этот день
Корнелиус Шумахер (нем. Cornelius Schumacher; род. 1 декабря 1969, Тюбинген, Германия) — немецкий разработчик свободного ПО, активист свободного софта, внёс вклад в KDE — популярную среду рабочего стола для GNU/Linux.
🌐 Знаковые события
1677— состоялся запуск первой в мире коммерческой системы интерактивного кабельного телевидения в Колумбусе (Огайо, США). Система предлагала порядка 30 каналов, из которых часть были обычными вещательными, часть — платными (pay-per-view), а часть — интерактивными, с возможностью «обратной связи» пользователя через пульт.
#Biography #Birth_Date #Events #01Декабря
Корнелиус Шумахер (нем. Cornelius Schumacher; род. 1 декабря 1969, Тюбинген, Германия) — немецкий разработчик свободного ПО, активист свободного софта, внёс вклад в KDE — популярную среду рабочего стола для GNU/Linux.
1677— состоялся запуск первой в мире коммерческой системы интерактивного кабельного телевидения в Колумбусе (Огайо, США). Система предлагала порядка 30 каналов, из которых часть были обычными вещательными, часть — платными (pay-per-view), а часть — интерактивными, с возможностью «обратной связи» пользователя через пульт.
#Biography #Birth_Date #Events #01Декабря
Please open Telegram to view this post
VIEW IN TELEGRAM
Advanced GraphQL: реактивность и Federation
GraphQL уже давно не ограничивается статическими запросами к одной базе.
Современные системы требуют:
реактивности: live updates, push-события на фронтенд;
масштабируемости: объединение схем из разных сервисов;
микросервисной интеграции: разные источники данных и форматы;
единый клиентский интерфейс: фронт видит единую схему, хотя данные приходят из нескольких микросервисов.
Эти задачи решаются через Subscriptions, Federation, Schema Stitching, GraphQL Gateway.
1. Subscriptions и live updates
1.1 Что такое Subscription
Subscription — это тип операции GraphQL, который подписывается на события и получает данные по мере их появления, в отличие от Query/Mutation, где данные запрашиваются один раз.
Используется для:
чатов и уведомлений;
реального мониторинга (метрики, логи);
обновления UI при изменении данных на сервере.
1.2 Механика на сервере
Клиент подписывается на событие через WebSocket или Server-Sent Events (SSE).
Сервер регистрирует подписку и хранит её в памяти или через pub/sub (Redis, Kafka).
При событии вызываются соответствующие резолверы Subscription, результат отправляется клиенту.
1.3 Пример на Spring Boot с graphql-java
Схема (schema.graphqls)
Резолвер Subscription
Публикация события (например, после мутации)
1.4 Реактивная интеграция с gRPC
Микросервис может уведомлять GraphQL через gRPC стриминг (Server Streaming).
GraphQL Gateway принимает события и пушит их клиентам через Subscription.
Реализуется через Publisher или Flux (Project Reactor) в Java.
Пример с Project Reactor:
#Java #middle #GraphQL
GraphQL уже давно не ограничивается статическими запросами к одной базе.
Современные системы требуют:
реактивности: live updates, push-события на фронтенд;
масштабируемости: объединение схем из разных сервисов;
микросервисной интеграции: разные источники данных и форматы;
единый клиентский интерфейс: фронт видит единую схему, хотя данные приходят из нескольких микросервисов.
Эти задачи решаются через Subscriptions, Federation, Schema Stitching, GraphQL Gateway.
1. Subscriptions и live updates
1.1 Что такое Subscription
Subscription — это тип операции GraphQL, который подписывается на события и получает данные по мере их появления, в отличие от Query/Mutation, где данные запрашиваются один раз.
Используется для:
чатов и уведомлений;
реального мониторинга (метрики, логи);
обновления UI при изменении данных на сервере.
1.2 Механика на сервере
Клиент подписывается на событие через WebSocket или Server-Sent Events (SSE).
Сервер регистрирует подписку и хранит её в памяти или через pub/sub (Redis, Kafka).
При событии вызываются соответствующие резолверы Subscription, результат отправляется клиенту.
1.3 Пример на Spring Boot с graphql-java
Схема (schema.graphqls)
type Subscription {
postAdded: Post!
}Резолвер Subscription
@Component
public class PostSubscription implements GraphQLSubscriptionResolver {
private final Publisher<Post> postPublisher;
public PostSubscription(Publisher<Post> postPublisher) {
this.postPublisher = postPublisher;
}
public Publisher<Post> postAdded() {
return postPublisher;
}
}
Публикация события (например, после мутации)
@Component
public class PostMutation implements GraphQLMutationResolver {
private final Publisher<Post> postPublisher;
private final PostService postService;
public PostMutation(PostService postService, Publisher<Post> postPublisher) {
this.postService = postService;
this.postPublisher = postPublisher;
}
public Post createPost(CreatePostInput input) {
Post newPost = postService.create(input);
postPublisher.publish(newPost); // пушим в подписчиков
return newPost;
}
}
Таким образом фронтенд автоматически получает новые посты без повторных запросов.
1.4 Реактивная интеграция с gRPC
Микросервис может уведомлять GraphQL через gRPC стриминг (Server Streaming).
GraphQL Gateway принимает события и пушит их клиентам через Subscription.
Реализуется через Publisher или Flux (Project Reactor) в Java.
Пример с Project Reactor:
public Publisher<Post> postAdded() {
return Flux.from(postGrpcStub.subscribePosts());
}#Java #middle #GraphQL
👍1
2. Federation / Schema stitching
2.1 Зачем нужна Federation
В микросервисной архитектуре каждая команда может иметь свой GraphQL-сервис.
Фронтенду нужен единый endpoint, а не десятки отдельных.
Schema stitching: объединяет схемы в один endpoint вручную.
Apollo Federation: более продвинутый стандарт, позволяющий каждому сервису быть федеративным узлом.
2.2 Принцип работы Federation
Subgraph Service — каждый сервис предоставляет свою часть схемы: User, Post, Comment.
Gateway / Apollo Gateway — объединяет схемы subgraph и решает, какой сервис вызывать для каждого запроса.
Reference resolver — позволяет связать типы из разных сервисов (например, User в Post).
Пример на Java (с Spring Boot + GraphQL Federation, библиотека graphql-java-federation):
Сервис Users
Сервис Posts
Java resolver для Post.author
3. GraphQL Gateway и объединение данных
3.1 Роль Gateway
Аггрегирует данные из нескольких микросервисов (REST, gRPC, базы, Kafka).
Решает проблемы N+1 через batching (DataLoader).
Управляет кешированием и throttling.
Поддерживает Subscriptions и Federation.
3.2 Пример архитектуры
Особенности:
Gateway использует DataLoader для агрегации запросов, уменьшения количества вызовов к сервисам.
Subscriptions могут получать события из gRPC стримов или Kafka и пушить клиенту.
4. Примеры использования и кейсы
4.1 Live feed
Мобильное приложение подписывается на postAdded.
PostService пушит новые посты через gRPC или внутренний EventBus.
Gateway трансформирует данные в GraphQL Subscription → клиент получает обновления моментально.
4.2 Микросервисная интеграция
UserService и PostService разрабатываются разными командами.
Gateway объединяет их схемы через Federation.
Фронтенд видит единый API: user(id: 1) { name posts { title } }, не зная, что posts приходит из другого сервиса.
4.3 Agreggation + caching
Gateway кеширует данные User на 5 минут.
PostService вызывается только для новых постов.
DataLoader агрегирует все запросы к UserService за одну операцию.
5. Лучшие практики
Использовать Federation для масштабируемых командных проектов.
Subscription через WebSocket + Publisher/Flux для реактивных интерфейсов.
DataLoader для оптимизации N+1 вызовов в распределённых сервисах.
Разделять ответственность: микросервисы предоставляют свои типы и резолверы, Gateway агрегирует.
Event-driven подход для live updates: gRPC streaming, Kafka, Redis Pub/Sub.
Мониторинг: трассировка на уровне каждого subgraph, latency, throughput.
Эволюция схем: добавление новых полей без ломки клиентов, депрекация старых.
#Java #middle #GraphQL
2.1 Зачем нужна Federation
В микросервисной архитектуре каждая команда может иметь свой GraphQL-сервис.
Фронтенду нужен единый endpoint, а не десятки отдельных.
Schema stitching: объединяет схемы в один endpoint вручную.
Apollo Federation: более продвинутый стандарт, позволяющий каждому сервису быть федеративным узлом.
2.2 Принцип работы Federation
Subgraph Service — каждый сервис предоставляет свою часть схемы: User, Post, Comment.
Gateway / Apollo Gateway — объединяет схемы subgraph и решает, какой сервис вызывать для каждого запроса.
Reference resolver — позволяет связать типы из разных сервисов (например, User в Post).
Пример на Java (с Spring Boot + GraphQL Federation, библиотека graphql-java-federation):
Сервис Users
type User @key(fields: "id") {
id: ID!
name: String!
}Сервис Posts
type Post {
id: ID!
title: String!
author: User @provides(fields: "name")
}Java resolver для Post.author
@Component
public class PostResolver implements GraphQLResolver<Post> {
private final UserGrpc.UserBlockingStub userStub;
public PostResolver(UserGrpc.UserBlockingStub userStub) {
this.userStub = userStub;
}
public User author(Post post) {
UserRequest req = UserRequest.newBuilder().setId(post.getAuthorId()).build();
UserResponse resp = userStub.getUser(req);
return mapToGraphQLUser(resp);
}
}
Gateway собирает всю федеративную схему и возвращает фронтенду единый API.
3. GraphQL Gateway и объединение данных
3.1 Роль Gateway
Аггрегирует данные из нескольких микросервисов (REST, gRPC, базы, Kafka).
Решает проблемы N+1 через batching (DataLoader).
Управляет кешированием и throttling.
Поддерживает Subscriptions и Federation.
3.2 Пример архитектуры
[Frontend SPA / Mobile] --GraphQL--> [GraphQL Gateway] --gRPC--> [UserService]
|--> [PostService]
|--> [CommentService]
|--> [External REST API]
Особенности:
Gateway использует DataLoader для агрегации запросов, уменьшения количества вызовов к сервисам.
Subscriptions могут получать события из gRPC стримов или Kafka и пушить клиенту.
4. Примеры использования и кейсы
4.1 Live feed
Мобильное приложение подписывается на postAdded.
PostService пушит новые посты через gRPC или внутренний EventBus.
Gateway трансформирует данные в GraphQL Subscription → клиент получает обновления моментально.
4.2 Микросервисная интеграция
UserService и PostService разрабатываются разными командами.
Gateway объединяет их схемы через Federation.
Фронтенд видит единый API: user(id: 1) { name posts { title } }, не зная, что posts приходит из другого сервиса.
4.3 Agreggation + caching
Gateway кеширует данные User на 5 минут.
PostService вызывается только для новых постов.
DataLoader агрегирует все запросы к UserService за одну операцию.
5. Лучшие практики
Использовать Federation для масштабируемых командных проектов.
Subscription через WebSocket + Publisher/Flux для реактивных интерфейсов.
DataLoader для оптимизации N+1 вызовов в распределённых сервисах.
Разделять ответственность: микросервисы предоставляют свои типы и резолверы, Gateway агрегирует.
Event-driven подход для live updates: gRPC streaming, Kafka, Redis Pub/Sub.
Мониторинг: трассировка на уровне каждого subgraph, latency, throughput.
Эволюция схем: добавление новых полей без ломки клиентов, депрекация старых.
#Java #middle #GraphQL
👍1
Что выведет код?
#Tasks
import java.util.Optional;
public class Task011225 {
public static void main(String[] args) {
Optional<String> emptyOpt = Optional.empty();
Optional<String> valueOpt = Optional.of("hello");
Optional<String> nullOpt = Optional.ofNullable(null);
System.out.println(valueOpt.get());
System.out.println(nullOpt.isPresent());
System.out.println(emptyOpt.isPresent());
System.out.println(emptyOpt.get());
}
}
#Tasks
Варианты ответа:
Anonymous Quiz
43%
hello false false исключение
43%
hello true false null
0%
hello false false null
14%
hello true true исключение
Вопрос с собеседований
Для чего нужен метод join() в потоках?🤓
Ответ:
join() заставляет текущий поток ждать завершения другого потока.
Это полезно для синхронизации выполнения, когда результат параллельной работы нужен дальше.
Правильное использование предотвращает гонки данных и обеспечивает согласованность программы.
#собеседование
Для чего нужен метод join() в потоках?
Ответ:
Это полезно для синхронизации выполнения, когда результат параллельной работы нужен дальше.
Правильное использование предотвращает гонки данных и обеспечивает согласованность программы.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1