У кого-нибудь есть пример кода для использования cglib MulticastDelegate для выполнения чего-то вроде событий C#?

В то время как C# имеет языковую поддержку для делегирования и событий в Java, мы должны либо использовать анонимные внутренние классы для привязки, либо использовать код отражения http://oatv.com/pub/a/onjava/2003/05/21/delegates.html. На этих страницах комментариев есть подсказка о CGLib Multicast Delegates, но Google-коды, похоже, не знают ни одного примера кода для этого класса. У кого-нибудь есть ссылка на рабочий пример, а у кого-то есть ссылка?

1 ответ

Решение

I know this question is old but maybe somebody is wondering about the same thing one day. Для нормального C#-like delegate, you would probably use the MethodDelegate, не MulticastDelegate, Assume, we have simple Java POJO bean:

public class SimpleBean {
  private String value;
  public String getValue() {
    return value;
  }
  public void setValue(String value) {
    this.value = value;
  }
}

тогда мы можем создать инструментированный (неотражающий) делегат следующим образом:

public static interface BeanDelegate {
  String getValueFromDelegate();
}

@Test
public void testMethodDelegate() throws Exception {
  SimpleBean bean = new SimpleBean();
  bean.setValue("Hello world!");
  BeanDelegate delegate = (BeanDelegate) MethodDelegate.create(
      bean, "getValue", BeanDelegate.class);
  assertEquals("Hello world!", delegate.getValueFromDelegate());
}

Есть несколько вещей, которые стоит отметить в этом примере:

  • Заводской метод MethodDelegate#create принимает только одно имя метода в качестве второго аргумента. Это метод MethodDelegate будет прокси для вас.

  • Для объекта должен быть определен метод без аргументов, который передается фабричному методу в качестве первого аргумента. Таким образом MethodDelegate не так сильно, как могло бы быть.

  • Третий аргумент должен быть интерфейсом с ровно одним аргументом. MethodDelegate реализует этот интерфейс и может быть приведен к нему. Когда метод вызывается, он вызывает метод прокси для объекта, который является первым аргументом.

Есть некоторые недостатки / подводные камни:

  • CGlib создает новый класс для каждого прокси. В конце концов, это засорит ваше пространство кучи постоянного поколения. (Это может вызвать проблемы в долгосрочной перспективе.)

  • Вы не можете использовать прокси-методы, которые принимают аргументы. (Это отстой.)

  • Если ваш интерфейс принимает аргументы, делегирование метода просто не будет работать без генерируемого исключения (возвращаемое значение всегда будет null). Если ваш интерфейс требует другого возвращаемого типа (даже если он более общий), вы получите IllegalArgumentException, (Это странно.)

MulticastDelegate работает немного по-другому. На этот раз нам нужен компонент, который на самом деле реализует интерфейс с помощью одного метода:

public class SimpleMulticastBean implements DelegatationProvider {
  private String value;
  public String getValue() {
    return value;
  }
  public void setValue(String value) {
    this.value = value;
  }
}

public interface DelegatationProvider {
  void setValue(String value);
}

На этот раз интерфейс - называется DelegatationProvider в примере - должен предложить один метод (как и раньше). Этот интерфейс должен быть реализован любым объектом, добавленным в этот прокси-сервер делегирования. Это можно сделать следующим образом:

@Test
public void testMulticastDelegate() throws Exception {
  MulticastDelegate multicastDelegate = MulticastDelegate.create(
      DelegatationProvider.class);
  SimpleMulticastBean first = new SimpleMulticastBean();
  SimpleMulticastBean second = new SimpleMulticastBean();
  multicastDelegate = multicastDelegate.add(first);
  multicastDelegate = multicastDelegate.add(second);

  DelegatationProvider provider = (DelegatationProvider)multicastDelegate;
  provider.setValue("Hello world!");

  assertEquals("Hello world!", first.getValue());
  assertEquals("Hello world!", second.getValue());
}

Опять же, эта реализация имеет свои недостатки:

  • Объекты должны реализовывать интерфейс с одним методом. Это отстой для сторонних библиотек и неудобно, когда вы используете CGlib, чтобы творить магию, когда эта магия подвергается воздействию обычного кода. Кроме того, вы могли бы легко реализовать свой собственный делегат (но без байт-кода, но я сомневаюсь, что вы выиграете так много по сравнению с делегированием вручную).

  • Когда ваши делегаты возвращают значение, вы получите только значение последнего добавленного вами делегата. Все остальные возвращаемые значения теряются (но в какой-то момент их получает делегат многоадресной рассылки).

Для дальнейшего чтения: я получил вдохновение и суммировал все, что я знаю о cglib, в статье в блоге.

Другие вопросы по тегам