Общие структуры уведомлений о событиях, основанные на аннотациях

StackOverflow https://stackoverflow.com/questions/178700

Вопрос

В то время как простые, управляемые интерфейсом фреймворки уведомления о событиях на Java существуют с докембрийских времен (напримерjava.beans.PropertyChangeSupport), фреймворки становятся все более популярными для использования уведомлений о событиях, основанных на аннотациях, вместо этого.

Для примера см. JBossCache 2.2.Класс listener имеет свои методы listener с аннотациями, а не в соответствии с жестким интерфейсом.Это довольно легко программировать и легче читать, поскольку вам не нужно писать пустые реализации обратных вызовов прослушивателя, которые вас не интересуют (и да, я знаю о суперклассах адаптера прослушивателя).

Вот пример из документов JBossCache:

@CacheListener
public class MyListener {
   @CacheStarted
   @CacheStopped
   public void cacheStartStopEvent(Event e) {
         switch (e.getType()) {
            case Event.Type.CACHE_STARTED:
               System.out.println("Cache has started");
               break;    
            case Event.Type.CACHE_STOPPED:    
               System.out.println("Cache has stopped");
               break;    
         }
   }    

   @NodeCreated    
   @NodeRemoved
   @NodeVisited
   @NodeModified
   @NodeMoved
   public void logNodeEvent(NodeEvent ne) {
         log("An event on node " + ne.getFqn() + " has occured");
   }

}

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

Итак, прежде чем я отправлюсь в путь написания универсального фреймворка, я надеялся, что кто-то это уже сделал.Кто-нибудь сталкивался с подобным?

Это было полезно?

Решение

Вы уже можете сделать это сегодня с помощью Автобус событий.

Следующий пример взят из Руководство по началу работы EventBus.Строка состояния, которая обновляется на основе опубликованных событий, и нет необходимости регистрировать элемент управления / виджет строки состояния в качестве прослушивателя издателя (ов).Без EventBus строку состояния необходимо будет добавить в качестве прослушивателя ко многим классам.Строка состояния также может быть создана и уничтожена в любое время.

