1、说明:
有状态的会话bean与无状态的会话bean是有区别的
a.无状态会话bean中ejb组件会使他忘记过去,他不会维护方法调用其间的会话信息。
b.而有状态的就不一样,ejb容器会维护其方法调用的会话信息。他和无状态的生命周期都是有ejb容器控制的(当然容器有自己的一套算法,知道哪些bean该销毁哪些不该销毁),当需要一个有状态的会话bean的时候EJB容器会构造出该bean,当一断时间没有用到这个bean的时候ejb容器会执行“挂起”策略将该bean由内存写入到硬盘中,当需要的时候就会激活它
2、下面就开始有状态的会话bean学习吧
首先我们在上次的项目基础上建一个statefull包
a.Statefull接口的源代码加说明
package statefull;
/**
* 有状态会话bean
* @author zhenlai
*
*/
public interface Statefull {
/**
* 计数器递增1
* @return
*/
public int count();
/**
* 对计数器进行值位
* @param value
*/
public void set(int value);
/**
* 删除计数器
*/
public void remove();
}
b.StatefullBean接口的源代码加说明
package statefull;
import javax.ejb.Remote;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.interceptor.Interceptors;
/**
* 有状态会话bean
* bean实例会维护一个整数,存在业务方法来实现递增
* @author zhenlai
*
*/
@Stateful
@Remote(Statefull.class)
@Interceptors(StatefullCallBack.class)
public class StatefullBean implements Statefull {
/*
* 无参构造器
*/
public StatefullBean() {
System.out.println("StatefullBean实例化了");
}
/*
* 维护会话bean的计数器
*/
private int value;
/**
* count业务方法
*/
public int count() {
System.out.println("count业务方法被调用了");
return ++value;
}
/**
* set业务方法
*/
public void set(int value) {
this.value = value;
System.out.println("set业务方法被调用了");
}
/**
* 使用remove注解,执行这个方法后ejb容器会销毁当前的bean
*/
@Remove
public void remove() {
System.out.println("remove方法被调用了");
}
}
c.StatefullCallBack接口的源代码加说明
package statefull;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.PostActivate;
import javax.ejb.PrePassivate;
import javax.interceptor.InvocationContext;
/**
* 生命周期回调拦截器,共
* @author zhenlai
*
*/
public class StatefullCallBack {
/**
* 无参构造器
*/
public StatefullCallBack() {
}
/**
* 构建bean后EJB容器会调用它
* @param ctx
* @throws Exception
*/
@PostConstruct
public void construct(InvocationContext ctx) throws Exception{
System.out.println("StatefullCallBack的construct方法被调用啦");
ctx.proceed();
}
/**
* 激活bean后EJB容器会调用它
* @param ctx
* @throws Exception
*/
@PostActivate
public void activate(InvocationContext ctx) throws Exception{
System.out.println("StatefullCallBack的activate方法被调用啦");
ctx.proceed();
}
/**
* 挂起bean前EJB容器会调用它
* @param ctx
* @throws Exception
*/
@PrePassivate
public void passivate(InvocationContext ctx) throws Exception{
System.out.println("StatefullCallBack的passivate方法被调用啦");
ctx.proceed();
}
/**
* 销毁bean前EJB容器会调用它
* @param ctx
* @throws Exception
*/
@PreDestroy
public void destory(InvocationContext ctx) throws Exception{
System.out.println("StatefullCallBack的destory方法被调用啦");
ctx.proceed();
}
}
d.客户端代码和说明
package statefull;
import java.util.Properties;
import javax.naming.InitialContext;
import javax.naming.NamingException;
/**
* 客户端
* @author zhenlai
*
*/
public class Client {
/* 客户端数目*/
public static final int CLIENTS = 3;
public static void main(String[] args) throws NamingException, InterruptedException {
/*参数信息*/
Properties props = new Properties();
props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
props.setProperty("java.naming.provider.url", "localhost:1099");
props.setProperty("java.naming.factory.url.pkgs", "org.jboss.naming");
/*获得上下文*/
InitialContext ctx = new InitialContext(props);
/*持有有状态bean数组*/
Statefull statefull[] = new Statefull[3];
int value = 0;
/*创建数组的成员,调用各自的count方法*/
System.out.println("开始实例化 bean");
for (int i = 0; i < CLIENTS; i++) {
statefull[i] = (Statefull) ctx.lookup("StatefullBean/remote");
/*初始化计数器*/
statefull[i].set(value);
/*加1并打印*/
value = statefull[i].count();
System.out.println("value="+value);
/*sleep100ms*/
Thread.sleep(100);
}
/*
* 为了证明挂起和激活是否被EJB容器正确处理
* 调用了Bean的实例count方法
*/
System.out.println("调用bean的count方法");
for (int i = 0; i < CLIENTS; i++) {
/* 加1并打印*/
value = statefull[i].count();
System.out.println("value="+value);
/* 调用remove方法,让EJB容器销毁当前bean*/
statefull[i].remove();
}
/* sleep50ms*/
Thread.sleep(50);
}
}
(说明:为了理解有状态的会话bean的运行过程,在这里加入了StatefullCallBack回调函数)
然后发布该项目,启动jboss,运行客户端看看结果
3.结果
客户端如下:
开始实例化 bean
value=1
value=2
value=3
调用bean的count方法
value=2
value=3
value=4
服务器输出结果如下:
StatefullBean实例化了
StatefullCallBack的construct方法被调用啦
set业务方法被调用了
count业务方法被调用了
StatefullBean实例化了
StatefullCallBack的construct方法被调用啦
set业务方法被调用了
count业务方法被调用了
StatefullBean实例化了
StatefullCallBack的construct方法被调用啦
set业务方法被调用了
count业务方法被调用了
count业务方法被调用了
remove方法被调用了
StatefullCallBack的destory方法被调用啦
count业务方法被调用了
remove方法被调用了
StatefullCallBack的destory方法被调用啦
count业务方法被调用了
remove方法被调用了
StatefullCallBack的destory方法被调用啦
(根据上面结果可以看出来ejb容器确实有激活和挂起操作,这里挂起不是很明显因为ejb觉得该bean还不需要挂起,当然没有挂起也就没有激活,这里大家可以把该bean改成无状态的对比一下运行结果,这样印象会更深刻,ok有状态bean告一段落。下一节将会介绍无状态和有状态bean的生命周期,敬请关注!)