摘要:JBoss Seam是“Java EE 5.0的一个轻量级的框架”。这是什么意思?难道Java EE(Enterprise Edition) 5.0本身不是一套“框架吗”?为什么在官方规范之外,还需要另外一个框架?好吧,我们就将seam看作是本应该被包括在Java EE 5.0中的一个“遗漏的框架”吧。它在Java EE 5.0框架的上层,为所有的在企业Web应用中的组件提供了一个统一的、易于理解的编程模型。它同样使基于状态的应用和业务流程驱动的应用的开发易如反掌。换句话说,Seam致力于开发者生产力和应用扩展性。
JBoss Seam是“Java EE 5.0的一个轻量级的框架”。这是什么意思?难道Java EE(Enterprise Edition) 5.0本身不是一套“框架吗”?为什么在官方规范之外,还需要另外一个框架?好吧,我们就将seam看作是本应该被包括在Java EE 5.0中的一个“遗漏的框架”吧。它在Java EE 5.0框架的上层,为所有的在企业Web应用中的组件提供了一个统一的、易于理解的编程模型。它同样使基于状态的应用和业务流程驱动的应用的开发易如反掌。换句话说,Seam致力于开发者生产力和应用扩展性。
开源Java EE框架 JBoss Seam 详细介绍
Seam打破了EJB3和JSF之间的人工层,它为整合EJB3和JSF提供了一个一致的,基于注解的途径。只需要个别简单的注解,Seam中的 EJB3业务组件就能直接被用来支持JSF Web表单或者处理Web UI事件。Seam允许开发者将“同一种东西”——有注解的POJOs——应用与所有的应用组件。与其他Web框架开发的应用相比,Seam应用概念简洁,同样的功能却需要较少的代码(在JAVA和XML中)。如果没有耐心,或者想要快速预览,一个Seam到底有多简单,你可以现看看本文描述的 hello world一例。
在JSP来说困难的任务,Seam可以轻易的完成。例如,JSF头疼的一个问题就是过分依赖HTTP POST。这使得将一个添加到书签中的JSF网页,通过HTTP GET访问相当困难。但是有了Seam,生成一个REST网页是非常容易的。Seam提供了一系列JSF组件标签和注解,增加了“web友好”和JSF应用的网页效率。
同时,Seam拓展了EJB3到POJO的组件模式, 从web层到业务层都有了状态上下文。进一步说,Seam整合了一系列主要的其他开放源代码框架,例如jBPM、JBoss Rules(又名Drools)、JBoss Portal、JBoss Microcontainer等等。Seam不仅能将它们“有机结合”起来,而且可以像整合JSF和EJB3一样强化原有的框架。
Seam位于Java EE 5.0底层,但它的应用并不局限与Java EE 5.0服务器。一个Seam应用可以部署在J2EE 1.4应用服务器和Tomcat服务器上。这意味着现在能在Seam应用中得到产品化支持。
1 + 1 > 2
或许有这样一种误解,认为Seam仅仅是将各种不同框架串起来的另外一个集成框架。Seam提供了它自身管理的状态上下文,允许框架通过注解和EL(表达式语言)表达式与其他框架进行深度整合。整合的程序来自于Seam开发者对第三方框架的认知。
Gavin King发明了Seam,同时他也发明了在世界上广为使用的ORM解决方案Hibernate。为了继承和发扬ORM的最佳实践,Seam进行了重新设计。有了Seam,就不必再写DTO,你所做的就是延迟加载。因为扩展后的持久上下文就如同一个自然的高速缓存,可以减少和数据库的交互,ORM的性能就会被极大地改进。
进一步讲,因为Seam整合了ORM层、业务层和表示层,开发者就能够在表示层直接展示ORM对象,也能把数据库验证注解用于输入表单,以及重新定向ORM例外到定制的错误页面。
3.专为有状态Web应用而设计
Seam是专为有状态Web应用而设计的。Web应用是天生的多用户应用,电子商务应用天生也是有状态的和有事务的。但是,大多数已有Web应用框架是面向无状态应用的。开发者必须操作HTTP会话(session)对象来管理用户状态,与核心业务逻辑无关的代码不仅会混乱你的应用,而且带来了一系列的性能问题。
在Seam中,所有的基础应用组件天生地有状态。它们使用起来要比HTTP session容易,因为它们的状态由Seam公开管理。没有必要在Seam应用中编写引起麻烦的状态管理代码——只需在其组件上注解其做用域、生命周期方法以及其他状态属性,Seam就会掌管其他[译者注:指这些组件的生命周期]。Seam状态组件要比HTTP会话(session)能更好的管理用户状态。例如,你能有多个“会话”进行,每个“会话”由在一个HTTP会话(session)中一系列的Web请求和业务方法调用组成。
进一步说,在Seam中,数据库缓存和事务能自动与应用的状态相连。Seam在内存中自动保存数据库更新,等到对话结束后提交到数据库。内存中的缓存能大大减轻复杂状态应用中数据库的负载。
除了以上这些,Seam支持整合开源JBoss jBPM业务程序引擎,大大提升了Web应用中的状态管理。你现在能为一个机构中不同工作人员(诸如客户、经理、技术支持人员等等)的指定工作流程,利用工作流程来驱动应用,而不是依赖用户界面事件处理和数据库。
对于AJAX应用,不断增长的数据库负载是一个巨大的挑战。与一个非AJAX应用相比,一个AJAX应用要向服务器发送的更频繁的请求。一但数据库必须响应这些AJAX请求,那么数据库就不堪重荷。Seam中的状态持久上下文正如一个内存中的缓存,它能在会话始末保存信息,最终帮助减少数据库交互。
Web2.0应用往往为其数据使用复杂关系模型(例如,一个网络交际站点所做的就是处理和显示“用户”之间的关系),对于这些站点,延迟加载对于 ORM层至关重要。否则,一个简单的查询就能级联地加载整个数据库。正如我们前面所讨论过的,Seam是现今唯一一个正确支持Web应用延时加载的Web 框架。
5.依赖双向映射的Pojo服务
Seam是一个“轻量级”框架,因为它使用POJO(plain old Java objects)作为服务组件。在应用中,POJO没有使用接口或抽象类来”钩住”组件。当然,问题是如何使POJO交互来组成这个应用?它们如何与容器服务(例如,数据库持久化服务)交互?
Seam通过使用一个流行的、被称作依赖注入(DI)的设计模式联结所有POJO组件。在这个模式下,Seam框架管理着所有组件的生命周期。当一个组件需要使用另外一个时,它通过注解(annotation)向Seam声明此依赖。Seam依据应用当前状态得到这个依赖组件,并将它注入到所需求的组件中。
通过拓展依赖注入概念,一个Seam组件A不但可以构造另外一个组件B,而且把此组件B“抛还”给Seam以备其他组件(例如组件C)以后使用。
这类双向依赖管理甚至都广泛的应用于简单的Seam web应用中(例如第二章的hello world一例)。在Seam术语中,我们称这个为“依赖双向映射”。
6.非常规的配置
[译者注:指以隐式映射为主题,以显式映射为例外的配置方式]
使Seam易用的主要设计原则是“非常规的配置”。其思想是为这些组件提供一系列默认行为,开发者只需要在预期行为非默认的时候,显示地配置组件。例如, 当Seam将组件A作为属性注入到组件B时,默认地,组件A刚会以组件B被注入的属性的名称命名。Seam里还有很类似的细节。总的结果是Seam中配置元数据要比其他Java框架简单的多。因此,大多数的Seam应用能通过一系列简单的Java注解进行充分配置。开发者从减化的复杂度中受益匪浅,最后,与其他Java框架相比,用更少的代码实现同样的功能。
7.避免滥用XML
或许你已经注意到,Java注解在表述和处理Seam配置元数据时扮演着重要的角色。通过这样的设计使框架更易于操作。
在J2EE发展早期,XML曾经被看作配置管理的“圣杯”。框架设计者将所有的配置信息,包括Java类和方法名称都统统丢进XML文档,而不考虑对开发者所带来的后果。反省后,发现这是个严重的错误。XML配置文档太过重复。开发者必须重复代码中已有的信息,从而将配置和代码联结起来。这些重复使应用易于出错(例如,一个拼写错误的类名可能在运行时显示为一个难于调试错误)。缺少合理的默认配置进一步使这一问题复杂化。事实上,在一些框架中,相当数量的样板代码伪装为XML,可能相当于或者超过实际应用中JAVA代码的数量。对于J2EE开发者,XML的滥用通常被称为“XML地狱”。
Java社区认识到了XML的滥用问题,并且已经非常成功地用Java代码中的注解取代了XML。EJB3是Java官方标准化机构促进Java企业组件中注解使用的一项成果。EJB3完全可选择的使用XML文档,它向正确方向迈出了积极的一步。Seam加入了EJB3的注解,为整个web应用拓展了基于注解的编程模型。
当然,XML对于配置数据并非完全不利。Seam设计者认识到XML适用于指定页面流程或者定义业务流程的web应用。XML文档使开发者集中地管理整个web应用的工作流程成为可能,同时也反对将配置信息分散于java源文件中。工作流程很少能与源代码耦合,因此XML文档中并不需要重复键入已存在于代码中的信息。
8.为测试而设计
Seam为了易于测试而重新设计。因为所有的Seam组件都是注解过的POJO,它们易于进行单元测试。开发者仅仅通过利用常规的Java new关键词来构造实例,然后在测试框架(例如JUnit 或者TestNG)中运行任何方法。如果需要测试多个Seam组件的交互,开发者则逐个实例化这些组件,然后手动建立它们的相互关系(也就是显示地使用 setter 方法,而不是依靠Seam依赖注入功能)。
集成测试整个Seam应用比较复杂,因为开发者必须在Seam容器中运行应用。Seam用嵌入的轻量级容器来帮助该类测试。在测试框架中,开发者能按步骤地加载Seam容器,然后运行测试。
但更重要的是,SeamGen生成项目不依赖于主流的Java集成开发环境,如Eclipse和NetBeans。有了SeamGen,开发者可以随时入门。
Seam Hello World
JBoss Seam是EJB3和JSF中间的粘合剂,这是Jboss Seam最基本的和最广泛的应用。通过被Seam管理的组件,Seam允许这两个框架之间无缝(不是有意双关的)的集成。它为整个web应用拓展了基于注解的EJB3 POJO编程模型。在层与层之间,没有了必需的手动JNDI查找,没有了冗长的JSF支持bean的声明,没有了过多facade方法,没有了艰辛的对象传递,快哉!
继续在Seam中使用JavaEE模式
在传统的java EE应用中,一些设计模式,例如JNDI查找、XML声明组件、值对象、facade是被强制使用的。Seam用基于注解的POJO消除了这些人为的需求。但是,当Seam应用中真正需要它们的时候,仍然可以自由地使用这些模式。
编写一个Seam web应用概念上很简单。你只需要编码出下列组件:
实体对象代表数据模型。实体对象可能是JPA或者Hibernate中的POJO对象。它们自动地映射到关系数据库表。
SF web页面展示了用户界面。页面通过表单捕获用户的输入,并且显示结果。表单域与其数据显示数据库表,这些表被映射到实体bean或者实体bean的集合上。
EJB3 会话bean或者注解过的Seam POJO可以作为JSF Web页面的UI事件处理器。它们处理封装在实体bean中的用户输入,为下一步(或者页面)生成显示的数据对象。
所有以上组件均由Seam自行管理,它们在运行时被自动注入到正确的页面或者对象。例如,当用户单击按钮提交一个JSF表单,Seam就会自动解析表单域并构造一个实体bean。然后,Seam将实体bean传入同样被Seam构造的事件处理器会话bean中来处理。开发者不需要在代码中管理组件的生命周期和组件之间的相互关系。依赖处理过程中,没有样板代码和XML文件。
本章中,我们使用hello world一例来明确展示Seam如何粘合一个web应用。该例子工作如下:用户能在web表单中输入其名字来“问候”Seam。一旦她提交了表单,应用则保存她的名字到一个关系数据库中,并且显示所有已经“问候”过Seam的用户。该项目示例在该书下载的源代码中的HelloWorld文件夹中。为了建立它,你必须安装Apache ANT 1.6版本以上 (http://ant.apache.org/)。进入HelloWorld目录,运行命令ant,则会生成build/jars /helloworld.ear文件,可以直接拷贝该文件到Jboss AS实例的server/default/deploy目录下。现在,启动JBoss AS并且打开网址http://localhost:8080/helloworld/。
为了运行本书中的例子,我们建议您使用JEMS GUI安装程序安装一个与Seam兼容的JBoss AS。您可以从http://labs.jboss.com/portal/jemsinstaller/downloads下载JEMS安装程序。如果您需要更多安装JBoss AS和应用部署帮助,请参见附录A,“安装和部署JBoss AS”
欢迎使用示例作为模板,快速开始你自己Seam项目(参见附录B “使用应用示例作为模板”)。或者,你能使用命令行工具Seam Gen (参见第四章“快速应用开发工具”)自动生成项目模板,包括所有的配置文件。本章中,我将花少量的时间来阐释源代码项目中的目录结构。相反,我们将集中讨论代码和配置,这也是开发者建立一个Seam 应用必需的。如此,我们就能将知识应用到任何一个项目结构,而不需要受模板的限制。
源代码目录
一个Seam应用由java类和XML或文本配置文件组成。本书的项目例子中,java源代码文件在src目录中,网页在view 目录中,所有的配置文件都在resources目录中。更多信息请看附件B,使用应用示例作为模板。
@Entity
@Name(“person”)
public class Person implements Serializable {
private long id;
private String name;
@Id @GeneratedValue
public long getId() { return id;}
public void setId(long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) {this.name = name;}
}
Person类中最重要的注解是@Name,它为这个将要注册于Seam中的Person bean指定了名称。在其他Seam组件中(例如,页面和会话bean)中,开发者能指直接使用“person”来引用被管理的Person bean。
Please enter your name: