1.前言
前几篇主要介绍了有状态和无状态、远程和本地调用的SessionBean,这篇介绍一下有关SessionBean的生命周期。SessionBean处于EJB容器管理之下,对于客户端来说是完全透明的。但对于开发者来说,必须要了解SessionBean在EJB容器中的运行规律。
2.为何会有SessionBean的生命周期
EJB容器创建和管理SessionBean实例,有些时候,可能也需要定制SessionBean的管理过程。例如,我想在创建SessionBean实例的时候初始化字段变量,或者在bean实例被销毁的时候关掉外部资源。这些都可以通过在bean类中定义生命周期方法,采用回调来实现。
3.无状态SessionBean的生命周期
分析:通过上图可以看出,如果需要改变无状态的SessionBean的生命周期,可以通过使用注解的形式,例如@PostConstruct、@PreDestroy来实现
4.有状态的SessionBean
有状态的SessionBean声明周期就有点复杂,因为客户端需要维护状态。
分析:从图上可以看出,有状态的SessionBean比无状态的SessionBean多了一个生命周期,去活状态,因而这就多出了两个注解:@PrePassivate和@PostActivate
5.生命周期分析
@PostConstruct:当 bean 对象完成实例化后,使用了这个注释的方法会被立即调用。这个注释同时适用于
有状态和无状态的会话 bean。
·@PreDestroy:使用这个注释的方法会在容器从它的对象池中销毁一个无用的或者过期的 bean 实例之前调
用。这个注释同时适用于有状态和无状态的会话 bean。
·@PrePassivate:当一个有状态的 session bean 实例空闲过长的时间,容器将会钝化(passivate)它,并把它的状态保存在缓存当中。使用这个注释的方法会在容器钝化 bean 实例之前调用。这个注释适用于有状态的会话 bean。当钝化后,又经过一段时间该 bean 仍然没有被操作,容器将会把它从存储介质中删除。以后,任何针对该 bean方法的调用容器都会抛出例外。
·@PostActivate:当客户端再次使用已经被钝化的有状态 session bean 时,新的实例被创建,状态被恢复。使用此注释的 session bean 会在 bean 的激活完成时调用。这个注释只适用于有状态的会话 bean。
·@Init:这个注释指定了有状态 session bean 初始化的方法。它区别于@PostConstruct 注释在于:多个@Init注释方法可以同时存在于有状态 session bean 中,但每个 bean 实例只会有一个@Init 注释的方法会被调用。这取决于 bean 是如何创建的(细节请看 EJB 3.0 规范)
@PostConstruct :在@Init 之后被调用。
@Remove,特别是对于有状态 session bean。当应用通过存根对象调用使用了@Remove 注释的方法时,容器就知道在该方法执行完毕后,要把 bean 实例从对象池中移走。
6.Demo分析
由于远程调用的SessionBean的生命周期比较复杂,下面也就以远程调用生命周期为例,来展示一下。
生命周期方法
<span style="font-family:SimSun;font-size:18px;">package ejbsessionbean; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.ejb.*; @Stateful @Remote(LifeCycle.class) public class LifeCycleBean implements LifeCycle { public LifeCycleBean(){ System.out.println("构造函数初始化"); } public String Say() { try { Thread.sleep(1000*10); } catch (InterruptedException e) { e.printStackTrace(); } return "这是会话Bean生命周期应用例子"; } @Init public void initialize () { System.out.println("@Init事件触发"); } @PostConstruct public void Construct () { System.out.println("@PostConstruct事件触发"); } @PreDestroy public void exit () { System.out.println("@PreDestroy事件触发"); } @PrePassivate public void serialize () { System.out.println("@PrePassivate事件触发"); } @PostActivate public void activate () { System.out.println("@PostActivate事件触发"); } @Remove public void stopSession () { System.out.println("@Remove事件触发"); //调用该方法以通知容器,移除该bean实例、终止会话。方法体可以是空的。 } } </span>测试方法
<span style="font-family:SimSun;font-size:18px;">package com.test; import javax.naming.InitialContext; import javax.naming.NamingException; import ejbsessionbean.LifeCycle; public class testDemo { public static void main(String[] args) throws NamingException { InitialContext ctx=new InitialContext(); LifeCycle lifecycle = (LifeCycle) ctx.lookup("LifeCycleBean/remote"); System.out.println(lifecycle.Say()); lifecycle.stopSession(); System.out.println("请注意观察Jboss控制台输出.等待10分钟,容器将会钝化此会话Bean,@PrePassivate注释的方法将会执行"); System.out.println("你可以调用stopSession方法把会话Bean实例删除。在删除会话Bean时,将触发@PreDestroy事件"); } } </span>
经过测试,会在创建EJB对象实例的时候,自动的回调各个生命周期方法。
7.小结
SessionBean的生命周期方法的方法名可以是任意的
SessionBean的生命周期方法不能定义任何形参
SessionBean的生命周期方法的返回值必须是void
SessionBean的生命周期方法不能声明抛出checked异常
SessionBean中相同类型的生命周期方法最多只能定义一个,比如@PostConstruct修饰的方法最多只能有一个。