您的位置:首页 > 其它

seam 作用域的介绍

2013-02-21 18:30 357 查看
JSF等框架有机地结合起来的纽带。如下图所示。


作用域的介绍" />

  由上图可以看出Seam会涉及很多技术,不过大家不必惊慌,因为其中有些技术不是必须的。然而要学好Seam,掌握JSF是必不可少的。Seam基于JSF作了一些扩展,使JSF更易用。另外,在上图中JSF上层有JSP、Facelets和Portal这三个框框,这三种技术是JSF的视图(View)技术,三者可任选其一。现在JSF默认是使用JSP作为视图技术,不过我早前在TSS上看过一篇关于JSF
2.0的文章,这方面会有所改变——Facelets将会取而代之。因为Facelets对比JSP要优越许多:

  Facelets使用XHTML规范,省却了一大堆JSP的<f:verbatim
/>;

  更强的性能;

  Facelets实现模板(Template)功能,这个可以称得上是杀手锏功能。因为几乎每个应用都要使用这个功能;

  Facelets还可以方便地创建自定义标签和EL函数。

  所以Facelets成为Seam的不二之选。通过上面的讲述,我想大家应该了解Seam、JSF与Facelets的关系,故我介绍使用Facelets作为视图技术的JSF。

  基本的XHTML构成

  如果大家可以通过上一篇文章可以顺利创建Seam工程,可以在WebContent文件夹下看到一些XHTML文件。不过,这些XHTML都并不是独立的,需要依赖模板页面。

JSF的页面逻辑是由Managed Bean(姑且译为托管BEAN)实现。所谓的“Managed
Bean”就是指一些由JSF运行时(Runtime)创建与管理的普通Java对象(潮流一点的叫法——POJO)。

  标准JSF中Managed Bean

  标准的JSF中Managed Bean是在faces-config.xml中通过XML定义的。例如:

<managed-bean>

    <managed-bean-name>helloBean</managed-bean-name>

    <managed-bean-class>

        net.blogjava.max.seam.HelloBean

    </managed-bean-class>

    <managed-bean-scope>request</managed-bean-scope>

</managed-bean>


  这些XML相信不用我怎么讲解大家也知道其作用啦。定义一个BEAN,无论是在Spring、EJB还其它的BEAN容器(Container)中,无非都是这几个元素:BEAN的名称(或者标识,ID)、JAVA类型和作用域。JSF的Managed
Bean有四个作用域,如下表所示:

作用域描述
none作用域是none的Managed Bean通常是定义一些公用的BEAN,它们的创建与存储依赖于引用它的BEAN
request在单一的HTTP请求(Request)中被创建和保持有效
session在HTTP的会话(Session)中被创建和保持有效,可以跨请求
application存储WEB应用的Application上下文中,对于所有的请求和会话可见
  可能大家对“none”作用域比较陌生,举个例子可能会好理解一点:

<managed-bean>

   <managed-bean-name>helloBean</managed-bean-name>

   <managed-bean-class>

      com.pccw.jsftraining.managedbean.HelloBean

   </managed-bean-class>

   <managed-bean-scope>request</managed-bean-scope>

   <managed-property>

      <property-name>messageFromOtherBean</property-name>

      <property-class>java.lang.String</property-class>

      <value>#{messageBean}</value>

   </managed-property>

</managed-bean>

<managed-bean>

   <managed-bean-name>messageBean</managed-bean-name>

   <managed-bean-class>java.lang.String</managed-bean-class>

   <managed-bean-scope>none</managed-bean-scope>

   <value>Hello World from Another Bean!</value>

</managed-bean>


  这个例子定义了一个名为messageBean、作用域是none的Managed
Bean,然后它被注入名为messageBean、作用域是request的Managed
Bean中。因此,这个messageBean的作用域会跟随helloBean,同为request。另外值得一提的是,上例同样展示了如何在一个Managed
Bean初始其属性(Property)的值,如何引用其它的Managed Bean。

  Seam中的Web Bean(相当于Managed Bean)

  标准JSF的Managed Bean存在不少缺点:

  必须通过XML进行配置,过于麻烦;

  贫乏的作用域,上文提及标准的JSF的Managed
Bean只有四种作用域:none、request、session和application。由于JSF对状态的依赖比较强,经常需要在请求之间保存应用的状态,所以很多时候我们时候都不得不使用Session作用域的Managed
Bean。但是众所周知,过多地使用Session会带来很多问题,如容易造成内存耗尽,难于集群(Cluster)等。

  有监于此,Seam对JSF进行了扩展,并进而起草了Web Bean标准(Web
Bean还在BETA阶段,坦白的说我也不是很了解)。下面我们就来学习一下Seam的Managed
Bean(官方文档中叫Component)。在这方面Seam与标准JSF有如下不同:

  Seam的Component既可以通过XML配置,又可以通过Annotation的方式配置。我个人比较偏爱Annotation的方式,方便快捷,能够提高工作效率。XML方式有一个好处就是可以集中管理,但是因为Managed
