0

我遇到了一个没有被调用的条件观察者方法的问题。这是代码,从一个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。日志输出不显示任何“观察”输出。如果条件被删除,则测试通过。

有任何想法吗?谢谢!

4

1 回答 1

0

当您的@ApplicationScopedBean 被发现时,它不会立即被实例化。
CDI足够聪明,可以仅在需要时初始化真实对象,即幕后对象。

你可以看到ApplicationScoped通过

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

确实返回一个代理实例。
在这个阶段,仍然没有AppBean 附加到 Application 上下文。

在此处输入图像描述

现在,尝试与该对象交互(即使只是通过调用toString),并且仅在 之后,触发事件。
您会注意到它确实有效,因为底层对象已通过其无参数构造函数进行实例化。

删除Reception.IF_EXISTS只是CDI表示它必须立即创建并附加到上下文底层实例,以便它无论如何都可以接受传入事件。

这种代理行为记录在规范中(我需要找到该页面),这就是 Bean 需要无参数构造函数的原因。

Dependent范围 Bean 不会遇到这个问题,因为它们是在每次需要时从头开始创建的,并且不会被框架跟踪。对于单例、会话或请求范围的 Bean,需要代理才能正确管理它们。


Dependentscope Bean,你可以看到它是一个“纯”实例

在此处输入图像描述

于 2019-03-11T22:58:06.503 回答