Глубокое клонирование объектов Java (не бобов) - PullRequest
8 голосов
/ 09 февраля 2011

В проекте, над которым я сейчас работаю, есть много объектов, которые сериализуются, чтобы получить полную копию существующего объекта.Это работает нормально, пока у нас не будет нескольких вызовов во время выполнения, в некоторых случаях у нас будет 100, 200 или даже 1000 вызовов между компонентами, и именно здесь мы сталкиваемся с головной болью производительности.

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

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

Я также попытался использовать CloneUtils (проект sourceforge), который также работает медленнее (мы вообще не используем Hibernate).Spring BeanUtils не является опцией (я предполагаю из документов, что он использует только bean-компоненты, то есть самоанализ, и в случае, если я использую его, если какие-либо поля предоставляются с использованием нестандартного метода доступа, мы не сможем их скопировать).

Есть у кого-нибудь идеи, улучшить производительность, все еще работая над разными копиями.У нас есть опция, которая ускорит процесс в случае, если мы обеспечим наши собственные методы копирования вместо сериализации, но у этого есть обратная сторона - обновлять эти методы каждый раз, и если мы забудем, мы можем потерять функциональность.

Ответы [ 4 ]

1 голос
/ 09 февраля 2011

Вы можете избежать отражения путем генерации динамического класса, например, используя cglib .Для каждого используемого вами класса вы должны сгенерировать «класс клонеров», содержащий код, необходимый для копирования.Это сделало бы отражение ненужным, при условии, что все поля по крайней мере являются частными для пакета, и вы помещаете класс копира в один и тот же пакет.Вам понадобится ctor по умолчанию и также нет окончательных полей.

Здесь сериализация имеет преимущество, поскольку она создает объекты с использованием sun.misc.Unsafe.

Реализация метода deepClone в каждомкласс тоже может быть вариантом.Это может быть даже объединено с идеей класса клонеров.

0 голосов
/ 09 февраля 2011

То, что вы описываете, является подходом ружья к управлению изменяемым состоянием.Попытка ускорить клонирование даст вам лишь ограниченные улучшения (скажем, на порядок).Кроме того, как вы клонируете сокет, поток или соединение с базой данных?

Что вам действительно нужно, так это реорганизовать ваше приложение с надлежащим разделением команд / запросов.Таким образом, вы будете знать, где вы меняете свои объекты, а где нет.Вы можете использовать модульные тесты, чтобы проверить это, если не уверены.

Существует ряд техник, которые могут вам помочь - вы можете изменить некоторые из ваших объектов на неизменяемые (чтобы вы могли делиться ими, создавая новые копии при мутации);вы можете заставить изменчивые объекты реализовывать интерфейсы только для чтения и использовать представление RO в графическом интерфейсе и т. д.

0 голосов
/ 09 февраля 2011

Я сомневаюсь, что вы можете сделать так, чтобы значительно повысить производительность, следуя упомянутым выше подходам. К сожалению, для копирования объекта требуется время.

Думая немного латерально и четко в зависимости от того, сколько у вас памяти, а также от отношения читателей к записи (особенно если у вас много читателей для каждой записи), как насчет создания кэша копий?

0 голосов
/ 09 февраля 2011

Просто подскажу, как можно улучшить производительность в таких случаях: используйте шаблон прототип , если вы его еще не используете. Возможно, вы получите некоторое улучшение

...