Bean配置相对比较稳定,不会经常修改,所以XML优势并不会太明显;

  更丰富的作用域(Seam中称为上下文Context),Seam有6种上下文可选:无状态(Stateless
Context)、事件(Event Context,或者Request Context)、页面(Page
Context)、对话(Conversation Context)、会话(Session Context)、业务流(Business
Process Context)和应用程序(Application Context);


  Seam引入一种双向注入(Binjection)的方式。所谓的双向注入就是可以将上下文中的Bean注入到另一个Bean中,又或者将Bean中的属性(Property)直接发布在上下文中;

  Seam的Compoenet可以直接使用EJB 3.0的Bean。

  下面我们看一个简单的Component的定义的例子,

 1 package net.blogjava.max.hello.session;

 2 

 3 import org.jboss.seam.ScopeType;

 4 import org.jboss.seam.annotations.Name;

 5 import org.jboss.seam.annotations.Scope;

 6 

 7 @Name("helloWB")

 8 @Scope(ScopeType.PAGE)

 9 public class HelloWB {

10     private String name;

11     private String message;

12 

13     public String getName() {

14         return name;

15     }

16 

17     public void setName(String name) {

18         this.name = name;

19     }

20 

21     public String getMessage() {

22         return message;

23     }

24 

25     public void setMessage(String message) {

26         this.message = message;

27     }

28 

29     public void sayHello() {

30         message = "Hello, " + name + "!";

31     }

32     

33     public void anotherEvent() {

34         System.out.println("Another request is coming

作用域的介绍" />");

35     }

36 }


  通过上述代码,大家可以看到有两句Annotation定义——Name和Scope。除此之外,并没有什么特别的地方,所以正是这两个Annotation使HelloWB成为一个可以被SEAM的运行时识别的Component。Name用于定义Component的名称,是必须的;Scope则用于定义Component的作用域,是可选的,默认值为短对话(Short
Conversation)。在本例中,HelloWB的作用域是Page。Page与Conversation都Seam的杰作,在标准JSF是没有的。而且,这两个作用域是比较常用,我个人比较热衷于Page作用域,所以在这里先谈一下Page。

  正如我前面所说“JSF对状态的依赖比较强...”,造成我们对Session的依赖,引起了很多问题。Page很大程度上解决了这个问题,它可以跨请求存活,只要该请求不是“新的”。什么请求是“新的”请求呢?要回答这个问题,先要搞清楚什么是“POST-BACK”。学过ASP.NET的朋友可能对POST-BACK概念比较熟悉,没学过的话不要紧。POST-BACK并不是什么深奥的东西,所谓的POST-BACK,就是指用户按下页面上的某个按钮或表单控件,将表单数据发送回到页面自身的URL。相反,如果用户是通过在地址栏中输入URL,或通过点击页面的链接访问页面,则这个请求就是一个NON-POST-BACK的请求,也即是一个新的请求。

  另外,一些JSF专家都推荐一种叫Backing Bean的风格。所谓的Backing
Bean就是指一个JSF页面对应一个Managed
Bean处理页面逻辑。Page作用域非常适用这种情况,因为它是与页面一起序列化(Serialize)到浏览器或保存在Session中。如果大家还是不太明白的话,请看以下的XHTML代码。

 1 <?xml version="1.0" encoding="utf-8"?>

 2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

 3 

 4 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">

 5     <head>

 6         <meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>

 7         <title>

 8             Hello World

 9         </title>

10     </head>

11     <body>

12         <h:form>

13             <h:outputLabel value="Name: " for="itName" />

14             <h:inputText id="itName" value="#{helloWB.name}" />

15             <h:commandButton action="#{helloWB.sayHello}" value="Say Hello" />

16             <h:commandButton action="#{helloWB.anotherEvent}" value="Another Reqeust" />

17             <hr />

18             <h2>

19                 <h:outputText value="#{helloWB.message}" />

20             </h2>

21         </h:form>

22     </body>

23 </html>


  发布运行上述代码,大家可以看如下页面。


作用域的介绍" />

  图片看不清楚?请点击这里查看原图(大图)。

  在输入框中键入“max”,点击“Say
Hello”按钮,将请求POST-BACK到Seam的组件中,由于按钮注册了组件的监听方法,所以HelloWB的sayHello方法会被调用。它将通过值绑定所得的name与“Hello”和“!”串起来,赋给message属性。因此,响应页面会如下图所示:


作用域的介绍" />

  图片看不清楚?请点击这里查看原图(大图)。

  这时候,大家可以再点击“Another
Request”按钮,出现的结果与上图一样。这就说明虽然发生了第二次请求,name与message的同样保持上一次的值。然后,大家可以再试下复制页面地址,粘贴到新窗口或新选项卡(TAB)的地址栏中,按下ENTER。你会发现页面的被重置回到最初的状态。这个例子很好地演示了POST-BACK请求与NON-POST-BACK请求的区别。

  小结

  本文粗略地介绍了一下JSF的页面逻辑处理组件——Managed
Bean,还有很多关于Seam的组件知识如Bijection和Conversation等还没有介绍,只有留待以后文章了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: