扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
为达到藕合松散的目的,应用把session bean实例的创建、缓存、销毁全部交给EJB 3.0容器(也就是,反向控制设计模式)。应用只和bean的商业接口打交道。
但如果应用需要对session对象更好的控制呢?比如说,应用可能需要在创建session bean的时候初始化数据库联接,而在销毁bean时关闭外部的联接。上述这些,你都可能通过在bean类中定义生命周期的回调方法来实现。这些方法将会被容器在生命周期的不同阶段调用(如:创建或销毁时)。通过使有下面所列的注释,EJB 3.0允许你将任何方法指定为回调方法。这不同于EJB 2.1,EJB 2.1中,所有的回调方法必须实现,即使这是空的。EJB 3.0中,bean可以有任意数量,任意名字的回调方法。
@PostConstruct:当bean对象完成实例化后,使用了这个注释的方法会被立即调用。这个注释同时适用于有状态和无状态的session bean。
@PreDestroy:使用这个注释的方法会在容器从它的对象池中销毁一个无用的或者过期的bean实例这前调用。同时适用于有状态和无状态的session bean.
@PrePassivate:当一个有状态的session bean实例空闲过长的时间,容器将会钝化它,并把它的状态保存下来。使用这个注释的方法会在容器钝化bean实例之前调用。适用于有状态session bean。
@PostActivate:当客户端再次使用已经被钝化的的有状态session bean时,新的实例被创建,状态被恢复。使用此注释的session bean会在bean的激活完成时调用。
@Init:这个注释指定了有状态session bean初始化的方法。它区别于@PostConstruct注释在于:多个@Init注释方法可以同时存在于有状态session bean 中,但每个bean实例只会有一个@Init注释的方法会被调用。这取决于bean是如何创建的(细节请看EJB 3.0规范)。@PostConstruct在@Init之后被调用。
另一个有用的生命周期方法注释是@Remove,特别是对于有状态session bean。当应用通过存根对象调用使用了@Remove注释的方法时,容器就知道在该方法执行完毕后,要把bean实例从对象池中移走。
@Stateful
public class CalculatorBean implements Calculator, Serializable {
// ... ...
@PostConstruct
public void initialize () {
// Initializes the history records and load
// necessary data from database etc.
// 初始化历史记录,并从数据库中装入必需的数据。
}
@PreDestroy
public void exit () {
// Save history records into database if necessary.
// 如有必要则将历史记录保存至数据库中
}
@Remove
public void stopSession () {
// Call to this method signals the container
// to remove this bean instance and terminates
// the session. The method body can be empty.
// 调用这个方法来通知容器将bean实例移除并中止session.
// 这个方法可以为空。
}
// ... ...
}
消息驱动bean
Session bean服务提供了同步调用的方法。另一个重要的藕合松散服务类型是一种通过进入的消息来触发的异步服务(比如:email或Java消息服务产生的消息)。EJB 3.0的消息驱动bean(MDB)是设计用来专门处理基于消息请求的组件。
一个MDB类必须实现MessageListener接口。当容器检测到bean守候的队列一条消息时,就调用onMessage()方法,将消息作为参数传入。MDB在OnMessage()中决定如何处理该消息。你可以用注释来配置MDB侦听哪一条队列。当MDB部署时,容器将会用到其中的注释信息。在下面的例子中,CalculatorBean MDB会在JMS队列queue/mdb有消息进入时调用。MDB解析消息,并根据消息内容计算投资。
@MessageDriven(activateConfig =
{
@ActivationConfigProperty(propertyName="destinationType",
propertyValue="javax.jms.Queue"),
@ActivationConfigProperty(propertyName="destination",
propertyValue="queue/mdb")
})
public class CalculatorBean implements MessageListener {
public void onMessage (Message msg) {
try {
TextMessage tmsg = (TextMessage) msg;
Timestamp sent =
new Timestamp(tmsg.getLongProperty("sent"));
StringTokenizer st =
new StringTokenizer(tmsg.getText(), ",");
int start = Integer.parseInt(st.nextToken());
int end = Integer.parseInt(st.nextToken());
double growthrate = Double.parseDouble(st.nextToken());
double saving = Double.parseDouble(st.nextToken());
double result =
calculate (start, end, growthrate, saving);
RecordManager.addRecord (sent, result);
} catch (Exception e) {
e.printStackTrace ();
}
}
// ... ...
}
依赖注入
在上一节中,你学到了如何开发藕合松散的服务组件。但是,为了存取那些服务对象,你需要通过服务器的JNDI来查找存根对象(session bean)或消息队列(MDB)。JNDI查找是把客户端与实际的服务端实现解藕的关键步骤。但是,直接使用一个字符串来进行JNDI查找并不优雅。有这样几个原因:
客户端与服务端必须有一致的基于字符串的名字。它没有在编译时得到认证或在布署时得到检查。
从JNDI返回的服务对象的类型没有在编译时进行检查,有可能在运行时出现转换(casting)错误。
冗长的查找代码,有着自己的try-catch代码块,在应用之间是重复的和杂乱的
如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者