A Sunny Commune - Cheng's Blog

Main | Next day (Mar 14, 2006) »

http://blogs.sun.com/chengfang/date/20060314 Tuesday March 14, 2006

资源注射,一生一次: EJB 3 编程笔记(3)

请做这道选择题:

资源注射发生在组件(EJB, Servlet, 等等)生命周期的哪一个阶段?

A. 实例创建完以后。
B. 实例投入服务以前。对于EJB,在第一个业务方法被调用以前;对于Servlet,在处理第一个HTTP请求以前。
C. 每次实例投入服务以前。对于EJB,在每个业务方法被调用以前;对于Servlet,在处理每个HTTP请求以前。
D. A和B
E. 不同的服务器有不同的做法。

正确答案是D。A和B部分正确,不够完整。任何资源都只在实例创建结束后注射一次,绝不会在其他时候被注射。你可以把资源注射看成容器创建实例这一行为的延伸。好比小孩刚刚生下来就要注射卡介苗,以后就再也不用打了。卡介苗有副作用[1],资源注射也一样。如果使用不小心,会造成麻烦无穷。下面这个Stateless bean注射了一个Stateful bean:

@Stateless
public class HelloBean implements HelloIF {
@EJB(name="ejb/shoppingCartBean")
private ShoppingCartIF shoppingCartBean;
public void startShopping(String userName) {
shoppingCartBean.begin(userName);
//more operations
shoppingCartBean.end(userName);
}
}
@Stateful
public class ShoppingCartBean implements ShoppingCartIF {
public void begin(String userName) {...}
@Remove
public void end(String userName) {
//remove this bean when we finished shopping...
}
}

大家都知道,Stateless bean平时生活在实例池中,如果有客户调用,容器就从池中提取一个是实例来履行业务,完成后再返回池中,等候下一次调用。在上例中,HelloBean 实例甲在第一次调用完成业务后,它的实例变量shoppingCartBean就已经被清除掉了。尽管shoppingCartBean stub还不是null,但它所对应的ShoppingCartBean实例已不存在。HelloBean实例甲在第二次被调用时就会得到 javax.ejb.NoSuchEJBException,因为我们通过Local Interface来调用ShoppingCartBean。如果是通过remote interface,会得到java.rmi.NoSuchObjectException.




[1] 我听说,打了卡介苗,以后每次做肺结核(TB)测试结果都是阳性,就算你其实根本没有肺结核也是这样。当然我不是医生,我只可能是病人,意见不权威。