`
javafenger
  • 浏览: 247812 次
  • 来自: ...
文章分类
社区版块
存档分类
最新评论

使用 AppFuse 的七个理由之二

阅读更多

理由 1:测试

测试是在软件开发项目中很少被给予足够信任的一个环节。注意我并不是说在软件开发的一些刊物中没有得到足够的信任!很多文章和案例研究都给出了测试优先的开发方式和足够的测试覆盖面以提高软件的质量。然而,测试通常都被看作是一件只会延长项目开发时间的事情。实际上,如果我们使用测试优先的方法在编写代码之前就开始撰写测试用例,我相信我们可以发现这实际上会加速 开发速度。另外,测试优先也可以使维护和重用更加 容易。如果我们不编写代码来测试自己的代码,那么就需要手工对应用程序进行测试 —— 这通常效率都不高。自动化才是关键。

当我们首次开始使用 AppFuse 时,我们可能需要阅读这个项目 Web 站点上提供的快速入门指南和教程(请参看 参考资料 中的链接)。这些教程的编写就是为了您可以首先编写测试用例;它们直到编写接口和/或实现之后才能编译。如果您有些方面与我一样,就会在开始编写代码之前就已经编写好测试用例了;这是真正可以加速编写代码的惟一方式。如果您首先编写了代码的实现,通过某种方式验证它可以工作,那么您可能会对自己说,“哦,看起来不错 —— 谁需要测试呢?我还有更多的代码需要编写!”这种情况不幸的一面是您通常都会做一些事情 来测试自己的代码;您简单地跳过了可以自动化进行测试的地方。

AppFuse 的文档展示了如何测试应用程序的所有 层次。它从数据库层开始入手,使用了 DbUnit(请参看 参考资料)在运行测试之前提前使用数据来填充自己的数据库。在数据访问(DAO)层,它使用了 Spring 的 AbstractTransactionalDataSourceSpringContextTests 类(是的,这的确是一个类的名字!)来允许简单地加载 Spring 上下文文件。另外,这个类对每个 testXXX() 方法封装了一个事务,并当测试方法存在时进行回滚。这种特性使得测试 DAO 逻辑变得非常简单,并且不会对数据库中的数据造成影响。

在服务层,jMock (请参看 参考资料)用来编写那些可以消除 DAO 依赖的真正 单元测试。这允许进行验证业务逻辑正确的快速测试;我们不用担心底层的持久性逻辑。

 

在 Web 层,测试会验证操作(Struts/WebWork)、控件(Spring MVC)、页面(Tapestry)和管理 bean(JSF)如我们所期望的一样进行工作。Spring 的 spring-mock.jar 可以非常有用地用来测试所有这些框架,因为它包含了一个 Servlet API 的仿真实现。如果没有这个有用的库,那么测试 AppFuse 的 Web 框架就会变得非常困难。

UI 通常是开发 Web 应用程序过程中最为困难的一部分。它也是顾客最经常抱怨的地方 —— 这既是由于它并不是非常完美,也是由于它的工作方式与我们期望的并不一样。另外,没有什么会比在客户面前作演示的过程中看到看到异常堆栈更糟糕的了!您的应用程序可能会非常可怕,但是客户可能会要求您做到十分完美。永远不要让这种事情发生。Canoo WebTest 可以对 UI 进行测试。它使用了 HtmlUnit 来遍历测试 UI,验证所有的元素都存在,并可以填充表单的域,甚至可以验证一个假想的启用 Ajax 的 UI 与我们预期的工作方式一样。(有关 WebTest 和 HTMLUnit 的链接请参看 参考资料。)

为了进一步简化 Web 的测试,Cargo(请参看 参考资料)对 Tomcat 的启动和停止(分别在运行 WebTest 测试之前和之后)进行了自动化。

理由 2:集成

正如我在本文简介中提到的一样,很多开放源码库都已经预先集成到 AppFuse 中了。它们可以分为以下几类:

  • 编译、报告和代码生成:Ant、Ant Contrib Tasks、Checkstyle、EMMA、Java2Html、PMD 和 Rename Packages
  • 测试框架:DbUnit、Dumbster、jMock、JUnit 和 Canoo WebTest
  • 数据库驱动程序:MySQL 和 PostgreSQL
  • 持久性框架:Hibernate 和 iBATIS
  • IoC 框架:Spring
  • Web 框架:JSF、Spring MVC、Struts、Tapestry 和 WebWork
  • Web 服务:XFire
  • Web 工具:Clickstream、Display Tag、DWR、JSTL、SiteMesh、Struts Menu 和 URL Rewrite Filter
  • Security:Acegi Security
  • JavaScript 和 CSS:Scriptaculous、Prototype 和 Mike Stenhouse 的 CSS Framework

除了这些库之外,AppFuse 还使用 Log4j 来记录日志,使用 Velocity 来构建 e-mail 和菜单模板。Tomcat 可以支持最新的开发,我们可以使用 1.4 或 5 版本的 Java 平台来编译或构建程序。我们应该可以将 AppFuse 部署到任何 J2EE 1.3 兼容的应用服务器上;这已经经过了测试,我们知道它在所有主要版本的 J2EE 服务器和所有主要的 servlet 容器上都可以很好地工作。

图 3 给出了上面创建的 devworks 项目的 lib 目录。这个目录中的 lib.properties 文件控制了每个依赖性的版本号,这意味着我们可以简单地通过把这些包的新版本放到这个目录中并执行诸如 ant test-all -Dspring.version=2.0 之类的命令来测试这些包的新版本。


图 3. 项目依赖性
AppFuse 项目依赖性

预先集成这些开放源码库可以在项目之初极大地提高生产效率。尽管我们可以找到很多文档介绍如何集成这些库,但是定制工作示例并简单地使用它来开发应用程序要更加简单。

除了可以简化 Web 应用程序的开发之外,AppFuse 让我们还可以将 Web 服务简单地集成到自己的项目中。尽管 XFire 也在 AppFuse 下载中一起提供了,不过如果我们希望,也可以自己集成 Apache Axis(请参看 参考资料 中有关 Axis 集成的教程)。另外,Spring 框架和 XFire 可以一起将服务层作为 Web 服务非常简单地呈现出来,这就为我们提供了开发面向服务架构的能力。

另外,AppFuse 并不会将我们限定到任何特定的 API 上。它只是简单地对可用的最佳开放源码解决方案重新进行打包和预先集成。AppFuse 中的代码可以处理这种集成,并实现了 AppFuse 的基本安全性和可用性特性。只要可能,就会减少代码,以便向 AppFuse 的依赖框架添加一个特性。例如,AppFuse 自带的 Remember Me 和 SSL 切换特性最近就因为类似的特性而从 Acegi Security 中删除了。

理由 3:自动化

Ant 使得简化了从编译到构建再到部署的自动化过程。Ant 是 AppFuse 中的一等公民,这主要是因为我发现在命令行中执行操作比从 IDE 中更加简单。我们可以使用 Ant 实现编译、测试、部署和执行任何代码生成的任务。

尽管这种能力对于有些人来说非常重要,但是它并不适用于所有的人。很多 AppFuse 用户目前都使用 Eclipse 或 Intellij IDEA 来构建和测试自己的项目。在这些 IDE 中运行 Ant 的确可以工作,但是这样做的效率通常都不如使用 IDE 内置的 JUnit 支持来运行测试效率高。

幸运的是,AppFuse 支持在 IDE 中运行测试,不过管理这种特性对于 AppFuse 开发人员来说就变得非常困难了。最大的痛苦在于 XDoclet 用来生成 Hibernate 映射文件和 Web 框架所使用的一些工件(例如 ActionForms 和 Struts 使用的 struts-config.xml)。IDE 并不知道需要生成的代码,除非我们配置使用 Ant 来编译它们,或者安装了一些可以认识 XDoclet 的插件。

这种对知识的缺乏是 AppFuse 2.0 切换到 JDK 5 和 Maven 2 上的主要原因。JDK 5、注释和 Struts 2 将让我们可以摆脱 XDoclet。Maven 2 将使用这些生成的文件和动态类路径来生成 IDE 项目文件,这样对项目的管理就可以进行简化。目前基于 Ant 的编译系统已经为不同的层次生成了一些工件(包括 dao.jar、service.jar 和 webapp.war),因此切换到 Maven 的模型上应该是一个非常自然的调整。

除了 Ant 之外(它对于编译、测试、部署和报告具有丰富的支持),对于 CruiseControl 的支持也构建到了 AppFuse 中。CruiseControl 是一个 Continuous Integration 应用程序,让我们可以在源代码仓库中代码发生变化时自动运行所有的测试。extras/cruisecontrol 目录包含了我们为基于 AppFuse 的项目快速、简单地设置 Continuous Integration 时所需要的文件。

设置 Continuous Integration 是软件开发周期中我们首先要做的事情之一。它不但激发程序员去编写测试用例,而且还通过 “You broke the build!” 游戏促进了团队之间的合作和融合。

理由 4:安全特性和可扩展性

AppFuse 最初是作为我为 Apress 编写的书籍 Pro JSP 中示例应用程序的一部分开发的。这个示例应用程序展示了很多安全特性和用于简化 Struts 开发的特性。这个应用程序中的很多安全特性在 J2EE 的安全框图中都不存在。使用容器管理认证(CMA)的认证方法非常简单,但是 Remember Me、密码提示、SSL 切换、登记和用户管理等功能却都不存在。另外,基于角色的保护方法功能在非 EJB 环境中也是不可能的。

最初,AppFuse 使用自己的代码和用于 CMA 的解决方案完全实现了这些特性。我在 2004 年年初开始学习 Spring 时就听说过有关 Acegi Security 的知识。我对 Acegi 所需要的 XML 的行数(175)与 web.xml 中所需要的 CMA 的行数(20)进行了比较,很快就决定丢弃 Acegi 了,因为它太过复杂了。

一年半之后 —— 在为另外一本书 Spring Live 中编写了一章有关使用 Acegi Security 的内容之后 —— 我就改变了自己的想法。Acegi 的确(目前仍然)需要很多 XML,但是一旦我们理解了这一点,它实际上是相当简单的。当我们最终作出改变,使用 Acegi Security 的特性来全部取代 AppFuse 的特性之后,我们最终删除了大量的代码。类之上的类都已经没有了,“Acegi handles that now” 中消失的部分现在全部进入了 CVS 的 Attic 中了。

Acegi Security 是 J2EE 安全模型中曾经出现过的最好模型。它让我们可以实现很多有用的特性,这些特性在 Servlet API 的安全模型中都不存在:认证、授权、角色保护方法、Remember Me、密码加密、SSL 切换、用户切换和注销。它让我们还可以将用户证书存储到 XML 文件、数据库、LDAP 或单点登录系统(例如 Yale 的 Central Authentication Service (CAS) 或者 SiteMinder)中。

AppFuse 对很多与安全性相关的特性的实现从一开始都是非常优秀的。现在 AppFuse 使用了 Acegi Security,这些特性 —— 以及更多特性 —— 都非常容易实现。Acegi 有很多地方都可以进行扩充:这是它使用巨大的 XML 配置文件的原因。正如我们已经通过去年的课程对 Acegi 进行集成一样,我们已经发现对很多 bean 的定义进行定制可以更加紧密地与 AppFuse 建立联系。

Spring IoC 容器和 Acegi Security 所提供的简单开发、容易测试的代码和松耦合特性的组合是 AppFuse 是这么好的一种开发平台的主要原因。这些框架都是不可插入的,允许生成干净的可测试代码。AppFuse 集成了很多开放源码项目,依赖注入允许对应用程序层进行简单的集成。

理由 5:使用 AppGen 生成代码

有些人会将代码生成称为代码气味的散播(code smell)。在他们的观点中,如果我们需要生成代码,那么很可能就会做一些错事。我倾向于这种确定自己代码使用的模式和自动化生成代码的能力应该称为代码香味的弥漫(code perfume)。如果我们正在编写类似的 DAO、管理器、操作或控件,并且不想为它们生成代码,那么这就需要根据代码的气味来生成代码。当然,当语言可以为我们提供可以简化任务的特性时,一切都是那么美好;不过代码生成通常都是一个必需 —— 通常其生产率也非常高 —— 的任务。

AppFuse 中提供了一个基于 Ant 和 XDoclet 的代码生成工具,名叫 AppGen。默认情况下,常见的 DAO 和管理器都可以允许我们对任何普通老式 Java 对象(POJO)进行 CRUD 操作,但是在 Web 层上这样做有些困难。AppGen 有几个特性可以用来执行以下任务:

  • (使用 Middlegen 和 Hibernate 工具)从数据库表中生成 POJO
  • 从 POJO 生成 UI
  • 为 DAO、管理器、操作/控制器和 UI 生成测试

在运行 AppGen 时,您会看到提示说 AppGen 要从数据库表或 POJO 中生成代码。如果在命令行中执行 ant install-detailed,AppGen 就会安装 POJO 特定的 DAO、管理器以及它们的测试。运行 ant install 会导致 Web 层的类重用通用的 DAO 和默认存在的管理器。

为了阐述 AppGen 是如何工作的,我们在 devworks MySQL 数据库中创建了如清单 2 所示的表:


清单 2. 创建一个名为 cat 的数据库表

    create table cat (      cat_id int(8) auto_increment,      color varchar(20) not null,      name varchar(20) not null,      created_date datetime not null,      primary key (cat_id)    ) type=InnoDB;

在 extras/appgen 目录中,运行 ant install-detailed。这个命令的输出结果对于本文来说实在太长了,不过我们在清单 3 中给出了第一部分的内容:


清单 3. 运行 AppGen 的 install-detailed 目标

$ ant install-detailedBuildfile: build.xmlinit:    [mkdir] Created dir: /Users/mraible/Work/devworks/extras/appgen/build     [echo]      [echo] +-------------------------------------------------------+     [echo] |             -- Welcome to the AppGen! --              |     [echo] |                                                       |     [echo] | Use the "install" target to use the generic DAO and   |     [echo] | Manager, or use "install-detailed" to general a DAO   |     [echo] | and Manager specifically for your model object.       |     [echo] +-------------------------------------------------------+    [input] Would you like to generate code from a table or POJO? (table,pojo)table    [input] What is the name of your table (i.e. person)?cat    [input] What is the name, if any, of the module for your table (i.e. organization)?     [echo] Running Middlegen to generate POJO...

要对 cat 表使用这个新生成的代码,我们需要修改 src/dao/com/ibm/dao/hibernate/applicationContext-hibernate.xml,来为 Hibernate 添加 Cat.hbm.xml 映射文件。清单 3 给出了我们修改后的 sessionFactory bean 的样子:


清单 4. 将 Cat.hbm.xml 添加到 sessionFactory bean 中

    <bean id="sessionFactory" class="...">    <property name="dataSource" ref="dataSource"/>    <property name="mappingResources">        <list>            <value>com/ibm/model/Role.hbm.xml</value>            <value>com/ibm/model/User.hbm.xml</value>            <value>com/ibm/model/Cat.hbm.xml</value>        </list>    </property>    ...</bean>

在运行 ant setup deploy 之后,我们就应该可以在部署的应用程序中对 cat 表执行 CRUD 操作了:


图 4. Cat 列表
所生成的主屏幕

图 5. Cat 表单
所生成的详细屏幕

我们在上面的屏幕快照中看到的记录都是作为代码生成的一部分创建的,因此现在就有测试数据了。

理由 6:文档

我们可以找到 AppFuse 各个风味的教程,并且它们都以 6 种不同的语言给出了:中文、德语、英语、韩语、葡萄牙语和西班牙语。使用风味(flavor) 一词,我的意思是不同框架的组合,例如 Spring MVC 加上 iBATIS、Spring MVC 加上 Hibernate 或 JSF 加上 Hibernate。使用这 5 种 Web 框架和两种持久框架,可以有好几种组合。有关它们的翻译,AppFuse 为自己的默认特性提供了 8 种翻译。可用语言包括中文、荷兰语、德语、英语、法语、意大利语、葡萄牙语和西班牙语。

除了核心教程之外,还添加了很多教程(请参看 参考资料) 来介绍与各种数据库、应用服务器和其他开放源码技术(包括 JasperReports、Lucene、Eclipse、Drools、Axis 和 DWR)的集成。

理由 7:社区

Apache 软件基金会对于开放源码有一个有趣的看法。它对围绕开放源码项目开发一个开放源码社区最感兴趣。它的成员相信如果社区非常强大,那么产生高质量的代码就是一个自然的过程。下面的内容引自 Apache 主页:

“我们认为自己不仅仅是一组共享服务器的项目,而且是一个开发人员和用户的社区。”

AppFuse 社区从 2003 年作为 SourceForge 上的一个项目(是 struts.sf.net 的一部分)启动以来,已经获得了极大的增长。通过在 2004 年 3 月转换到 java.net 上之后,它已经成为这里一个非常流行的项目,从 2005 年 1 月到 3 月成为访问量最多的一个项目。目前它仍然是一个非常流行的项目(有关 java.net 项目统计信息的链接,请参看 参考资料),不过在这个站点上它正在让位于 Sun 赞助的很多项目。

在 2004 年年末,Nathan Anderson 成为继我之后第一个提交者。此后有很多人都加入了进来,包括 Ben Gill、David Carter、Mika G?ckel、Sanjiv Jivan 和 Thomas Gaudin。很多现有的提交者都已经通过各种方式作出了自己的贡献,他们都帮助 AppFuse 社区成为一个迅速变化并且非常有趣的地方。

邮件列表非常友好,我们试图维护这样一条承诺 “没有问题是没有人理会的问题”。我们的邮件列表归档文件中惟一一条 “RTFM” 是从用户那里发出的,而不是从开发者那里发出的。我们绝对信奉 Apache 开放源码社区的哲学。引用我最好的朋友 Bruce Snyder 的一句话,“我们为代码而来,为人们而留下”。目前,大部分开发者都是用户,我们通常都喜欢有一段美妙的时间。另外,大部分文档都是由社区编写的;因此,这个社区的知识是非常渊博的。

结束语

我们应该尝试使用 AppFuse 进行开发,这是因为它允许我们简单地进行测试、集成、自动化,并可以安全地生成 Web 应用程序。其文档非常丰富,社区也非常友好。随着其支撑框架越来越好,AppFuse 也将不断改进。

从 AppFuse 2.0 开始,我们计划迁移到 JDK 5(仍然支持部署到 1.4)和 Maven 2 上去。这些工具可以简化使用 AppFuse 的开发、安装和升级。我们计划充分利用 Maven 2 的功能来处理相关依赖性。我们将碰到诸如 appfuse-hibernate-2.0.jar 和 appfuse-jsf-2.0.jar 之类的工件。这些工件都可以在 pom.xml 文件中进行引用,它们负责提取其他相关依赖性。除了在自己的项目中使用 AppFuse 基类之外,我们还可以像普通的框架一样在 JAR 中对这些类简单地进行扩展,这应该会大大简化它的升级过程,并鼓励更多用户将自己希望的改进提交到这个项目中。

如果没有其他问题,使用 AppFuse 可以让您始终处于 Java Web 开发的技术前沿上 —— 就像我们一样!

参考资料

学习


获得产品和技术

  • AppFuse on java.net:下载不同风味的 AppFuse。

  • WebWork:了解这个易于使用的 Web 框架。

  • DbUnit:查看更多有关 JUnit 扩展的内容。

  • jMock:创建动态仿真对象来简化真正的单元测试。

  • Canoo WebTest:自动化 Web 应用程序的 UI 测试。

  • HtmlUnit:WebTest 的优秀 JavaScript 支持背后的基础。

  • Cargo:自动启动和停止容器。

  • Greenbox:一种代码生成框架。


讨论

 



分享到:
评论

相关推荐

    appfuse

    描述中提到的是使用AppFuse 2.0版本的情况,这可能是指一个基于早期MVC架构的示例项目。在AppFuse 2.0时代,它主要支持Struts或 Tapestry 框架,而非现代的Spring Boot。由于描述中提到“没有jar包”,这可能意味着...

    使用 AppFuse 快速构建 java

    为了开始使用AppFuse,首先需要准备一个合适的开发环境。以下是一些基本步骤: 1. **下载AppFuse**: 从AppFuse的官方网站下载最新版本的源码包(本文使用的版本是appfuse-tapestry-1.9.3-src.zip)。将其解压至所需...

    可直接使用的appfuse项目

    AppFuse是一个集成了众多当前最流行开源框架与工具(包括Hibernate、ibatis、Struts、Spring、DBUnit、Maven、Log4J、Struts Menu、Xdoclet、SiteMesh、OSCache、JUnit、JSTL等(现在还有lucene的,无敌了))于一身的...

    玩转appfuse--使用appfuse建设MVC网站

    **玩转AppFuse:使用AppFuse建设MVC网站** AppFuse是一个开源项目,它提供了一个快速启动MVC(Model-View-Controller)Web应用程序开发的框架。基于Java,AppFuse集成了Spring、Struts2、Hibernate等流行的技术,极...

    AppFuse

    文档和教程最早于2003年11月发布,自那以后,AppFuse不断更新和完善,成为了java.net网站上最受欢迎的项目之一。 #### 三、功能特点 AppFuse提供了许多有用的功能,帮助开发者快速搭建和测试应用程序: 1. **容器...

    appfuse学习笔记(一)安装部署

    使用 Maven 的 archetype:generate 命令创建一个新的 AppFuse 项目。在命令行中输入以下命令: ``` mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeGroupId=org.appfuse -...

    APPFUSE工具研究.doc

    AppFuse分为1.x和2.0两个主要版本,其中2.0版是重构建的,采用了Maven 2作为构建工具,而1.x版本则使用Ant。 Maven 2的引入带来了许多优势,包括自动下载依赖项、简化维护(因为所有组件可以一次编译)以及方便最终...

    使用appfuse2建立项目原型骨架的步骤

    使用appfuse2建立项目原型骨架的步骤 appfuse2 项目原型 骨架

    appfuse 学习笔记

    在硬盘上创建一个项目根目录,例如 `E:\appfuse2-ly`。 **2. 使用 Maven 创建 Appfuse 项目** 在命令行中切换到项目根目录,然后输入以下命令: ```bash mvn archetype:create -DarchetypeGroupId=org....

    使用 AppFuse 快速构建 J2EE 应用

    2. **集成流行框架**:AppFuse 集成了诸如 Spring、Hibernate、MyBatis、Apache Tiles、Velocity 等广泛使用的 Java 开发框架,帮助开发者构建稳定且可扩展的应用。 3. **统一的配置**:通过整合各框架的配置,...

    建立项目原型骨架的步骤(最新版本appfuse)appfuse2.1.0-M2

    2. 生成项目后,使用`mvn appfuse:full-source`命令初始化项目。这个命令会处理ant存在的问题,特别是Windows环境下遇到的问题,确保$USER_HOME/.m2/repository目录存在并包含正确的settings.xml文件。 3. 接下来,...

    Appfuse2搭建文档

    Appfuse2的强大之处在于它的模块化设计,可以根据项目需求选择性地使用各个组件,同时,其丰富的文档和社区支持为开发者提供了便利的学习资源。在实际开发中,你可以继续深入学习这些技术,如Spring的高级特性、...

    AppFuse2.1所需包

    AppFuse 是一个开源项目,旨在简化Java Web应用程序的开发。它提供了一个基础架构,开发者可以在此基础上快速构建安全、可扩展的应用程序。AppFuse 2.1 版本是该项目的一个较早版本,但仍然包含了现代Web开发的核心...

    appfuse使用手册

    代码自动生成工具appfuse的中文使用手册

    MAVEN 搭建APPFUSE

    【MAVEN 搭建APPFUSE】是一个关于使用Maven构建基于AppFuse的应用程序的教程。AppFuse是一个开源项目,旨在简化Web应用程序的开发,它提供了一个基础框架,可以帮助开发者快速启动新项目,整合了Spring、Hibernate、...

Global site tag (gtag.js) - Google Analytics