何时是注入的构造函数,何时是CDI中调用的no-args构造函数

时间:2017-04-22 12:19:39

标签: java-ee cdi

我想知道构造函数注入是如何与bean类需要no-args构造函数的要求完全一致的。在下面描述的测试之后,我的结论是no-args构造函数被调用两次,然后调用注入的构造函数。谁能解释我为什么?

为了测试这种行为,我创建了一个HelloProducer类:

public class HelloProducer {

    @Produces
    @Hello
    public String helloWildFly() {
        return "Hello!";
    }

}

Hello限定符:

@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface Hello {
}

然后我创建了一个bean类,它使用这个Producer作为注入构造函数:

@Stateless
public class HelloBean {

    private final Logger log = LoggerFactory.getLogger("HelloBean");
    private String hello;

    public HelloBean() {
        log.warn("No-args constructor called");
        this.hello = "Hi!";
    }

    @Inject
    public HelloBean(@Hello String hello) {
        log.warn("Injected constructor called");
        this.hello = hello;
    }

    public String getHello() {
        return hello;
    }  

}

那么当我调用getHello()方法时会发生什么?你好!还是嗨!?我们来测试一下:

@RunWith(Arquillian.class)
public class HelloBeanIT {

    @Deployment
    public static JavaArchive createDeployment() {
        return ShrinkWrap.create(JavaArchive.class, "test.jar")
                .addClass(HelloProducer.class)
                .addClass(Hello.class)
                .addClass(HelloBean.class)
                .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml");
    }

    @Inject
    HelloBean helloBean;

    @Test
    public void testSomeMethod() {
        assertThat(helloBean.getHello(), is("Hello!"));
    }

}

好吧,该测试运行正常,因此调用的最终构造函数是注入的构造函数。但如果我查看日志,我会看到以下内容:

WARN [HelloBean] No-args constructor called
WARN [HelloBean] No-args constructor called 
WARN [HelloBean] Injected constructor called

那么,为什么在注入构造函数之前,CDI会将no-args构造函数调用两次?

1 个答案:

答案 0 :(得分:2)

所以,通过一些挖掘,我发现了那里发生了什么。

no-args构造函数调用在代理初始化期间发生,而带参数的唯一调用是实际的对象创建(以及最终使用的内容)。

进一步详细说明,你的bean是@Stateless - 这意味着它既是EJB又是CDI bean(根据定义,EJB和CDI也会自动为你选择它)。这两个规范的运行方式是它们在实际实例之上创建代理对象,然后您只需传递代理引用而不是实际实例。

因此它是这样的:

WARN [HelloBean] No-args constructor called -> CDI Proxy on top of EJB proxy
WARN [HelloBean] No-args constructor called -> EJB proxy
WARN [HelloBean] Injected constructor called -> actual instance creation