CDI 2.0, Java SE - метод условного наблюдателя, не вызываемый в сварном шве 3.0.5. Окончательный - PullRequest
0 голосов
/ 12 марта 2019

У меня проблема с методом условного наблюдателя, который не вызывается.Вот код, начинающийся с теста junit:

    import static org.hamcrest.CoreMatchers.notNullValue;
    import static org.hamcrest.CoreMatchers.nullValue;
    import static org.junit.Assert.assertThat;

    import javax.enterprise.inject.Instance;
    import javax.enterprise.inject.se.SeContainer;
    import javax.enterprise.inject.se.SeContainerInitializer;

    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;

    public class CDIMinimalConditionalObserverTest
    {
        private final static Logger LOGGER = LogManager.getLogger(CDIMinimalConditionalObserverTest.class);

        private SeContainer container;

        @Before public void before()
        {
            LOGGER.debug("before");
        final SeContainerInitializer initialiser = SeContainerInitializer.newInstance();
        container = initialiser.initialize();
    }

    @After public void after()
    {
        container.close();
        LOGGER.debug("after");
    }

    @Test public void testObservation_observationInManagedNonExistentConditionalObservers()
    {
        CDIMinimalConditionalObserverEvent event = new CDIMinimalConditionalObserverEvent();
        container.getBeanManager().fireEvent(event);
        assertThat(event.msg, nullValue());
    }

    @Test public void testObservation_observationInManagedExistentConditionalObservers()
    {
        // create observer by selection
        Instance<CDIMinimalConditionalObserver> instance = container.select(CDIMinimalConditionalObserver.class);
        CDIMinimalConditionalObserver observer = instance.get();
        assertThat(observer, notNullValue());

        CDIMinimalConditionalObserverEvent event = new CDIMinimalConditionalObserverEvent();
        container.getBeanManager().fireEvent(event);
        observer.doSomething();
        assertThat(event.msg, notNullValue());
    }
}

Вот класс с методом условного наблюдателя:

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.event.Reception;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import de.jmda.sandbox.cdi.se.CDIMinimalTests.SimpleInnerEvent;

/**
 * {@link Model} annotation assigns non-dependent scope and thereby makes it possible to make {@link
 * #observation(SimpleInnerEvent)} conditional
 */
@ApplicationScoped public class CDIMinimalConditionalObserver
{
    private final static Logger LOGGER = LogManager.getLogger(SimpleConditionalObserver.class);

    public CDIMinimalConditionalObserver()
    {
        LOGGER.debug("constructor");
    }

    @PostConstruct public void postConstruct()
    {
        LOGGER.debug("post construct");
    }

    @PreDestroy public void preDestroy()
    {
        LOGGER.debug("pre destroy");
    }

    public void observation(@Observes(notifyObserver=Reception.IF_EXISTS) CDIMinimalConditionalObserverEvent event)
    {
        event.msg = "observation";
        LOGGER.debug(event.msg);
    }

    public void doSomething()
    {
        LOGGER.debug("doing something");
    }
}

И, наконец, класс событий:

public class CDIMinimalConditionalObserverEvent { String msg; }

Тест не пройден, поскольку event.msg имеет значение null, хотя это не должно быть.Выходные данные журналов не показывают никаких результатов «наблюдения».Тест проходит, если условие снято.

Есть идеи?Спасибо!

1 Ответ

0 голосов
/ 12 марта 2019

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

Вы можете видеть, что получение ApplicationScoped Бина через

final Instance<App> select = container.select(App.class);
final App app = select.get();

Действительно ли возвращает экземпляр прокси .
На данном этапе все еще нет App Bean-компонента, привязанного к контексту приложения.

enter image description here

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

Удаление Reception.IF_EXISTS просто сигнализирует CDI, что он должен немедленно создать и присоединить к контексту базовый экземпляр, чтобы он мог принимать входящие события независимо от того, что.

Такое поведение прокси задокументировано в спецификации (мне нужно найти страницу), и поэтому Бину требуется конструктор без аргументов.

Dependent scope Бины не страдают от этой проблемы, поскольку они создаются каждый раз, когда это необходимо, с нуля и не отслеживаются платформой. Для одноэлементных, сеансовых или запрашиваемых объектов EJB требуется прокси-сервер для их правильного управления.


Dependent scope Bean, вы можете видеть, что это "чистый" экземпляр

enter image description here

...