В Java, как я могу создать «прокси-оболочку» вокруг объекта, которая вызывает метод при изменении свойства? - PullRequest
4 голосов
/ 23 января 2009

Я ищу что-то похожее на шаблон Proxy или Динамические прокси-классы , только для того, чтобы я не хотел перехватывать вызовы методов, прежде чем они будут вызваны на реальном объект, но я бы хотел перехватить свойства, которые меняются. Я бы хотел, чтобы прокси мог представлять несколько объектов с разными наборами свойств. Что-то вроде класс Proxy в Action Script 3 будет в порядке.

Вот чего я хочу добиться в целом:

У меня есть поток, работающий с объектом, который управляет списком значений (чисел, строк, объектов), которые были переданы другими потоками в программе, поэтому класс может позаботиться о создании регулярных постоянных снимков на диске для Цель проверки приложения. Этот объект персистора управляет «грязным» флагом, который указывает, изменился ли список значений со времени последней контрольной точки, и должен заблокировать список, пока он занят записью его на диск.

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

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


Редактировать : В качестве альтернативы, есть ли в Java универсальные сеттеры (как в PHP 5), то есть метод, который вызывается, если свойство не существует? Или есть тип объекта, к которому я могу добавить свойства во время выполнения?

Ответы [ 4 ]

3 голосов
/ 23 января 2009

Если под «свойствами» вы имеете в виду свойства JavaBean, то есть представляли собой метод получения и / или метода установки, то вы можете использовать динамический прокси для перехвата метода набора.

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

На самом деле, самый простой способ сделать это, вероятно, с помощью AspectJ и определением точки set () (которая будет перехватывать доступ к полю на уровне байтового кода).

2 голосов
/ 23 января 2009

Шаблон проектирования, который вы ищете: Дифференциальное исполнение. Я верю.

Как работает дифференциальное выполнение?

Это вопрос, на который я ответил, который касается этого.

Однако могу ли я предложить вам использовать обратный вызов? Вам придется прочитать об этом, но общая идея заключается в том, что вы можете реализовать интерфейсы (часто называемые слушателями), которые активируются при «чем-то интересном». Например, наличие структуры данных для изменения.

Обязательные ссылки:

Wiki Дифференциальное исполнение

Wiki Callback

Хорошо, вот ответ, который я вижу. Дифференциальное выполнение - O (N) время. Это действительно разумно, но если это не сработает для вас, обратные вызовы будут. Обратные вызовы в основном работают путем передачи метода по параметру вашему классу, который изменяет массив. Этот метод примет измененное значение и местоположение элемента, передаст его по параметру в «класс хранения» и соответствующим образом изменит значение. Так что да, вы должны подкреплять каждое изменение вызовом метода.

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

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

Тогда есть отражение ... У Java есть отражение, и я уверен, что вы можете написать что-нибудь, используя это для этого. Тем не менее, размышление, как известно, медленно. Не говоря уже о боли в коде (на мой взгляд).

Надеюсь, это поможет ...

1 голос
/ 13 ноября 2010

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

В любом случае я разместил полное объяснение и код в моем блоге здесь: http://clockwork -fig.blogspot.com / 2010/11 / JavaBean-свойство-изменение-слушателем-with.html

1 голос
/ 24 января 2009

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

Таким образом, на самом деле объекты, которые вы хотите отслеживать, - это не удобные бины, а возрождение структур Си. Единственный способ, который приходит мне в голову, - это вызов Field Access в JVMTI .

.
...