События CDI fire () создают новые экземпляры наблюдателей - PullRequest
0 голосов
/ 14 июня 2019

Я пишу приложение JavaFX (JavaSE) с CDI (Weld). Я пытаюсь использовать события CDI для замены ужасной системы событий JavaFX (свойства JavaFX).

Я смог позволить CDI правильно создавать мои контроллеры JavaFX. Это означает, что при загрузке FXML контроллер создается CDI (с использованием FXLoader.setControllerFactory). К сожалению, как только я добавил @Observe в один контроллер, CDI начал создавать несколько экземпляров этого контроллера. это безумие.

Похоже, я просто не понимаю правильную семантику fire(). С каких это пор fire() будут создавать наблюдатели ?! Может быть, это как-то связано с @Dependent scope.

Я сделал перехватчик для отправки события, когда какое-либо свойство где-либо изменяется (в моем случае это фоновая задача, которая обновляет свойство Progress). (Не обращайте внимания на ObservableSourceLiterral и @ObservableSource, это просто не для того, чтобы запускать события для всех)

@ObservableProperty
@Interceptor
public class CDIPropertyWatcher {
    @Inject
    private Event<PropertyChangedEvent> listeners;

    @AroundInvoke
    public Object onPropertyCalled(InvocationContext ctx) throws Exception {
        String method = ctx.getMethod()
                .getName();
        if (method.startsWith("set")) {
            Object result = ctx.proceed();
            String propertyName = method.substring(3, 4)
                    .toLowerCase() + method.substring(4);
            listeners.select(new ObservableSourceLiterral(ctx.getTarget().getClass().getSuperclass()))
                    .fire(new PropertyChangedEvent(ctx.getTarget(), propertyName));

            return result;
        } else {
            return ctx.proceed();
        }
    }
}

Вот установщик в моем классе Задач:

@ObservableProperty
public void setProgress(double progress) {
      this.progress = progress;
}

Это метод моего контролера, ответственного за получение события:

public void onProgressTaskChanged(@Observes @ObservableSource(Task.class) PropertyChangedEvent evt)
{
        Double progress = evt.getSource(Task.class).getProgress();
        System.out.println("onProgressTaskChanged "+progress+" "+this);
        if (progressBar!=null)
        {
            Platform.runLater(() -> progressBar.setProgress(progress));
        }
}

Я ожидаю, что когда я запускаю событие, оно принимается фактическими существующими наблюдателями, а не создает новых.

1 Ответ

0 голосов
/ 17 июня 2019

Таким образом, уловка здесь - это действительно область действия @Dependent компонента с наблюдателем.

В соответствии со спецификацией всегда будет создаваться новый экземпляр для получения уведомления, который впоследствии будет уничтожен.Соответствующими частями спецификации являются 5.5.6 Вызов методов-наблюдателей и 6.4.2 Уничтожение объектов с областью видимости @ Dependent .

Чтобы объяснить, почему он ведет себя так -для других (обычных) областей у вас всегда есть 0 или 1 экземпляр этого данного компонента в контексте, и уведомление может легко выбрать существующий или создать новый и сохранить его в контексте.Принимая во внимание, что с @Dependent вы можете иметь от 0 до n экземпляров, которые привели бы к нескольким уведомлениям на каждое событие, запущенное, если бы оно велось по-другому.

Попробуйте вместо этого использовать некоторую обычную область (приложение / запрос / сеанс / разговор), и вам следуетполучить поведение, которое вы ожидаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...