在上一节中,我们已经知道了如何用@Inject实现基本注入,这一节研究Bean实例注入后的“生命周期”,web application中有几种基本的生命周期(不管哪种编程语言都类似)
1、Application 生命周期
即:web application启动后,处于该生命周期级别的对象/变量,将一直存在,可以被所有web应用的用户共同访问,通常用来做网站计数器,实现流量访问之类。直到web 应用停止或重新启动,该对象才被销毁。简单来说:只要web application处于激活状态,不论你换什么浏览器,不论你是否关闭页面,这个对象都会一直存在。
2、Session 生命周期
每次我们在某种类型的浏览器(比如:IE或Firefox)里,请求web application的某个页面时,就会生成Session,只要浏览器不关闭,Session就能持续有效(哪怕你把当前Tab标签页面给关掉,或者在当前url地址栏,输入一个其它不相关的网址,跳到其它网站,然后再回过来访问web app,只要Session不超时,Session仍有效)。说得更白一点:按F5刷新,该对象/变量不会被自动销毁,除非Session过期。
注:Session是跟浏览器有关的,如果在FireFox里打开web Application的某个url,再到IE里打开同样的url,这二个浏览器里的Session是不同的。
3、Request 生命周期
即只有本次http请求才有效,通俗点讲,如果你定义一个变量的生命周期是Request级别,刷新一次页面后,该变量就被初始化(重新投胎)了。
为了演示上面的几种情况,我们创建一个新的Dynamic Website,仍然用Maven来管理,项目结构如下:
model包下,创建了几个类,先来看基类BaseItem
1 package model; 2 3 import java.io.Serializable; 4 5 public class BaseItem implements Serializable { 6 7 private static final long serialVersionUID = -8431052435964580554L; 8 9 private long counter; 10 11 public void addCounter() { 12 counter++; 13 14 } 15 16 public long getCounter() { 17 return counter; 18 } 19 20 public long getHashCode() { 21 return hashCode(); 22 } 23 24 }
注:SessionScoped使用时,要求Bean实现序列化接口,否则运行会报错,建议要注入的Bean,全都实现Serializable接口。
其它几个类都继承自这个类,只是在类上应用了不同的注解
ApplicationBean
1 package model; 2 3 import javax.enterprise.context.*; 4 5 @ApplicationScoped 6 public class ApplicationBean extends BaseItem { 7 8 /** 9 * 10 */ 11 private static final long serialVersionUID = -2434044044797389734L; 12 13 14 15 }
SessionBean
1 package model; 2 3 import javax.enterprise.context.*; 4 5 @SessionScoped 6 public class SessionBean extends BaseItem { 7 8 /** 9 * 10 */ 11 private static final long serialVersionUID = -4285276657265507539L; 12 13 14 15 }
RequestBean
1 package model; 2 3 import javax.enterprise.context.*; 4 5 @RequestScoped 6 public class RequestBean extends BaseItem { 7 8 /** 9 * 10 */ 11 private static final long serialVersionUID = -2625124180601128375L; 12 13 14 15 }
SingletonBean
1 package model; 2 3 import javax.inject.Singleton; 4 5 @Singleton 6 public class SingletonBean extends BaseItem { 7 8 /** 9 * 10 */ 11 private static final long serialVersionUID = 283705326745708570L; 12 13 14 15 }
注:@Singleton算是一个“伪”Scope,顾名思义,它将以单例模式注入一个唯一的对象实例。从使用效果上看,这跟@ApplicationScoped类似.
同样,为了跟前端JSF交互,我们再来一个“Controller”
1 package controller; 2 3 import javax.inject.*; 4 import model.*; 5 6 @Named("Index") 7 public class IndexController { 8 9 @Inject 10 private ApplicationBean applicationBean; 11 12 @Inject 13 private SessionBean sessionBean; 14 15 @Inject 16 private RequestBean requestBean; 17 18 @Inject 19 private SingletonBean singletonBean; 20 21 public ApplicationBean getApplicationBean() { 22 applicationBean.addCounter(); 23 return applicationBean; 24 } 25 26 // public long getApplicationBeanCount(){ 27 // applicationBean.addCounter(); 28 // return applicationBean.getCounter(); 29 // } 30 31 public SessionBean getSessionBean() { 32 sessionBean.addCounter(); 33 return sessionBean; 34 } 35 36 public RequestBean getRequestBean() { 37 requestBean.addCounter(); 38 return requestBean; 39 } 40 41 public SingletonBean getSingletonBean() { 42 singletonBean.addCounter(); 43 return singletonBean; 44 } 45 46 }
我们注入了上述四种生命周期的Bean,并提供了getter方法,最后准备一个简单的xhtml页面,作为UI展现
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 2 <html xmlns="http://www.w3.org/1999/xhtml" 3 xmlns:h="http://java.sun.com/jsf/html" 4 xmlns:f="http://java.sun.com/jsf/core" 5 xmlns:ui="http://java.sun.com/jsf/facelets"> 6 7 <h:head> 8 <title>cdi scope sample</title> 9 </h:head> 10 <body> 11 Application Bean:#{Index.applicationBean.counter} , 12 hashCode:#{Index.applicationBean.hashCode} 13 <br /> Session Bean:#{Index.sessionBean.counter} , 14 hashCode:#{Index.sessionBean.hashCode} 15 <br /> Request Bean:#{Index.requestBean.counter} , 16 hashCode:#{Index.requestBean.hashCode} 17 <br /> Singleton Bean:#{Index.singletonBean.counter} , 18 hashCode:#{Index.singletonBean.hashCode} 19 <br /> 20 </body> 21 </html>
在Jboss里部署后,可以用http://localhost:8080/cdi-scope-sample/index.jsf 访问,下面是运行截图:
大家可以F5刷新下看看变化,然后多开几个Tab页,访问同样的网址,F5刷新,然后把浏览器关掉,再重新打开浏览器,访问同样的网址再比较一下
附:示例源码下载 cdi-scope-sample.zip