我想知道构造函数注入是如何与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构造函数调用两次?
答案 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