⚠️Эта статья является первой подписанной статьей сообщества Nuggets, перепечатка без разрешения запрещена.
причина события
Сегодня мне нужно запустить очень маленькое, но очень важное системное изменение, то есть в основной интерфейсRPC
В параметр интерфейса добавлен интерфейс сериализации (как видно из рисунка ниже, исходный класс сущностей не реализует сериализацию).
Кодирование, тестирование и проверка кода выполняются за один раз, а затем приходит уведомление об отказе.Архитектор сказал, что при реализации интерфейса сериализации будьте осторожны, чтобы не забыть конфигурациюserialversionUID, а также очень интимно рассказал мне, что у IDEA есть плагин, который может автоматически генерировать UID, и его рекомендуется скачать и использовать (Адрес плагина IDEA serialversionUID), после настройки в соответствии с требованиями, тестирования, компиляции и публикации за один раз, введите сегодняшний режим сна (😎)
испуг во сне
Мне вдруг приснилось, что корпоративный WeChat мерцает со скоростью всплывающего окна каждую миллисекунду, люди вокруг суетятся от беспокойства, и я не знаю, о чем они говорят...
Проблемы онлайн? При чем тут я (🤪) Это точно не моя проблема, но на всякий случай вспомним, что мы сегодня делали.
**Что вы наделали? **Система средней платформы онлайн. **Что изменилось? **Добавлен интерфейс сериализации для некоторых классов и добавленserialversionUID
... Что будет причиной этого?Ошибка вызова интерфейса... COE...
После быстрого свайпа я сразу очнулся от сна и начал смотреть WeChat компании, мониторинг и доступность интерфейса.Увидев, что все данные в норме и верны, я постепенно почувствовал облегчение.
Нани? Мы не используем сериализацию Java?
Оглядываясь назад на то, что я знаю о сериализации, я открывал различные статьи о сериализации, и все они указывают мне на ответ:Мое изменение определенно повлияет на сериализацию, программа сообщит об ошибке, как показано ниже.
Exception in thread "main" java.io.InvalidClassException: ser.demo.StuDemo; local class incompatible: stream classdesc serialVersionUID = 6395135316924936201, local class serialVersionUID = 1
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1843)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1713)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2000)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1535)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
at ser.demo.App.main(App.java:27)
В настоящее время в Интернете нет сообщений об ошибках, есть только одна возможность, а именно: нашRPC框架
Собственный метод сериализации не используется. Архитектор был в нерешительности.После консультации, как я догадался, он также узнал от архитектора еще несколько методов сериализации, таких как: MessagePack, Hessian и т.д.
Общие методы сериализации
Java-сериализация
Java-сериализацияЭто преобразование объекта в массив байтов двоичного представления и достижение цели сохранения путем сохранения или передачи этих двоичных массивов.
Чтобы добиться сериализации, необходимо реализовать интерфейс java.io.Serializable. Десериализация — это процесс, противоположный сериализации, то есть процесс преобразования бинарных массивов в объекты.При десериализации необходимо иметь шаблон исходного класса для преобразования Основной метод восстановления объекта заключается в следующих двух методах: Роль интерфейса Serializable заключается в том, чтобы определить, реализована ли сериализация и согласованы ли объекты до и после.
Сериализация: java.io.ObjectOutputStream#writeObject0
Десериализация: java.io.ObjectInputStream#readObject0
Взяв в качестве примера тестовый класс (StuDemo), сериализованный результат выглядит следующим образом:
// 序列化
FileOutputStream fos = new FileOutputStream("C:\\Users\\Kerwin\\Desktop\\log\\object.out");
ObjectOutputStream oos = new ObjectOutputStream(fos);
StuDemo demo = new StuDemo("Kerwin");
oos.writeObject(demo);
oos.flush();
oos.close();
// 结果如下
// sr ser.demo.StuDemoX??莅 L namet Ljava/lang/String;xpt Kerwin
Куча перевёрнутых символов, но всё равно видно, что содержимое файла примерно указывает на некий класс, какие там поля, соответствующие значения и прочая информация.
Сериализация MessagePack
MessagePack(сокращенно Msgpack) — это эффективный формат двоичной сериализации, который позволяет обмениваться данными между языками, такими как JSON, но он быстрее и меньше, чем JSON.
Быстрее и меньше означает более высокую производительность, как это достигается?
Когда Msgpack сериализуется, поля не будут помечены ключом и будут храниться только в порядке полей.Подобно массиву, его метод кодированиятип + длина + содержание,Следующее:
Этот эффективный метод кодирования имеет некоторые ограничения, такие как:
- Сервер не может добавлять поля в любом месте по своему желанию, потому что, если клиент не обновится, десериализация завершится ошибкой.
- Инструментарий класса коллекции, предоставляемый сторонним пакетом, нельзя использовать в качестве возвращаемого значения.
Он используется следующим образом:
// 其中 StuDemo 类需要增加 @Message 注解标识需要被MessagePack序列化
// MessagePack 序列化方式不需要依赖 Serializable
public static void main(String[] args) throws IOException {
StuDemo demo = new StuDemo("Kerwin");
MessagePack pack = new MessagePack();
// 序列化
byte[] bytes = pack.write(demo);
// 反序列化
StuDemo res = pack.read(bytes, StuDemo.class);
System.out.println(res.getName());
}
PS: RPC-инфраструктура нашей компании в настоящее время использует метод сериализации MessagePack, и поэтому при настройке serialVersionUID выше не возникает проблем. Точно так же, с учетом ограничений базовой сериализации, в нашем новом документе также четко упоминаются вышеуказанные ограничения, такие как поля, которые должны быть добавлены в конце и т. д.
сериализация гессиана2
Hessian — это динамическая типизированная, двоичная, компактная и переносимая на разные языки структура сериализации.На основе Hessian производительность и степень сжатия Hessian2 значительно улучшены.
Hessian будет хранить все атрибуты сложных объектов в структуре, аналогичной Map для сериализации, поэтому, когда в родительском классе и подклассе есть переменные-члены с тем же именем, он сначала сериализует подкласс, а затем сериализует родительский класс, поэтому он приведет к тому, что значение переменной-члена с тем же именем подкласса будет перезаписано родительским классом и т. д.
Он имеет восемь основных целей дизайна,Официальный сайт:
- Типы сериализации должны быть самоописываемыми, т. е. не требуются определения внешней схемы или интерфейса.
- Должен быть независимым от языка, включая поддержку языков сценариев
- Должен быть доступен для чтения или записи за один проход
- Должен быть максимально компактным (сжатым)
- должно быть просто
- должно быть как можно быстрее
- Строки Unicode должны поддерживаться
- Должен поддерживать 8-битные двоичные данные
- Шифрование должно поддерживаться
Он используется следующим образом:
public class StuHessianDemo implements Serializable {
private static final long serialVersionUID = -640696903073930546L;
private String name;
public StuHessianDemo(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static void main(String[] args) throws IOException {
StuHessianDemo hessianDemo = new StuHessianDemo("Kerwin");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
HessianOutput hessianOutput = new HessianOutput(stream);
hessianOutput.writeObject(hessianDemo);
ByteArrayInputStream inputStream = new ByteArrayInputStream(stream.toByteArray());
// Hessian的反序列化读取对象
HessianInput hessianInput = new HessianInput(inputStream);
System.out.println(((StuHessianDemo) hessianInput.readObject()).getName());
}
// 结果:Kerwin
Основание для выбора
Из вышеизложенного мы узнали о нескольких часто используемых методах сериализации, их преимуществах и недостатках.Например, MessagePack — это максимальное сжатие и скорость, а Hessian2 полагается на интерфейс Serializable.На основе обеспечения безопасности и информативности, как как можно больше Стремление к использованию пространства, эффективности и т. д., а метод сериализации Java всегда подвергался критике, и сложно дождаться элегантного зала Поэтому, когда каркас RPC выбирает базовый метод сериализации, необходимо выбирать определенную последовательность в соответствии со своими потребностями.
Выбор основан на следующем, с приоритетом от высокого к низкому:
небольшая мысль
Статус сериализации JSON
На самом деле сериализация JSON является наиболее знакомым методом сериализации. Для него не требуется реализовывать сам интерфейс Serializable. Почему большинство RPC-фреймворков не используют его в качестве метода сериализации по умолчанию?
После понимания вышеприведенного содержания мы знаем, что ключ по-прежнему заключается в производительности, эффективности и накладных расходах, поскольку JSON — это структура сериализации текстового типа, которая использует KEY-VALUE для хранения данных, что является дополнительным пространством для сериализации. больше, не говоря уже о необходимости полагаться на отражение при десериализации, поэтому производительность еще больше снижается.
Однако сам JSON чрезвычайно удобочитаем, поэтому он используется в качестве стандарта де-факто для протокола HTTP в Интернете.
Зачем настраивать serialVersionUID
В «Effect Java» упоминается предложение:
Независимо от выбранного вами метода сериализации, объявите явный UID сериализованной версии для каждого написанного вами сериализуемого класса.
Зачем архитектору напоминать мне о его реализации? Почему в книге так сказано?
Полное имя разложенного serialVersionUID: последовательный UID версии, последовательный UID версии, каждый сериализуемый класс имеет длинное поле для явного указания номера, если кодер не определяет его, система будет использовать структуру этого класса. Криптографическая хэш-функция. (SHA-1), чтобы идентификационный номер автоматически генерировался во время выполнения, на который влияют имя класса, имя интерфейса, общедоступные и защищенные переменные-члены, после внесения связанных изменений, таких как добавление важных общедоступных методов, которые повлияют на UID. , что приводит к возникновению исключений.
Так что это дело привычки и избежание потенциальных рисков.
Суммировать
К этому моменту мы узнали, что сериализация Java, которую мы изучили ранее, настолько непрактична (даже до такой степени, что на нее можно жаловаться), и мы также знаем основные секреты некоторых мер предосторожности при использовании фреймворка (таких как добавление полей в MsgPack). Ниже приведены некоторые небольшие предложения по сериализации:
- независимо от того, зависим он или нет
Serializable
, параметры интерфейса рекомендуются для реализации интерфейса сериализации. - Если вы реализуете интерфейс сериализации, вы должны сами реализовать serialVersionUID.
- Объекты параметров интерфейса не должны использовать специальные типы данных (такие как сторонние коллекции MsgPack и т. д.), чрезмерно сложные структуры (наследование и т. д.), иначе возникнет множество необъяснимых проблем.
- Когда возникает несогласованность данных сервера/клиента, первое, что приходит на ум, — это проблема сериализации, и тщательно исследуются характеристики текущего метода сериализации.
Если вы считаете этот контент полезным:
- Конечно, ставьте лайки и поддерживайте~
- Кроме того, вы можете искать и следить за официальной учетной записью "это Кервин», давайте вместе пойдем по дороге технологий~ 😋
использованная литература
- Официальный сайт MsgPack
- "Эффект Ява"