Подтвердить что ты не робот

Есть ли там API-интерфейс для отслеживания объектов/версий Java API?

Я знаю, по крайней мере, два усилителя байт-кода, которые изменяют "объектную модель" во время выполнения, чтобы транзакция выполнялась прозрачно. Один из них является частью Versant VOD, который я использую на работе каждый день, а другой является частью Terracotta. Есть, вероятно, немало других, например, в ORM, но Versant позаботится об этом в моей компании.

Мой вопрос: есть ли такой API с открытым исходным кодом, который можно использовать на нем самостоятельно, независимо от продукта, для которого он был разработан? Вы можете сказать "hackable" API. Он должен отслеживать изменения, а не читать доступ, что значительно замедлит работу кода. Другими словами, он не требует явной блокировки чтения/записи. Для этого требуется либо доступ ко всем классам, которые выполняют изменения, а не только к модели данных, или для сохранения сравнения в памяти требуется некоторая форма "предыдущей версии".

Проблема, которую я пытаюсь решить, заключается в том, что у меня есть "большие" (32K до 256K) графы объектов, которые "сериализованы" в (NoSQL) DB. Они долговечны и должны быть повторно сериализованы регулярно, чтобы иметь "историю" изменений. Но они довольно дороги для сериализации, и большинство изменений незначительны.

Я мог бы последовательно их сериализовать и запускать двоичный diff в потоке, но это очень интенсивно. Лучшим решением будет API, который изменит операции записи в модели на протокол, чтобы изменения, так что после того, как начальное "изображение" будет сохранено, необходимо сохранить только протокол.

Я нашел несколько вопросов о Apache Commons Beanutils для сравнения объектов, но это не полезно для изменений на месте; Мне нужно было бы сделать полный клон модели между каждой "бизнес-транзакцией".

Повторяю, я ищу "встроенный" API в рамках той же JVM, которая не связана с каким-либо внешним серверным приложением. API, содержащие встроенный код, в порядке, если они доступны в Win, Mac и Linux. API не должен быть в настоящее время упакован независимо; просто нужно извлечь его из "родительского проекта" для создания независимого API (лицензия родительского проекта должна разрешить это).

Графики объектов будут включать в себя множество больших массивов, и поэтому их необходимо поддерживать эффективно.

Изменения не желательны только для аудита, но для их повторного воспроизведения или отмены. Точнее, с десериализованным начальным графом и списком изменений я должен получить одинаковый конечный граф. Кроме того, начиная с конечного графика, должно быть возможно вернуться к первоначальному графику, применив изменения в обратном порядке. Это использует точно такую ​​же функциональность, но требует, чтобы протокол изменений сохранял старое значение в дополнение к новому значению.

Лицензия API должна быть совместима с коммерческим использованием.

[EDIT] До сих пор я не получил полезного ответа, и мне кажется, что я не хочу. Это оставляет мне только один вариант: сделайте это. Я отправлю ссылку здесь как ответ, когда у меня будет рабочая реализация, так как это следующий шаг в моем проекте, и я не могу идти вперед без него.

[EDIT] Я случайно обнаружил этот несколько смежный вопрос: Есть ли библиотека Java, которая может "diff" два объекта?

4b9b3361

Ответ 1

Kryo v1 имел сериализатор, который знает о последних данных, которые были сериализованы и только излучает дельта. При чтении он знает о последних полученных данных и применяет дельта. Дельта выполняется на уровне байта. Здесь сериализатору. Большая часть работы выполняется этот класс. Это можно использовать несколькими полезными способами, например, в сети, подобной Quake 3.

Это было опущено в Kryo v2, потому что AFAIK он никогда не использовался. Кроме того, у него не было широкого набора тестов. Его можно было портировать, хотя и может делать то, что вам нужно, или служить основой для того, что вам нужно.

Выше также размещены на сериализаторах JVM список рассылки.

Выполнение этого на уровне объекта было бы немного сложнее. Вы могли бы написать что-то похожее на FieldSerializer, который одновременно ходит по двум объектным графам. Это будет автономный код, но не сериализатор Kryo. На каждом уровне вы можете называть равным. Напишите байт, чтобы, когда вы читаете, вы знаете, был ли он равным. Если нет, используйте Kryo для записи объекта. Равные числа будут вызываться много раз для одного и того же объекта, особенно для глубоко вложенных объектов.

Другой способ, которым вы можете это сделать, - это сделать только выше для скаляров и строк, т.е. только значения, написанные классом Output. Проблема состоит в том, чтобы пройти два объектных графика. Чтобы использовать Kryo, я думаю, вам придется дублировать все сериализаторы, чтобы узнать о другом графике объектов.

Возможно, вы можете использовать Kryo со своим собственным Output, который собирает значения в списке, а не записывает их. Используйте это, чтобы "сериализовать" свой старый граф объектов. Теперь напишите другую версию собственного Output, которая берет этот список и использует его для сериализации вашего нового графа объектов. Каждый раз, когда значение записывается, сначала проверьте его со следующим объектом в своем списке. Если равно, напишите a 1. Если не равно, напишите 0 и затем значение.

Это может быть сделано с большей эффективностью пространства, используя первый вывод дважды, один раз на старом и один раз на новом графике. Теперь у вас есть два списка значений. Используйте их для записи битовой строки, обозначающей равные. Это экономит место при написании целого байта для каждого значения, но имеет накладные расходы дополнительного списка. Наконец, напишите все значения, которые не равны.

Чтобы завершить эту идею, вы должны иметь возможность десериализовать данные. Вам понадобится ваша собственная версия класса Input, которая берет список значений из старого графа объектов. Сначала ваш вход считывает битовую строку (или байт за значение). Для значения, которое было равно, оно возвращает значение из списка вместо чтения из данных. Если значение не было равным, оно вызывает супер метод для чтения из данных.

Я не уверен, будет ли это быстрее, чем делать это на уровне байтов. Если бы я должен был догадаться, я бы сказал, что это, вероятно, будет быстрее. При сохранении всех значений в списке будет много бокса/распаковки, и этот подход по-прежнему присваивает все поля, даже если они не изменились. Я сомневаюсь, что производительность будет проблемой в любом случае, поэтому я бы просто выбрал более простой подход. Трудно сказать, что это... воскресить дельта-материал или написать свои собственные классы Output/Input.

Если вам хочется вернуться в Крио, это, конечно, будет здорово.:)

Ответ 3

Я не знаю такого API, но он не может быть таким сложным:

Лучшим решением будет API, который модифицирует операции записи в модели, чтобы протоколировать изменения, так что после того, как начальное "изображение" будет сохранено, необходимо сохранить только протокол.

Я бы сказал, вам нужно всего 2 компонента: Action и ActionProcessor

Вам нужно только сохранить список (протокол) выполненных действий.

interface ActionProcessor{
    void perform(Action action);
    void undoToDate(Date date);
} 

iterface Action{
    Date getDate();
    void perform();
    void undo();
}      

Ответ 4

Насколько я знаю, GemFire ​​- это корпоративный продукт Gemstone (теперь VmWare), делающий что-то похожее на OODB с помощью Gemstone smalltalk, но затем для java. Джеймс Фостер создал серию видеороликов о том, как работает Gemstone. Я нашел их очень интересными. Gemstone имеет бесплатную версию для создания небольших (Seaside web) систем с.