public StatusBar extends JLabel {
    public StatusBar() {
        AnnotationProcessor.process(this);
    }
    @EventSubscriber(eventClass=StatusEvent.class)
    public void updateStatus(StatusEvent statusEvent) {
        this.setText(statusEvent.getStatusText();
    }
}

Подобный проект является ELF (Фреймворк прослушивателя событий) но это кажется менее зрелым.

В настоящее время я изучаю фреймворки уведомлений о событиях на Программирование, управляемое публикацией и подпиской на события | Kev Spring vs Java EE Dev и последующие статьи.

Другие советы

Я сделал http://neoevents.googlecode.com для обработки такого рода обработчика событий на основе аннотаций.

        @actionPerformed
        private void onClick() {
                //do something
        }

        protected void initComponents() {
                JButton button = new JButton("Click me!!!");
                button.addActionListener(new ActionListener(this) );
        }

Это выглядит так просто, как я и ожидал.Аннотации доступны для каждого отдельного прослушивателя в J2SE.

Не путайте сложное с умным.Мне кажется , что это было бы:

  1. Кошмар для отладки
  2. Трудно уследить (с точки зрения технического обслуживания, или кто-то пытается что-то изменить через 6 месяцев)
  3. Полный if (event instanceof NodeCreatedEvent) как код.Почему это лучше, чем подкласс adapter Я понятия не имею!

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

Это то, что делает интерфейсы привлекательными для меня для реализаций шаблонов observer, таких как Java event model.Такие инструменты, как eclipse, могут автоматически генерировать заглушки методов, чтобы вы не могли ошибиться в подписях.В вашем примере очень просто использовать неправильный тип параметра и никогда не знать об этом, пока не произойдет событие (которое может быть ошибкой через несколько месяцев).

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

package a.b.c;

public interface SomeListener {
    void fee();
    void fie();
    void fo();
    void fum();
}

и хотел создать экземпляр listener.Вы могли бы написать

package x.y.z;

import a.b.c.SomeListener;
import com.javadude.annotation.Bean;
import com.javadude.annotation.NullObject;

@Bean(nullObjectImplementations = {@NullObject(type = SomeListener.class) })
public class Foo extends FooGen implements SomeListener {
    @Override
    public void fie() {
        // whatever code you need here
    }
}

Чтобы создать источник для этих событий, вы можете написать

package a.b.c;

import com.javadude.annotation.Bean;
import com.javadude.annotation.Observer;

@Bean(observers = {@Observer(type = SomeListener.class)})
public class Source extends SourceGen {
    // SourceGen will have add/remove listener and fire methods
    //   for each method in SomeListener
}

Видишь http://code.google.com/p/javadude/wiki/Annotations если вам интересно.Возможно, это натолкнет вас и на другие идеи.

Я также думал об универсальной структуре событий, основанной на аннотациях.Мне нравятся преимущества, предоставляемые статической типизацией, но текущая модель событий, управляемая интерфейсом, болезненна в использовании (уродливый код).Можно ли было бы использовать пользовательский процессор аннотаций для выполнения некоторой проверки во время компиляции?Это могло бы помочь добавить немного недостающей "безопасности", к которой мы все привыкли.

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

Вот пример того, как может выглядеть универсальный фреймворк, с которым я играл:

public class ExampleProducer {

    private EventSupport<ActionEvent> eventSupport;

    public ExampleProducer() {
        eventSupport = new EventSupport<ActionEvent>(this);
    }

    @AddListenersFor(ActionEvent.class)
    public void addActionListener(Object listener)
    {
        eventSupport.addListener(listener);
    }

    @RemoveListenersFor(ActionEvent.class)
    public void removeActionListener(Object listener)
    {
        eventSupport.removeListener(listener);
    }

    public void buttonClicked() {
        eventSupport.fire(new ActionEvent(this, 
                              ActionEvent.ACTION_PERFORMED, "Click"));
    }
   }

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

public class ExampleListener
{   
  private ExampleProducer submitButton;

  public ExampleListener()
  {
    submitButton = new ExampleProducer();
    EventSupport.autoRegisterEvents(this);
  }

  @HandlesEventFor("submitButton")
  public void handleSubmitButtonClick(ActionEvent event)
  {
    //...some code to handle the event here
  }
}

Здесь, EventSupport имеет статический метод, который использует отражение для автоматической регистрации прослушивателя в производителе событий.Это избавляет от необходимости вручную регистрироваться в источнике события.Пользовательский обработчик аннотаций может быть использован для проверки того, что @HandlesEventFor аннотация относится к фактическому полю ExampleListener.Обработчик аннотаций мог бы выполнять и другие проверки, например, чтобы убедиться, что сигнатура метода обработчика событий совпадает с одним из методов регистрации на ExampleProducer (по сути, та же проверка, которая могла бы быть выполнена во время регистрации).

А ты как думаешь?Стоит ли тратить некоторое время на полноценную разработку?

Вот аналогичный проект под названием СЬЕС.

public class SomeController {

private Calculator c1 = new Calculator();
private Calculator c2 = new Calculator();

public SomeController() {
    c1.registerReceiver(this);
    c2.registerReceiver(this);
    c1.add(10, 10);
    c2.add(20, 20);
}

@EventReceiver(handleFor="c1")
public void onResultC1(Calculator.Event e) {
    System.out.println("Calculator 1 got: " + e.result);
}

@EventReceiver(handleFor="c2")
public void onResultC2(Calculator.Event e) {
    System.out.println("Calculator 2 got: " + e.result);
}

@EventReceiver
public void onResultAll(Calculator.Event e) {
    System.out.println("Calculator got: " + e.result);
}
}

public class Calculator {

private EventHelper eventHelper = new EventHelper(this);

public class Event {

    long result;

    public Event(long result) {
        this.result = result;
    }
}

public class AddEvent extends Event {

    public AddEvent(long result) {
        super(result);
    }
}

public class SubEvent extends Event {

    public SubEvent(long result) {
        super(result);
    }
}

public void unregisterReceiver(Object o) {
    eventHelper.unregisterReceiver(o);
}

public void registerReceiver(Object o) {
    eventHelper.registerReceiver(o);
}

public void add(long a, long b) {
    eventHelper.fireEvent(new AddEvent(a + b));
}

public void sub(long a, long b) {
    eventHelper.fireEvent(new SubEvent(a - b));
}

public void pass(long a) {
    eventHelper.fireEvent(new Event(a));
}
}

Я думаю, что это очень просто в использовании.

Вы также можете проверить Мбасадор Он управляется аннотациями, очень легкий и использует слабые ссылки (таким образом, его легко интегрировать в среды, где управление жизненным циклом объектов осуществляется с помощью фреймворка, такого как spring, guice или somethign).

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top