Форматы данных: JSON и XML
JSON (JavaScript Object Notation) и XML (eXtensible Markup Language) — это два популярных формата для обмена данными между клиентом и сервером. В рамках Spring оба формата поддерживаются для сериализации и десериализации данных, что делает их основными выбором для RESTful API и других интеграций.
JSON (JavaScript Object Notation)
JSON — это легковесный текстовый формат для обмена данными, основанный на синтаксисе JavaScript. Он разработан для передачи структурированных данных в человекочитаемой форме.
Пример JSON:
Преимущества JSON
Простота и читаемость:
JSON компактен и легко читается человеком.
Широкая поддержка:
JSON поддерживается большинством языков программирования.
Легковесность:
JSON менее объемный, чем XML, что снижает нагрузку на сеть.
Совместимость:
Он может быть легко интегрирован в JavaScript и другие языки.
Ограничения JSON
Ограниченный синтаксис:
Нет встроенной поддержки атрибутов, как в XML.
Менее строгий стандарт:
Возможны несовместимости при использовании сложных структур.
XML (eXtensible Markup Language)
XML — это язык разметки для представления данных в формате, удобном для чтения как человеком, так и машиной. В отличие от JSON, XML имеет более сложный синтаксис и поддерживает атрибуты.
Пример XML:
Преимущества XML
Гибкость:
XML позволяет использовать как элементы, так и атрибуты для представления данных.
Самоописываемость:
Схемы XML (DTD, XSD) помогают проверять структуру и формат данных.
Поддержка сложных структур:
XML идеально подходит для иерархических данных.
Поддержка метаданных:
Атрибуты позволяют добавлять дополнительную информацию к элементам.
Ограничения XML
Больший размер:
XML более громоздкий по сравнению с JSON.
Сложность обработки:
XML требует большего количества ресурсов для парсинга.
Менее читаемый:
Из-за объема разметки XML менее удобен для восприятия человеком.
Поддержка JSON и XML в Spring
Spring поддерживает оба формата через модули Jackson (для JSON) и JAXB или другие парсеры (для XML).
Для работы с JSON используется библиотека Jackson. Она автоматически преобразует объекты Java в JSON и обратно.
Пример сериализации объекта в JSON:
Ответ:
XML в Spring
Для работы с XML можно использовать библиотеку JAXB (Java Architecture for XML Binding) или другие парсеры.
Пример работы с XML:
Ответ:
#Java #Training #Spring #Json #Xml
JSON (JavaScript Object Notation) и XML (eXtensible Markup Language) — это два популярных формата для обмена данными между клиентом и сервером. В рамках Spring оба формата поддерживаются для сериализации и десериализации данных, что делает их основными выбором для RESTful API и других интеграций.
JSON (JavaScript Object Notation)
JSON — это легковесный текстовый формат для обмена данными, основанный на синтаксисе JavaScript. Он разработан для передачи структурированных данных в человекочитаемой форме.
Пример JSON:
{
"id": 1,
"name": "John Doe",
"age": 30,
"isActive": true,
"roles": ["admin", "user"],
"address": {
"street": "123 Main St",
"city": "Springfield"
}
}Преимущества JSON
Простота и читаемость:
JSON компактен и легко читается человеком.
Широкая поддержка:
JSON поддерживается большинством языков программирования.
Легковесность:
JSON менее объемный, чем XML, что снижает нагрузку на сеть.
Совместимость:
Он может быть легко интегрирован в JavaScript и другие языки.
Ограничения JSON
Ограниченный синтаксис:
Нет встроенной поддержки атрибутов, как в XML.
Менее строгий стандарт:
Возможны несовместимости при использовании сложных структур.
XML (eXtensible Markup Language)
XML — это язык разметки для представления данных в формате, удобном для чтения как человеком, так и машиной. В отличие от JSON, XML имеет более сложный синтаксис и поддерживает атрибуты.
Пример XML:
<user>
<id>1</id>
<name>John Doe</name>
<age>30</age>
<isActive>true</isActive>
<roles>
<role>admin</role>
<role>user</role>
</roles>
<address>
<street>123 Main St</street>
<city>Springfield</city>
</address>
</user>
Преимущества XML
Гибкость:
XML позволяет использовать как элементы, так и атрибуты для представления данных.
Самоописываемость:
Схемы XML (DTD, XSD) помогают проверять структуру и формат данных.
Поддержка сложных структур:
XML идеально подходит для иерархических данных.
Поддержка метаданных:
Атрибуты позволяют добавлять дополнительную информацию к элементам.
Ограничения XML
Больший размер:
XML более громоздкий по сравнению с JSON.
Сложность обработки:
XML требует большего количества ресурсов для парсинга.
Менее читаемый:
Из-за объема разметки XML менее удобен для восприятия человеком.
Поддержка JSON и XML в Spring
Spring поддерживает оба формата через модули Jackson (для JSON) и JAXB или другие парсеры (для XML).
Для работы с JSON используется библиотека Jackson. Она автоматически преобразует объекты Java в JSON и обратно.
Пример сериализации объекта в JSON:
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public User getUser(@PathVariable int id) {
return new User(1, "John Doe", 30, true);
}
}
Ответ:
{
"id": 1,
"name": "John Doe",
"age": 30,
"isActive": true
}XML в Spring
Для работы с XML можно использовать библиотеку JAXB (Java Architecture for XML Binding) или другие парсеры.
Пример работы с XML:
@RestController
@RequestMapping("/users")
public class UserController {
@GetMapping(value = "/{id}", produces = MediaType.APPLICATION_XML_VALUE)
public User getUser(@PathVariable int id) {
return new User(1, "John Doe", 30, true);
}
}
Ответ:
<user>
<id>1</id>
<name>John Doe</name>
<age>30</age>
<isActive>true</isActive>
</user>
#Java #Training #Spring #Json #Xml
👍1
Раздел 11. Работа с файлами, I/O и сетью (NIO.2)
Глава 3. Сериализация и форматы обмена
JSON — современный стандарт обмена данными
JSON (JavaScript Object Notation) — это текстовый формат сериализации данных, изначально выведенный из синтаксиса литералов объектов языка JavaScript. Несмотря на происхождение, JSON является полностью языконезависимым форматом и определён стандартом RFC 8259 (декабрь 2017), который заменил RFC 7159. Сегодня JSON де-факто является стандартным форматом обмена данными в веб-сервисах, конфигурационных файлах, логах, сообщениях брокеров и хранилищах документов.
Что такое JSON
JSON представляет собой текстовый формат, основанный на двух структурах:
Коллекция пар ключ-значение — в разных языках это реализуется как объект, запись, структура, словарь, хэш-таблица или ассоциативный массив.
Упорядоченный список значений — в большинстве языков это массив, вектор, список или последовательность.
Формат спроектирован так, чтобы быть легко читаемым для человека и легко парсящимся для машины. Это достигается за счёт минималистичного синтаксиса и строгих правил: каждый документ JSON — это либо один объект, либо один массив.
JSON как основа REST API
JSON стал доминирующим форматом представления ресурсов в REST API благодаря нескольким факторам:
Нативная поддержка в JavaScript, который исполняется в браузере клиента.
Простота генерации и парсинга на стороне сервера — любой язык имеет библиотеку для работы с JSON.
Читаемость при отладке — в отличие от бинарных форматов, JSON можно просмотреть в инструментах разработчика браузера или в логах.
Отсутствие необходимости в схеме для базового использования — в отличие от XML, JSON не требует DTD или XSD для валидации.
#Java #для_новичков #beginner #IO #NIO #Serialize #JSON
Глава 3. Сериализация и форматы обмена
JSON — современный стандарт обмена данными
JSON (JavaScript Object Notation) — это текстовый формат сериализации данных, изначально выведенный из синтаксиса литералов объектов языка JavaScript. Несмотря на происхождение, JSON является полностью языконезависимым форматом и определён стандартом RFC 8259 (декабрь 2017), который заменил RFC 7159. Сегодня JSON де-факто является стандартным форматом обмена данными в веб-сервисах, конфигурационных файлах, логах, сообщениях брокеров и хранилищах документов.
Сериализация — это процесс преобразования структуры данных или объекта в формат, который можно сохранить на диск, передать по сети или записать в базу данных, с возможностью последующего восстановления (десериализации) в исходную структуру.
RFC (Request for Comments) — серия документов Интернет-инженерного совета (IETF), описывающих стандарты, протоколы и технологии Интернета. RFC 8259 является официальной спецификацией формата JSON.
Что такое JSON
JSON представляет собой текстовый формат, основанный на двух структурах:
Коллекция пар ключ-значение — в разных языках это реализуется как объект, запись, структура, словарь, хэш-таблица или ассоциативный массив.
Упорядоченный список значений — в большинстве языков это массив, вектор, список или последовательность.
Формат спроектирован так, чтобы быть легко читаемым для человека и легко парсящимся для машины. Это достигается за счёт минималистичного синтаксиса и строгих правил: каждый документ JSON — это либо один объект, либо один массив.
Парсинг — это процесс анализа строки или потока данных в соответствии с правилами формального языка (грамматикой) с целью построения структурированного представления, обычно дерева разбора или абстрактного синтаксического дерева (AST).
JSON как основа REST API
REST (Representational State Transfer) — это архитектурный стиль проектирования распределённых систем, введённый Роем Филдингом в его докторской диссертации 2000 года. REST не является протоколом или стандартом в строгом смысле; это набор ограничений и принципов.
Ключевое ограничение — statelessness (отсутствие состояния): каждый запрос от клиента к серверу должен содержать всю информацию, необходимую для его обработки, и сервер не хранит контекст клиента между запросами.
JSON стал доминирующим форматом представления ресурсов в REST API благодаря нескольким факторам:
Нативная поддержка в JavaScript, который исполняется в браузере клиента.
Простота генерации и парсинга на стороне сервера — любой язык имеет библиотеку для работы с JSON.
Читаемость при отладке — в отличие от бинарных форматов, JSON можно просмотреть в инструментах разработчика браузера или в логах.
Отсутствие необходимости в схеме для базового использования — в отличие от XML, JSON не требует DTD или XSD для валидации.
DTD (Document Type Definition) и XSD (XML Schema Definition) — это механизмы определения структуры и допустимых элементов XML-документа. JSON изначально не имел встроенного механизма схем, хотя позже появились JSON Schema и OpenAPI.
#Java #для_новичков #beginner #IO #NIO #Serialize #JSON
👍3
Структура JSON
Спецификация JSON определяет шесть типов значений:
Объекты
Объект — это неупорядоченный набор пар ключ-значение, заключённый в фигурные скобки. Ключ — это строка, значение — любой допустимый JSON-тип. Пары разделяются запятыми.
В Java объект JSON обычно маппится на
Массивы
Массив — это упорядоченная последовательность значений, заключённая в квадратные скобки. Значения разделяются запятыми. Индексация начинается с нуля.
В Java массив JSON маппится на
Строки
Строка — это последовательность из нуля или более символов Unicode, заключённая в двойные кавычки. JSON поддерживает escape-последовательности:
Строки в JSON кодируются в UTF-8, UTF-16 или UTF-32. На практике UTF-8 доминирует, так как обеспечивает обратную совместимость с ASCII и экономит память для латинских текстов.
Числа
Числа в JSON записываются в десятичной системе и могут быть целыми или с плавающей точкой. Поддерживается экспоненциальная нотация. Нет различия между целыми и вещественными числами на уровне синтаксиса — это одна грамматическая категория.
Спецификация JSON не ограничивает точность или диапазон чисел. Однако на практике числа с плавающей точкой часто интерпретируются как IEEE 754 double-precision (64 бита), что даёт точность около 15–17 значащих цифр. Для финансовых расчётов, где критична точность до копеек, это может привести к ошибкам округления. В таких случаях числа передаются как строки.
Булевы значения
Два литерала:
Null
Литерал
Преимущества JSON
Читаемость
JSON читается без специальных инструментов. Структура вложенности визуально очевидна благодаря отступам. Это снижает порог входа для разработчиков и упрощает отладку. В отличие от бинарных форматов, JSON можно открыть в любом текстовом редакторе или даже в терминале через
Универсальная поддержка
Каждый современный язык программирования имеет библиотеку для работы с JSON. В Java экосистеме существуют Jackson, Gson, JSON-B, JSON-P, org.json и многие другие. В JavaScript JSON — нативный формат. В Python — модуль
Простота
Грамматика JSON минимальна: всего два контейнерных типа и четыре скалярных. Нет пространств имён, нет схем, нет атрибутов, нет комментариев (официально — комментарии не поддерживаются, хотя некоторые парсеры их принимают). Эта простота снижает сложность парсеров и уменьшает вероятность ошибок при сериализации.
Интеграция с веб-стеком
JSON родственен JavaScript, что делает его естественным выбором для веб-приложений. Fetch API, XMLHttpRequest, WebSocket — все эти API работают с JSON напрямую. Браузер предоставляет нативный объект
Недостатки JSON
Размер и текстовая природа
JSON — текстовый формат. Каждое число, булево значение или null записывается символами, а не бинарными данными. Ключи объектов повторяются в каждом документе. Для массовых данных это приводит к значительному overhead.
В этом примере ключи
Отсутствие строгой типизации
JSON не имеет схемы встроенной в сам документ. Поле
Отсутствие поддержки бинарных данных
JSON не имеет встроенного типа для бинарных данных. Для передачи бинарного контента (изображения, PDF, аудио) используется кодирование в Base64, что увеличивает размер данных примерно на 33%. Альтернативы — передача бинарных данных отдельно (multipart/form-data) или использование бинарных форматов.
Отсутствие комментариев
Спецификация JSON явно запрещает комментарии. Это создаёт проблемы для конфигурационных файлов, где комментарии полезны для документирования. Решения: использование JSON5 (расширение JSON с комментариями), YAML или TOML для конфигурации, либо отдельные файлы документации.
Производительность парсинга
Парсинг JSON требует посимвольного разбора строки, построения дерева объектов в памяти и часто — рефлексии для маппинга на Java-объекты. Для высоконагруженных систем это может стать bottleneck. Оптимизации включают потоковый парсинг (Jackson Streaming API), бинарные форматы на основе JSON (BSON, MessagePack) или полный отказ от JSON в пользу protobuf/Avro.
#Java #для_новичков #beginner #IO #NIO #Serialize #JSON
Спецификация JSON определяет шесть типов значений:
Объекты
Объект — это неупорядоченный набор пар ключ-значение, заключённый в фигурные скобки. Ключ — это строка, значение — любой допустимый JSON-тип. Пары разделяются запятыми.
{
"user": {
"id": 42,
"name": "Alice",
"active": true
}
}В Java объект JSON обычно маппится на
Map<String, Object> или на POJO (Plain Old Java Object — простой Java-объект без специальных требований к наследованию или аннотациям). Ключи в объекте JSON уникальны в пределах одного объекта, но спецификация не запрещает дубликаты — поведение при дубликатах зависит от парсера. Большинство парсеров используют последнее встреченное значение.Массивы
Массив — это упорядоченная последовательность значений, заключённая в квадратные скобки. Значения разделяются запятыми. Индексация начинается с нуля.
{
"orders": [
{ "id": 1, "total": 99.99 },
{ "id": 2, "total": 150.00 }
]
}В Java массив JSON маппится на
List<Object>, Object[] или типизированный список List<Order>, если используется библиотека с поддержкой дженериков.Строки
Строка — это последовательность из нуля или более символов Unicode, заключённая в двойные кавычки. JSON поддерживает escape-последовательности:
\n (перевод строки), \t (табуляция), \\ (обратный слеш), \" (кавычка), \uXXXX (символ Unicode в шестнадцатеричном виде).{
"description": "Line 1\nLine 2\tTabbed",
"emoji": "\uD83D\uDE00"
}Строки в JSON кодируются в UTF-8, UTF-16 или UTF-32. На практике UTF-8 доминирует, так как обеспечивает обратную совместимость с ASCII и экономит память для латинских текстов.
UTF-8 (Unicode Transformation Format, 8-bit) — это кодировка переменной длины, которая кодирует символы Unicode от 1 до 4 байтами. Символы ASCII (0–127) занимают 1 байт, что делает UTF-8 эффективной для англоязычных текстов.
Числа
Числа в JSON записываются в десятичной системе и могут быть целыми или с плавающей точкой. Поддерживается экспоненциальная нотация. Нет различия между целыми и вещественными числами на уровне синтаксиса — это одна грамматическая категория.
{
"integer": 42,
"negative": -17,
"float": 3.14159,
"exponential": 6.022e23,
"small": 1e-10
}Спецификация JSON не ограничивает точность или диапазон чисел. Однако на практике числа с плавающей точкой часто интерпретируются как IEEE 754 double-precision (64 бита), что даёт точность около 15–17 значащих цифр. Для финансовых расчётов, где критична точность до копеек, это может привести к ошибкам округления. В таких случаях числа передаются как строки.
IEEE 754 — это стандарт представления чисел с плавающей точкой в компьютерах. Double-precision использует 64 бита: 1 бит знака, 11 бит экспоненты и 52 бита мантиссы. Не все десятичные дроби точно представимы в двоичной системе, отсюда ошибки округления.
Булевы значения
Два литерала:
true и false. В Java маппятся на примитив boolean или объект Boolean.{
"enabled": true,
"debug": false
}Null
Литерал
null представляет отсутствие значения. В Java маппится на null.{
"middleName": null
}Преимущества JSON
Читаемость
JSON читается без специальных инструментов. Структура вложенности визуально очевидна благодаря отступам. Это снижает порог входа для разработчиков и упрощает отладку. В отличие от бинарных форматов, JSON можно открыть в любом текстовом редакторе или даже в терминале через
curl.Универсальная поддержка
Каждый современный язык программирования имеет библиотеку для работы с JSON. В Java экосистеме существуют Jackson, Gson, JSON-B, JSON-P, org.json и многие другие. В JavaScript JSON — нативный формат. В Python — модуль
json в стандартной библиотеке. В Go — пакет encoding/json. Это означает, что сервис на Java может бесшовно обмениваться данными с сервисом на Python, Go или Node.js.Простота
Грамматика JSON минимальна: всего два контейнерных типа и четыре скалярных. Нет пространств имён, нет схем, нет атрибутов, нет комментариев (официально — комментарии не поддерживаются, хотя некоторые парсеры их принимают). Эта простота снижает сложность парсеров и уменьшает вероятность ошибок при сериализации.
Интеграция с веб-стеком
JSON родственен JavaScript, что делает его естественным выбором для веб-приложений. Fetch API, XMLHttpRequest, WebSocket — все эти API работают с JSON напрямую. Браузер предоставляет нативный объект
JSON с методами parse() и stringify().Недостатки JSON
Размер и текстовая природа
JSON — текстовый формат. Каждое число, булево значение или null записывается символами, а не бинарными данными. Ключи объектов повторяются в каждом документе. Для массовых данных это приводит к значительному overhead.
{
"users": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
}В этом примере ключи
"id" и "name" повторяются для каждого элемента. В бинарном формате (например, Protocol Buffers) ключи заменяются числовыми тегами, а строковые значения могут быть закодированы более эффективно. JSON также не поддерживает сжатие на уровне формата — для уменьшения размера применяется внешнее сжатие (gzip, brotli).Protocol Buffers (protobuf) — бинарный формат сериализации, разработанный Google. В отличие от JSON, protobuf требует предварительного определения схемы (proto-файл), но обеспечивает компактное бинарное представление и строгую типизацию.
Отсутствие строгой типизации
JSON не имеет схемы встроенной в сам документ. Поле
"age" может содержать число в одном запросе и строку в другом. Это создаёт риск ошибок при десериализации, если клиент и сервер не согласовали контракт. Для решения этой проблемы используются JSON Schema, OpenAPI/Swagger или кодогенерация по proto-файлам.JSON Schema — это спецификация (draft 2020-12) для описания структуры JSON-документов. Она позволяет определять типы полей, обязательность, диапазоны значений, регулярные выражения для строк и другие ограничения.
Отсутствие поддержки бинарных данных
JSON не имеет встроенного типа для бинарных данных. Для передачи бинарного контента (изображения, PDF, аудио) используется кодирование в Base64, что увеличивает размер данных примерно на 33%. Альтернативы — передача бинарных данных отдельно (multipart/form-data) или использование бинарных форматов.
Base64 — это схема кодирования бинарных данных в текстовый формат с использованием 64 символов ASCII (A–Z, a–z, 0–9, +, /). Каждые 3 байта (24 бита) кодируются 4 символами Base64 (по 6 бит каждый), отсюда overhead в 33%.
Отсутствие комментариев
Спецификация JSON явно запрещает комментарии. Это создаёт проблемы для конфигурационных файлов, где комментарии полезны для документирования. Решения: использование JSON5 (расширение JSON с комментариями), YAML или TOML для конфигурации, либо отдельные файлы документации.
Производительность парсинга
Парсинг JSON требует посимвольного разбора строки, построения дерева объектов в памяти и часто — рефлексии для маппинга на Java-объекты. Для высоконагруженных систем это может стать bottleneck. Оптимизации включают потоковый парсинг (Jackson Streaming API), бинарные форматы на основе JSON (BSON, MessagePack) или полный отказ от JSON в пользу protobuf/Avro.
Bottleneck — это узкое место в системе, которое ограничивает общую производительность. В контексте JSON-парсинга bottleneck часто возникает из-за аллокации объектов в куче и работы GC при обработке больших JSON-документов.
#Java #для_новичков #beginner #IO #NIO #Serialize #JSON
👍3
Путь байтов в памяти JVM при работе с JSON
1. Получение JSON-строки
JSON-данные обычно поступают в JVM одним из трёх способов: как строка из HTTP-ответа, как содержимое файла, считанное через
Если JSON приходит по HTTP, процесс начинается на уровне сетевого стека ОС. Пакеты TCP собираются в сегменты, данные копируются из kernel space (пространство ядра) в user space (пользовательское пространство) в буфер сокета. Servlet-контейнер (Tomcat, Jetty, Netty) или фреймворк (Spring Boot) читает байты из сокета в буфер — обычно это
2. Декодирование байтов в строку
Байты из сети или файла представляют JSON в кодировке UTF-8. JVM декодирует их в объект
В Java 9+ строки хранятся как
3. Парсинг JSON: аллокация объектов в куче
Парсер (Jackson, Gson или стандартный
Jackson создаст следующие объекты в куче:
Один
Один
Два
Четыре
Два
Строковые ключи
Все эти объекты создаются в Young Generation, в области Eden. Для JSON-документа размером 10 КБ количество объектов может достигать сотен. При обработке тысяч запросов в секунду это создаёт огромное давление на Minor GC.
4. Маппинг на POJO: рефлексия и дополнительные аллокации
При десериализации JSON в Java-объекты (POJO) парсер использует рефлексию — механизм Java для интроспекции классов во время выполнения.
Рефлексия требует:
Создания объекта
Вызова
Установки полей через
Jackson оптимизирует это через
5. Работа GC с JSON-объектами
После десериализации JSON-строка и промежуточные структуры парсера (токены, узлы дерева) становятся мусором. Если использовался Jackson в режиме потокового парсинга (Streaming API), дерево не строится целиком — объекты создаются по мере чтения и сразу собираются GC. В режиме древовидного парсинга (Tree Model) всё дерево JSON хранится в памяти до явного освобождения.
Для высоконагруженных систем критично минимизировать аллокации:
В этом примере
6. Сериализация: обратный путь
При сериализации Java-объекта в JSON происходит обратный процесс:
Jackson обходит поля объекта через кэшированные сериализаторы.
Генерирует JSON-текст как
Если вывод идёт в
Если вывод идёт в
При сериализации в HTTP-ответ через Spring Boot используется
7. Ключевые строки и пул строк
Ключи JSON-объектов (
Интернирование строк — это процесс помещения строки в пул строк JVM через метод
8. Бинарные JSON-форматы и память
Для снижения давления на GC и размера данных используются бинарные форматы на основе JSON:
BSON (Binary JSON) — используется в MongoDB. Содержит типовые теги и длины полей, что ускоряет навигацию без полного парсинга.
MessagePack — бинарный формат, совместимый с JSON по структуре, но более компактный.
CBOR (Concise Binary Object Representation) — стандарт RFC 8949, разработанный IETF как бинарная альтернатива JSON.
Эти форматы парсятся быстрее, так как не требуют посимвольного разбора текста, и создают меньше объектов в куче.
#Java #для_новичков #beginner #IO #NIO #Serialize #JSON
1. Получение JSON-строки
JSON-данные обычно поступают в JVM одним из трёх способов: как строка из HTTP-ответа, как содержимое файла, считанное через
Files.readString(), или как сообщение из брокера (Kafka, RabbitMQ).Если JSON приходит по HTTP, процесс начинается на уровне сетевого стека ОС. Пакеты TCP собираются в сегменты, данные копируются из kernel space (пространство ядра) в user space (пользовательское пространство) в буфер сокета. Servlet-контейнер (Tomcat, Jetty, Netty) или фреймворк (Spring Boot) читает байты из сокета в буфер — обычно это
byte[] или ByteBuffer в куче JVM.Kernel space и user space — это два режима работы процессора. Kernel space — привилегированный режим, в котором работает код операционной системы и драйверов. User space — непривилегированный режим, в котором работают обычные приложения, включая JVM. Переход между режимами (context switch) — дорогая операция.
2. Декодирование байтов в строку
Байты из сети или файла представляют JSON в кодировке UTF-8. JVM декодирует их в объект
String — это массив byte[] (начиная с Java 9; ранее char[]) в куче, плюс объект-обёртка String со ссылкой на массив, хэш-кодом и флагами.В Java 9+ строки хранятся как
byte[] с кодировкой LATIN1 (1 байт на символ) или UTF-16 (2 байта на символ), в зависимости от содержимого. Компактные строки (compact strings) экономят память для ASCII-текстов. Для JSON, состоящего преимущественно из ASCII, это означает экономию ~50% по сравнению со старым char[].Compact strings — оптимизация, введённая в Java 9 (JEP 254). Строки, содержащие только символы Latin-1 (коды 0–255), хранятся в массиве
byte[]по одному байту на символ. Если встречается символ вне Latin-1, массив переключается на UTF-16 (2 байта на символ).
3. Парсинг JSON: аллокация объектов в куче
Парсер (Jackson, Gson или стандартный
org.json) читает строку посимвольно и строит дерево объектов. Для JSON-документа:{
"users": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
}Jackson создаст следующие объекты в куче:
Один
JsonNode (или LinkedHashMap при десериализации в Map) для корневого объекта.Один
ArrayNode (или ArrayList) для массива "users".Два
ObjectNode (или LinkedHashMap) для объектов пользователей.Четыре
IntNode / Integer для полей "id".Два
TextNode / String для полей "name".Строковые ключи
"users", "id", "name" — если они не интернированы, создаются как отдельные объекты String.Все эти объекты создаются в Young Generation, в области Eden. Для JSON-документа размером 10 КБ количество объектов может достигать сотен. При обработке тысяч запросов в секунду это создаёт огромное давление на Minor GC.
4. Маппинг на POJO: рефлексия и дополнительные аллокации
При десериализации JSON в Java-объекты (POJO) парсер использует рефлексию — механизм Java для интроспекции классов во время выполнения.
Рефлексия требует:
Создания объекта
Constructor через Class.getDeclaredConstructor().Вызова
Constructor.newInstance() — аллокация POJO в куче.Установки полей через
Field.set() или вызова сеттеров.Jackson оптимизирует это через
SerializerCache и DeserializerCache — кэши, хранящие скомпилированные сериализаторы и десериализаторы. После первого использования класса его метаданные кэшируются, и последующие операции не требуют полной рефлексии. Однако первый парсинг класса — дорогая операция, создающая множество временных объектов.5. Работа GC с JSON-объектами
После десериализации JSON-строка и промежуточные структуры парсера (токены, узлы дерева) становятся мусором. Если использовался Jackson в режиме потокового парсинга (Streaming API), дерево не строится целиком — объекты создаются по мере чтения и сразу собираются GC. В режиме древовидного парсинга (Tree Model) всё дерево JSON хранится в памяти до явного освобождения.
Для высоконагруженных систем критично минимизировать аллокации:
// Потоковый парсинг Jackson — минимум аллокаций
public void processLargeJson(InputStream in) throws IOException {
// JsonFactory — лёгкий фабричный объект для создания парсеров
JsonFactory factory = new JsonFactory();
// JsonParser — потоковый парсер, читает JSON без построения дерева
try (JsonParser parser = factory.createParser(in)) {
while (parser.nextToken() != JsonToken.END_OBJECT) {
String fieldName = parser.getCurrentName();
if ("users".equals(fieldName)) {
parser.nextToken(); // переходим к массиву
while (parser.nextToken() == JsonToken.START_OBJECT) {
// Обрабатываем каждый объект пользователя
int id = 0;
String name = null;
while (parser.nextToken() != JsonToken.END_OBJECT) {
String key = parser.getCurrentName();
parser.nextToken();
if ("id".equals(key)) {
id = parser.getIntValue();
} else if ("name".equals(key)) {
name = parser.getValueAsString();
}
}
// Обрабатываем пользователя без создания промежуточных объектов
processUser(id, name);
}
}
}
}
}
В этом примере
JsonParser читает JSON как поток токенов, не создавая дерево объектов. Память используется минимально, и давление на GC снижается на порядки по сравнению с mapper.readValue(json, UserList.class).6. Сериализация: обратный путь
При сериализации Java-объекта в JSON происходит обратный процесс:
Jackson обходит поля объекта через кэшированные сериализаторы.
Генерирует JSON-текст как
char[] или byte[] внутри StringWriter или OutputStream.Если вывод идёт в
OutputStream (HTTP-ответ, файл), байты записываются напрямую без промежуточной строки.Если вывод идёт в
String, создаётся объект String в куче, который затем передаётся дальше.При сериализации в HTTP-ответ через Spring Boot используется
MappingJackson2HttpMessageConverter, который пишет JSON напрямую в OutputStream ответа, минуя создание промежуточной строки. Это экономит аллокации и снижает нагрузку на GC.7. Ключевые строки и пул строк
Ключи JSON-объектов (
"id", "name", "users") — это строки, которые повторяются в каждом документе. Jackson может интернировать часто встречающиеся ключи через JsonFactory.Feature.INTERN_FIELD_NAMES. Интернирование помещает строки в пул строк (String Pool) в Metaspace, делая их доступными для повторного использования между запросами. Это снижает аллокации, но увеличивает потребление Metaspace — пул строк не собирается обычным GC.Интернирование строк — это процесс помещения строки в пул строк JVM через метод
String.intern(). Если строка с таким содержимым уже есть в пуле, возвращается существующий объект; иначе строка добавляется в пул. Интернирование экономит память при множестве одинаковых строк, но может привести к утечке памяти в Metaspace при интернировании уникальных строк.8. Бинарные JSON-форматы и память
Для снижения давления на GC и размера данных используются бинарные форматы на основе JSON:
BSON (Binary JSON) — используется в MongoDB. Содержит типовые теги и длины полей, что ускоряет навигацию без полного парсинга.
MessagePack — бинарный формат, совместимый с JSON по структуре, но более компактный.
CBOR (Concise Binary Object Representation) — стандарт RFC 8949, разработанный IETF как бинарная альтернатива JSON.
Эти форматы парсятся быстрее, так как не требуют посимвольного разбора текста, и создают меньше объектов в куче.
#Java #для_новичков #beginner #IO #NIO #Serialize #JSON
👍4