java与java ee_最佳Java EE最佳实践

摘自IBM WebSphere开发者技术期刊

在过去的近十年中,关于Java™平台企业版(Java EE)最佳实践的文章很多。 现在有数十本书和数百(也许更多)的文章提供了有关应如何编写Java EE应用程序的见解。 实际上,有太多资源(通常带有相互矛盾的建议),以至于仅浏览这个迷宫本身就成为采用Java EE的障碍。 因此,为了为进入这个世界的客户提供一些简单的指导,我们汇总了这份最佳清单,列出了我们认为对Java EE最重要和最重要的最佳实践。 尽管我们进行了认真的尝试,但是我们无法捕获整洁的前十名中需要说的所有内容。 因此,为了避免遗漏关键的最佳实践,也为了尊重Java EE的增长,我们的清单是Java EE必不可少的“前19个”最佳实践。

最好的最佳实践

  1. 始终使用MVC。
  2. 不要重新发明轮子。
  3. 在每一层应用自动化的单元测试和测试工具。
  4. 开发规格,而不是应用服务器。
  5. 从第一天开始计划使用Java EE安全性。
  6. 建立您所知道的。
  7. 每当您使用EJB组件时,请始终使用会话外观。
  8. 使用无状态会话Bean而不是有状态会话Bean。
  9. 使用容器管理的事务。
  10. 首选JSP作为表示技术的首选。
  11. 使用HttpSessions时,仅存储当前业务交易所需的状态,不能存储更多状态。
  12. 利用不需要修改代码的应用程序服务器功能。
  13. 在现有环境中发挥出色。
  14. 拥抱应用程序服务器环境提供的服务质量。
  15. 拥抱Java EE,不要伪造它。
  16. 规划版本更新。
  17. 在代码的所有关注点上,使用标准日志记录框架记录程序状态。
  18. 一定要自己清理。
  19. 遵循严格的程序进行开发和测试。

1.始终使用MVC。

将业务逻辑(Java Bean和EJB组件)与表示形式(JSP,XML / XSLT)的控制器逻辑(servlet / Struts操作)完全分开。 良好的分层可以掩盖大量的罪过。


这种做法对于成功采用Java EE至关重要,因此对于#1插槽没有竞争。 模型视图控制器(MVC)是设计好的Java EE应用程序的基础。 它只是将程序的工作分为以下几个部分:

  1. 负责业务逻辑的人员(模型-通常使用Enterprise JavaBeans™或普通的旧Java对象实现)。
  2. 负责呈现用户界面(视图)的人员。
  3. 负责应用程序导航的人员(控制器-通常使用Java servlet或诸如Struts控制器之类的关联类实现)。

关于Java EE,有许多关于该主题的出色评论。 特别是,我们将感兴趣的读者定向到[Fowler]或[Brown](请参阅参考资料 )进行全面,深入的报道。

如果不遵循基本的MVC体系结构,可能会出现许多问题。 大多数问题是由于在架构的“视图”部分中放置过多内容而引起的。 在小型应用程序中,使用JSP标记库执行数据库访问或在JSP中执行应用程序流控制之类的做法在小规模应用程序中相对常见,但是随着JSP变得越来越难以维护和调试,这些做法可能会在以后的开发中引起问题。

同样,我们经常看到View层构造向业务逻辑的迁移。 例如,一个常见的问题是将用于视图构建的XML解析技术推入业务层。 业务层应该对业务对象进行操作,而不是对与视图绑定的特定数据表示形式进行操作。

但是,仅具有适当的组件并不能使您的应用程序正确分层。 找到具有所有三个servlet,JSP和EJB组件的应用程序是很普遍的,其中大多数业务逻辑是在servlet层中完成的,或者应用程序导航是在JSP中处理的。 您必须严格执行代码审查和重构,以确保仅在模型层中处理业务逻辑,应用程序导航仅是控制器层的工作范围,并且您的视图仅涉及将模型对象呈现为适当HTML和Javascript。 ™。

今天,此建议的价值应比本文的原始版本更加明确。 用户界面技术日新月异,将业务逻辑绑定到用户界面上的更改使得对“仅界面”的更改会深刻影响现有系统。 就在几年前,Web应用程序的用户界面开发人员可以从servlet和JSP,struts以及XML / XSL转换中进行选择。 从那时起,Tiles and Faces变得流行起来,现在AJAX赢得了很大的关注。 每当首选的用户界面技术发生变化时,都必须重新开发应用程序的核心业务逻辑,这是可耻的。

2.不要重新发明轮子。

使用公认的通用框架,例如Apache Struts,JavaServer Faces和Eclipse RCP。 使用经过验证的模式。


早在我们最初开始帮助客户培训如何使用当时出现的Java EE标准时,我们(与其他许多人一样)发现,开发用户界面开发框架比直接将UI应用程序构建到基础上显着提高了开发人员的生产率。 Servlet和JSP规范。 结果,许多公司开发了自己的UI框架,从而简化了界面开发的任务。

随着像Apache Struts这样的开源框架开始发展[Brown] ,我们相信向这些新框架的转换将是自动且快速的。 我们认为,拥有一个开源社区支持框架的好处对于开发人员来说是显而易见的,并且他们将很快获得普遍接受-不仅对于新开发,而且在改装应用程序中也是如此。

事实证明令人惊讶的是事实并非如此。 我们仍然看到许多公司维护或开发新的用户界面框架,这些框架在功能上与Struts或JSF等效。 之所以如此,有很多原因:组织惯性,“未在这里发明”综合症,在更改工作守则方面缺乏可察觉的利益,甚至在认为您可以做得比公开的事情“做得更好”时甚至有些自负源开发人员在特定框架中进行。

但是,这些原因中的任何一个值得作为不采用标准框架的借口的时间是很长的。 Struts和JSF不仅在Java社区中广为接受,而且在WebSphere运行时和Rational®工具套件中也得到了完全支持。 同样,在富客户端领域,Eclipse RCP(Rich Client Platform)也已获得了构建独立富客户端的广泛认可。 这些框架虽然不是Java EE标准的一部分,但现在已成为Java EE社区的一部分,因此应被接受。

几乎不使用现成的UI框架就显得有些暴躁,而忽略了[Alur]和[Fowler]中的课程。 这两本书详细介绍了Enterprise Java应用程序中最常见的可重用模式。 从简单的模式(例如会话外观)(在以后的建议中讨论)到更复杂的模式(例如Fowler的持久性模式(已在许多开源持久性框架中实现),这些作品都抓住了Java资深人士的积淀。 向桑塔亚纳(Satanyana)道歉,那些不了解过去的人会被谴责重蹈覆辙-如果他们有幸在第一次失败后获得了机会。

3.在每一层应用自动化的单元测试和测试工具。

不要只是测试您的GUI。 分层测试使调试和维护变得非常简单。


目前已在过去几年中为自称敏捷新的轻量级方法已经相当换血的方法学领域(如SCRUM [Schwaber的]和极限编程[Beck1在相关主题 )变得更加普遍。 几乎所有这些方法的标志之一是,它们提倡使用自动化测试工具,以帮助开发人员减少回归测试的时间,并避免因回归测试不足而导致的错误,从而提高程序员的工作效率。 实际上,一种称为“测试优先开发” [Beck2]的做法通过提倡在实际代码本身的开发之前编写单元测试来使这种做法更进一步。 但是,在测试代码之前,需要将其隔离为可测试的片段。 很难测试“大泥球”,因为它没有执行单个易于识别的功能。 如果代码的每个段都执行多项操作,则很难测试每一位的正确性。

MVC体系结构(以及MVC的Java EE实现)的优点之一是,元素的组件化使得有可能(实际上相对容易)分段测试应用程序。 因此,您可以轻松地编写测试来分别测试持久性,会话Bean和用户代码其余部分之外的部分用户界面。 有许多用于Java EE测试的框架和工具使此过程更加容易。 例如,由junit.org开发的开源工具JUnit和Apache联盟的开源项目Cactus对测试Java EE组件都非常有用。 [Hightower]详细讨论了这些工具在Java EE中的使用。

尽管有关于深度测试应用程序的所有重要信息,但我们仍然看到许多项目认为,如果对GUI进行了测试(可能是基于Web的GUI或独立的Java应用程序),则整个应用程序已经全面经过测试。 GUI测试很少。 有几个原因。

  1. 使用GUI测试,很难测试通过系统的每条路径。 GUI只是影响系统的一种方法。 可能会有后台作业,脚本和各种其他访问点也需要进行测试-但这些访问点通常没有与之关联的GUI。
  2. 在GUI级别上的测试非常粗糙。 GUI在系统的宏级别上测试系统的行为,这意味着如果发现问题,则必须考虑整个子系统,这使得发现任何已确定的错误非常困难。
  3. GUI测试通常要到开发周期的后期才能完全定义好,才能做好。 这意味着直到很晚才可以系统地发现潜在的错误。
  4. 一般的开发人员可能无法使用自动GUI测试工具。 因此,当开发人员进行更改时,该开发人员没有简单的方法来重新测试受影响的子系统。 这实际上不利于进行良好的测试。 如果开发人员可以访问自动代码级单元测试,则开发人员可以轻松地运行它们以确保所做的更改不会破坏现有功能。
  5. 如果完成了自动构建,则向自动构建过程添加自动化单元测试套件相当容易。 这样,可以定期(通常每晚)重建该系统,并在很少的人工干预下进行回归测试。

此外,我们必须强调,使用EJB和Web服务进行的基于组件的分布式开发绝对必要地测试您的单个组件。 如果没有要测试的GUI,则必须退回到较低级别的测试。 最好以这种方式开始,当需要将应用程序的一部分作为分布式组件或Web服务公开时,不必麻烦您进行流程的改进以包括那些测试。

总之,通过使用自动化的单元测试,可以更快地发现缺陷,更易于发现缺陷,可以使测试更加系统化,从而提高了总体质量。

4.开发规格,而不是应用服务器。

认真了解规格并在仔细考虑后才偏离规格。 仅仅因为您可以做某事并不意味着您应该做。


通过尝试在Java EE使您可以做的事情的边缘玩弄,很容易使自己感到悲伤。 我们发现开发人员尝试了一些他们认为比Java EE允许的工作“稍微好一点”的工作,从而发现自己陷入了一个漏洞,只是发现这会导致性能或迁移(从一个供应商到另一个供应商,或更常见的情况)的严重问题。版本之间)。 实际上,这是迁移中的一个问题,韦恩·比顿(Wayne Beaton)将此原则称为迁移工作的主要最佳实践。

在很多地方,没有采取最直接的方法肯定会引起问题。 当今常见的一种情况是,开发人员通过使用JAAS模块来接管Java EE安全性,而不是依靠内置的符合规范的应用程序服务器机制进行身份验证和授权。 谨防超出Java EE规范提供的认证机制。 这可能是安全漏洞和供应商兼容性问题的主要来源。 同样,依赖于servlet和EJB规范提供的授权机制,并且在需要超越它们的地方,请确保使用规范的API(例如getCallerPrincipal())作为实现的基础。 这样,您将能够利用供应商提供的强大安全基础结构,并在业务需求需要时支持更复杂的授权规则。 (有关授权的更多信息,请参见[Ilechko] 。)

其他常见问题包括使用未绑定到Java EE规范中的持久性机制(使事务管理变得困难),依赖Java EE程序中不适当的Java Standard Edition工具(如线程或单例),以及针对“滚动自己的”解决方案程序间通信,而不是停留在Java 2连接器,JMS或Web服务等受支持的机制之内。 从一台符合Java EE的服务器迁移到另一台,甚至迁移到同一服务器的新版本时,这种设计选择都不会造成困难。 在Java EE之外使用元素通常会引起细微的可移植性问题。 您唯一一次应该偏离规范的情况是,存在明显的问题无法在规范内解决。 例如,在引入EJB 2.1之前,安排定时业务逻辑的执行是一个问题。 在这种情况下,我们建议您在可能的情况下使用供应商提供的解决方案(例如WebSphere Application Server中的Scheduler工具),或者在不可用的情况下使用第三方工具。 当然,今天,EJB规范现在提供了基于时间的功能,因此我们鼓励使用标准接口。 这样,维护和迁移到更高规范版本就成为供应商的问题,而不是您自己的问题。

最后,过早采用新技术时要小心。 在将技术集成到Java EE规范的其余部分或供应商的产品中之前,过分地采用该技术通常会带来灾难。 支持至关重要-如果您的供应商不直接支持特定技术,则应仔细考虑是否应使用它。 人们(尤其是开发人员)倾向于过于关注简化开发过程,而忽略了长期后果,即依赖于组织外部开发的大量代码(不受供应商支持)而导致的长期后果。 我们已经看到太多的项目团队迷上了新技术(例如最新的开源框架),并且很快就依赖它,而没有考虑到业务的实际成本。 坦白地说,公司架构,业务和法律团队(或您所在环境中的同等团队)应仔细评估使用除您从供应商那里购买的产品以外的任何技术的决定,就像评估正常的产品购买决定一样。 毕竟,除了极少数的例外,我们大多数人都在解决业务问题,而不是为了纯粹的乐趣而发展技术。

5.从第一天开始计划使用Java EE安全性。

打开WebSphere安全性。 将所有EJB和URL锁定到至少所有经过身份验证的用户。 甚至不问-只需这样做。


我们一直感到惊讶,这是我们不断感到惊讶的原因,最初与我们合作的客户中有多少人计划开启WebSphere Application Server的Java EE安全性。 据我们估计,最初看到的客户中只有大约50%计划使用此功能。 我们甚至与多家计划不启动安全性的大型金融机构(银行,经纪公司等)合作; 幸运的是,通常在部署之前先审查一下这种情况。

不充分利用Java EE安全性是一个危险的游戏。 假设您的应用程序需要安全性(几乎所有功能都需要这样做),您打赌您的开发人员可以比从Java EE供应商那里购买更好的安全性基础架构。 那不是一个好选择。 保护分布式应用程序非常困难。 例如,您需要使用网络安全的加密令牌来控制对EJB的访问。 根据我们的经验,大多数本地安全基础结构都不安全-存在严重缺陷,使生产系统非常脆弱。 (有关更多信息,请参阅[Barcia]的第18章。)

不使用Java EE安全性的原因包括:担心性能下降,相信其他安全产品(例如IBMTivoli®Access Manager和Netegrity SiteMinder)已经可以解决此问题,或者对WebSphere Application Server安全性的特性和功能不了解。 不要掉入这些陷阱。 特别是,虽然像Tivoli Access Manager这样的产品提供了出色的安全性功能,但仅靠它们本身并不能保护整个Java EE应用程序。 他们必须与Java EE应用程序服务器协同工作,以保护系统的所有方面。

不使用Java EE安全性的另一个常见原因是基于角色的模型不能提供足够的粒度访问控制来满足复杂的业务规则。 尽管通常是这样,但这并不是避免Java EE安全的理由。 而是将Java EE身份验证模型和Java EE角色与您的特定扩展规则结合使用。 如果需要复杂的业务规则来做出安全决策,请编写代码以执行该决策,并基于易于获得且可信任的Java EE身份验证信息(用户的ID和角色)来做出决策。 (有关授权的更多信息,请参见[Ilechko] 。)

6.建立您所知道的。

迭代开发使您逐渐掌握Java EE的所有移动组件。 通过您的应用程序构建小的垂直切片,而不是一次完成所有操作。


面对现实,Java EE非常强大。 如果开发团队只是从Java EE开始,那么尝试一次全部学习就太困难了。 有太多的概念和API需要掌握。 在这种环境下取得成功的关键在于以较小的受控步骤进行Java EE的开发。

通过在应用程序中构建小的垂直切片,可以最好地实现此方法。 一旦团队通过构建简单的域模型和后端持久性机制(也许使用JDBC)建立了信心,并且已经对该模型进行了彻底的测试,他们便可以继续使用该Servlet和JSP来掌握前端开发。域模型。 如果开发团队发现对EJB的需求,那么他们可以从在容器管理的持久性EJB或基于JDBC的DAO(数据访问对象)之上的简单会话外观开始,然后再转向消息驱动Bean和JMS等更复杂的结构。

这种方法并不是什么新鲜事物,但是实际上很少有团队以这种方式来培养自己的技能。 取而代之的是,大多数团队都试图通过一次构建所有内容来安排压力—他们同时攻击MVC中的View层,Model层和Controller层。 相反,可以考虑采用一些新的敏捷开发方法,例如极限编程(XP),这些方法可以促进这种增量式学习和开发。 在XP中通常使用一种称为ModelFirst [Wiki]的过程 ,该过程涉及首先构建域模型,作为组织和实现用户案例的机制。 基本上,您将域模型构建为所实现的第一组用户故事的一部分,然后作为实现更高版本的用户故事的结果,在其之上构建UI。 这非常适合让团队一次学习一种技术,而不是让他们同时参加十二门课(或让他们阅读十二本书),而这可能会让人感到不知所措。

同样,每个应用程序层的迭代开发也促进了适当模式和最佳实践的应用。 如果从应用程序的较低层开始并应用数据访问对象和会话外观等模式,则不应以JSP和其他View对象中的域逻辑结束。

最终,当您在垂直的薄切片中进行开发时,可以更轻松地开始对应用程序进行性能测试。 正如[Joines]所说的那样,将性能测试推迟到应用程序开发周期的末尾肯定会带来灾难。

7.每当您使用EJB组件时,请始终使用会话外观。

在架构上适当时,请使用本地EJB。


使用会话外观是使用EJB的最佳实践之一。 实际上,对于任何分布式技术,包括CORBA,EJB和DCOM,都广泛倡导通用做法。 基本上,应用程序的分布“横截面”越低,针对小块数据进行多次重复的网络跃迁所造成的开销浪费的时间就越少。 完成此操作的方法是创建非常大的“外观”对象,这些对象包装逻辑子系统并且可以在单个方法调用中完成有用的业务功能。 这不仅将减少网络开销,而且在EJB中,还可以通过为整个业务功能创建单个事务上下文来显着减少数据库调用的次数。 (此被详细描述在[布朗]描述。阿卢尔]具有这种模式的规范表示,但它也被在[福勒](其概括它不仅仅是的EJB)和[马里内斯库]。见描述相关主题 。)细心的读者会意识到,这实际上是面向服务的体系结构(SOA)的核心原则之一。

作为EJB 2.0规范的一部分引入的EJB本地接口,为同一位置的EJB提供了性能优化。 本地接口必须由您的应用程序显式调用,这需要更改代码并阻止以后无需应用程序更改即可分发EJB的能力。 如果您确定EJB调用将始终是本地的,请利用本地EJB的优化。 但是,会话外观本身的实现(通常是无状态会话Bean)应设计用于远程接口。 这样,EJB本身可以被其他客户端远程使用,而不会严重破坏现有的业务逻辑。 由于EJB可以同时具有本地和远程接口,所以这是相当可行的。

为了优化性能,可以将本地接口添加到会话外观。 这利用了这样一个事实,即在大多数情况下,至少在Web应用程序中,您的EJB客户端和EJB将位于同一JVM中。 另外,如果会话外观在本地但使用远程接口调用,则可以使用Java EE应用程序服务器配置优化,例如WebSphere“ No Local Copies”。 但是,您必须意识到,这些替代方案将交互的语义从“按值传递”更改为“按引用传递”。 这可能会导致代码中的细微错误。 最好使用本地EJB,因为该行为可以逐个bean进行控制,而不是影响整个应用程序服务器。

如果将会话界面使用远程接口(而不是本地接口),则还可以通过Java EE 1.4兼容方式将同一会话界面作为Web服务公开。 (这是因为JSR 109是Java EE 1.4的Web服务部署部分,要求您使用无状态会话Bean的远程接口作为EJB Web服务和EJB实现之间的接口。)这样做通常是可取的,因为它可以增加业务逻辑的客户端类型数量。

8.使用无状态会话Bean而不是有状态会话Bean。

这使您的系统更适合故障转移。 使用HttpSession来存储用户特定的状态。


在我们看来,有状态会话bean是一个想法,它的时代已经来临...过去了。 如果您考虑一下,从结构上来说,有状态会话Bean与CORBA对象完全相同-单个对象实例绑定到单个服务器,该服务器的生命周期取决于该服务器。 如果服务器关闭,对象值将丢失,因此该bean的所有客户端都将失去运气。

提供有状态会话Bean故障转移的Java EE应用程序服务器可以解决某些问题,但是有状态解决方案的可伸缩性不如无状态解决方案。 例如,在WebSphere Application Server中,对无状态会话Bean的请求在已部署无状态会话Bean的集群的所有成员之间进行负载平衡。 相反,Java EE应用程序服务器无法平衡对有状态Bean的请求的负载。 这意味着负载可能会不均衡地分布在群集中的服务器之间。 另外,使用有状态会话Bean会将状态推送到您的应用程序服务器,这是不希望的。 有状态会话Bean增加了系统复杂性并使故障场景变得复杂。 健壮的分布式系统的关键原理之一是尽可能使用无状态行为。

因此,我们建议为大多数应用程序选择无状态会话bean方法。 处理所需的任何特定于用户的状态都应作为EJB方法的参数传递(并通过HttpSession之类的机制存储在EJB外部),或作为EJB事务的一部分从持久后端存储中检索。 (例如,通过使用实体Bean)。 在适当的情况下,此信息可以缓存在内存中,但要注意在分布式环境中保持缓存一致所带来的潜在挑战。 缓存最适合只读数据。

通常,您应该确保从第一天开始就计划可伸缩性。 检查设计中的所有假设,看看您的应用程序是否可以在多台服务器上运行,这些假设是否仍然成立。 该规则不仅适用于上述情况下的应用程序代码,还适用于MBean和其他管理接口等情况。

避免有状态性不仅仅是基于IBM工具套件的假定局限性的IBM / WebSphere建议。 这是Java EE的基本设计原则。 请参阅[Jewell],以了解Tyler Jewell对有状态bean的尖酸刻薄的观点,这些观点与上述陈述相呼应。

9.使用容器管理的事务。

了解两阶段提交事务如何在Java EE中工作并依赖它们,而不是开发自己的事务管理。 容器几乎总是会在事务优化方面做得更好。


使用容器管理的事务(CMT)具有两个关键优势,如果没有容器支持,这些优势几乎是无法获得的:可组合的工作单元和强大的事务行为。

如果您的应用程序代码明确地开始和结束事务(也许使用javax.jts.UserTransaction,甚至使用本机资源事务),那么将来对模块的需求(可能是重构的一部分)通常需要更改事务代码。 例如,如果模块A开始数据库事务,更新数据库然后提交事务,而模块B做同样的事情,请考虑当您尝试同时使用模块C中的两个模块时会发生什么。现在,模块C正在执行以下操作:单个逻辑操作实际上导致了两个独立的事务发生。 如果模块B在操作过程中发生故障,则模块A的工作仍将提交。 这不是所需的行为。 相反,如果模块A和模块B都使用CMT,则模块C也可以启动CMT(通常通过部署描述符隐式启动),并且模块A和B中的工作将隐式属于同一工作单元,而无需进行任何操作。复杂的返工。

如果您的应用程序需要在同一操作中访问多个资源,则需要两阶段提交事务。 例如,如果从JMS队列中删除了一条消息,然后根据该消息在数据库中更新了一条记录,那么这两种操作都会发生-或两者都不发生很重要。 如果从队列中删除了该消息,然后系统在未更新数据库的情况下发生了故障,则该系统不一致。 不一致的状态导致严重的客户和业务影响。

我们偶尔会看到客户端应用程序试图实现自己的解决方案。 如果数据库更新失败,则应用程序代码可能会尝试“撤消”队列操作。 我们不建议这样做。 实现比您最初想象的要复杂得多,并且有很多极端的情况(想象一下,如果应用程序在此过程中崩溃,将会发生什么)。 而是使用两阶段提交事务。 如果您使用CMT并在单个CMT中访问具有两阶段提交功能的资源(例如JMS和大多数数据库),那么WebSphere Application Server将处理繁琐的工作。 它将确保事务完全完成或完全没有完成,包括失败情况,例如系统崩溃,数据库崩溃或其他情况。 该实现在事务日志中维护事务状态。 如果应用程序访问多个资源,我们不能足够强调依赖CMT事务的需求。 如果您正在访问的资源无法提供两阶段提交,那么您当然别无选择,只能使用更复杂的方法-但是您应该尽一切可能避免这种情况。

10.选择JSP作为表示技术的首选。

仅当您具有必须由单个控制器和后端支持的多种演示输出类型时,才使用XML / XSLT。


对于为什么您应该选择XML和XSLT作为基于JSP的表示技术,我们经常听到一个普遍的争论,那就是JSP允许您“过多地混合模型和视图”,而XML / XSLT在某种程度上不受限制。这个问题。 不幸的是,事实并非如此-或至少不像看起来的那样黑白。 XSL and XPath are, in reality, programming languages. In fact, XSL is Turing-complete, even though it may not match most people's definition of a programming language in that it is rules-based and does not have all of the control facilities that programmers may be used to.

The issue is that given this flexibility, developers will take advantage of it. While everyone agrees that JSP makes it easy for developers to do "model-like" behaviors in the view, the fact is that it's possible to do some of the same kinds of things in XSL. While it's very difficult (if not impossible) to do things like calling databases from XSL, we've seen some incredibly complex XSLT stylesheets that perform difficult transformations that still amount to model code.

However, the most basic reason why you should choose JSP as your first option for presentation technology is simply because it's the best supported and best-understood Java EE view technology available. Given the introduction of custom tag libraries, the JSTL, and the JSP 2.0 features, it's become increasingly easy to build JSPs that do not require any Java code, and that cleanly separate model and view. There is significant support (including debugging support) for JSP built into development environments, like IBM Rational Application Developer, and many developers find developing with JSP easier than developing with XSL -- mainly due to how JSP is procedurally based, as opposed to rules-based. While Rational Application Developer supports XSL development, the graphical layout tools and other features supporting JSP (especially when in the context of frameworks like JSF) make it much easier for developers to work in a WYSIWYG way -- something that isn't easily done with XSL.

This is not to say that you should never use XSL, however. There are certain cases where the ability of XSL to take a single representation of a fixed set of data and render it in one of several different ways based on different stylesheets (see [Fowler] ) is the best solution for rendering your views. However, this kind of requirement is most often the exception rather than the rule. If you are only ever producing one HTML rendering for each page, then in most cases, XSL is overkill, and it will cause more problems for your developers than it will solve.

11. When using HttpSessions, store only as much state as you need for the current business transaction and no more.

Enable session persistence.


HttpSessions are great for storing information about application state. The API is easy to use and understand. Unfortunately, developers often lose sight of the intent of the HttpSession -- to maintain temporary user state. It's not an arbitrary data cache. We've seen far too many systems that put enormous amounts of data -- megabytes -- in each user's session. Well, if there are 1000 logged-in users, each with a 1 MB HTTP session, that's one gigabyte or more of memory in use just for sessions. Keep those HTTP sessions small. If you don't, your application's performance will suffer. A good rule of thumb is something under 2K-4K. This isn't a hard rule. 8K is still okay, but obviously slower than 2K. Just keep your eye on it and prevent the HttpSession from becoming a dumping ground for data that "might" be used.

One common problem is in using HttpSessions to cache information that can be easily recreated, if necessary. Since sessions are persisted, this is a very expensive decision forcing unnecessary serialization and writing of the data. Instead, use an in memory hash table to cache the data and just keep a key to the data in the session. This enables the data to be recreated should the user fail over to another application server.

Speaking of session persistence, don't forget to enable it. If you don't enable session persistence, should a server be stopped for any reason (a server failure or ordinary maintenance), any user that is currently on that application server will lose their session. That makes for a very unpleasant experience. They have to log in again and redo whatever they were working on. If instead, session persistence is enabled, WebSphere will automatically move the user (and their session) to another application server, transparently. They won't even know it happened. This works so well, that we've actually seen production systems that crash regularly (due to nasty bugs in native code -- not IBM code!) still provide adequate service.

12. Take advantage of application server features that do not require your code to be modified.

With features such as WebSphere Application Server caching and the Prepared Statement cache, the performance gains are substantial and the overhead is minimal.


Best practice #4 above states a clear case as to why you should be very prudent in applying application-server-specific features that modify your code. It makes portability difficult and may make version migration challenging as well. However, there are a suite of application-server specific features, particularly in WebSphere Application Server, that you can and should take full advantage of precisely because they do not modify your code. Your code should be written to the specification, but if you know about these features and how to properly use them you can take advantage of significant performance gains.

For one example of this, in WebSphere Application Server, you should turn on dynamic caching and use servlet caching. The performance gains are substantial and the overhead minimal, while the programming model is unaffected. The merits of caching to improve performance are well understood. Unfortunately, the current Java EE specification does not include a mechanism for servlet/JSP caching. However, WebSphere Application Server provides support for page and fragment caching through its dynamic cache function without requiring any application changes. The cache policy is specified declaratively and configuration is through XML deployment descriptors. Therefore, your application is unaffected, remaining Java EE specification compliant and portable, while benefiting from the performance optimizations provided from WebSphere's servlet and JSP caching.

The performance gains from dynamic caching of servlets and JSPs can be substantial, depending on the application characteristics. Cox and Martin [Cox] showcase performance benefits up to a multiplier of 10 from applying dynamic caching to an existing RDF (Resource Description Format) site summary (RSS) servlet. Please recognize that this experiment involved a simple servlet, and this order of magnitude improvement may not be reflective of a more complex application mix.

For additional performance gains, the WebSphere Application Server servlet/JSP results cache is integrated with the WebSphere plug-in ESI Fragment processor, the IBM HTTP Server Fast Response Cache Accelerator (FRCA) and Edge Server caching capabilities. For heavy read-based workloads, significant additional benefits are gained through leveraging these capabilities. (See performance gains described in [Willenborg] and [Bakalova] in Related topics .)

For another example of the principle (which we often observe customers not use simply because they don't know that it exists), take advantage of the WebSphere Prepared Statement Cache when writing JDBC code. By default, whenever you use a JDBC PreparedStatement in WebSphere Application Server, it will compile the statement once and then place it in a cache that will be reused not just later in the same method where the PreparedStatement is created, but across all points in your program where the same SQL code is used in the same or another PreparedStatement. Saving this re-compilation step can result in a significantly lower number of calls to the JDBC driver and improve the performance of your application. You don't have to do anything special to take advantage of this; just write your JDBC code to use PreparedStatements. By writing your code to use a PreparedStatement instead of a regular JDBC Statement class (which uses purely dynamic SQL) you can take advantage of this performance enhancement while not losing any portability.

13. Play nice within existing environments.

Deliver a Java EE EAR and configurable installation scripts, not a black box binary installer.


In most realistic scenarios, large WebSphere Application Server users run multiple applications in the same shared cell. This means that if you provide an application to be installed, it must install reasonably into an existing infrastructure. This means two things: First, you must limit the number of assumptions you make about the environment, and ultimately because you can't possibly anticipate every variant, your installation process must be visible. By visible, we mean that providing a binary executable that is the installer is not acceptable. Administrators performing the installation need to understand what the install process is doing to their cell. To facilitate this, you should deliver an EAR file (or a set of EAR files), along with documentation and installation scripts. The scripts should be readable so that the installer can understand what they do and can validate that there is nothing dangerous being done by the scripts. For situations where the scripts are inappropriate, users may need to install your EARs using some other process that they already use - meaning you must document what your installer is doing!

14. Embrace the qualities of service provided by the application server environment.

Design applications to be clusterable using WebSphere Application Server Network Deployment.


We've already mentioned the importance of leveraging WebSphere Application Server security and transactional support. One more important area that we see ignored far too often is clustering. Applications need to be designed and delivered to run in a clustered environment. Most realistic environments require clustering for scalabity and reliabilty. Applications that don't cluster lead quickly to disaster.

Closely related to clustering is supporting WebSphere Application Server Network Deployment. If you are building an application that you will sell to others, make sure your application runs on WebSphere Application Server Network Deployment and not just the single server versions.

15. Embrace Java EE, don't fake it.

Commit to building real Java EE applications that truly leverage Java EE function.


One of the most disturbing things we've seen more than once is an application that claims to "run in WebSphere" but isn't really a WebSphere application. We've seen several examples where there is a thin piece of code (perhaps a servlet) in WebSphere Application Server and all of the remaining application logic is actually in a separate process; for example, a daemon process written in Java, C, C++ or whatever -- but not using Java EE -- does the real work. That's not a real WebSphere Application Server application. Virtually all of the qualities of service that WebSphere Application Server provides aren't available to such applications. This can be quite a rude awakening for folks that think this is a WebSphere Application Server application.

16. Plan for version updates.

变化是不可避免的。 Plan for new releases and fix updates so that your customers can stay current.


WebSphere Application Server continues to evolve, and so it should not surprise you that IBM regularly produces fixes for WebSphere Application Server, and that IBM periodically releases new major versions. You need to plan for this. There are two kinds of development organizations that this impacts: in-house developers and third party application vendors. The basic issues are the same, but each is impacted differently.

First, consider fixes. IBM regularly releases recommended updates that fix known bugs in our products. While it is likely impossible to always be running at the latest levels, it is prudent to not fall too far behind. How "far behind" is it okay to be? There is no right answer to this, but you should plan on supporting fix levels within a few months of their release. Yes, this means upgrades in production a few times a year. In-house developers can feel free to skip certain fix levels and support one fix level at a time to reduce testing costs. Application vendors aren't so lucky. If this is you, then you need to support multiple fix levels at the same time so that your customers can run your software in conjunction with other software. If you support only one fix level, it may quite literally be impossible to find fix levels compatible across multiple products. Really, the best approach for vendors is to go with the model of supporting "upwardly compatible fixes." This is the approach IBM uses with regard to support products of other vendors with which we integrate (such as Oracle®, Solaris™, and so on). Refer to our support policy for more information.

Second, consider major version upgrades. Periodically, IBM releases new major releases of our products with major functional upgrades. We continue to support older major releases, but not forever. This means you must plan for forced moves from one major release to another. This is simply unavoidable and must be considered in your cost model. If you are a vendor, this means you have to upgrade your product to support new versions of WebSphere Application Server from time to time, or your customers will be stranded on unsupported IBM products -- which is something we've seen happen more than once! If you are purchasing a product from a vendor, we encourage you to ensure through due diligence that your vendor is committed to supporting new versions of IBM products. Being stranded on unsupported software is a very dangerous situation.

17. At all points of interest in your code, log your program state using a standard logging framework.

This includes exception handlers. Use a logging framework like JDK 1.4 logging or Log4J.


Logging is sometimes the most tedious, undervalued part of programming, but it is the difference between long hours of debugging and going home at a reasonable time. As a general rule of thumb, at every transition point, log it. When you're passing parameters from one method to another method, or between classes, log it. When doing some transformation on an object, log it. When in doubt, log it.

Once you've made the decision to log, choose an appropriate framework. There are lots of good choices out there but we are partial to the JDK 1.4 trace APIs, as they are fully integrated into the WebSphere Application Server trace subsystem and are standards-based.

18. Always clean up after yourself.

If you obtain an object from a pool, always make sure you return it back to the pool.


One of the most common errors we see with Java EE applications, whether running in development, test, or production, are memory leaks. Nine times out of ten, it's because a developer forgot to close a connection (JDBC most of the time) or return an object back into the pool. Make sure that any objects that need to be explicitly closed or returned to the pool are so done. Don't be one of the culprits responsible for the offending code.

19. Follow rigorous procedures for development and testing.

This includes adopting and following a software development methodology.


Large scale system development is hard and it should be taken seriously. Yet, too many times we find teams that are lax in their policies, or that half-heartedly follow development methods that may not apply for the type of development that they are doing, or that they don't understand well. Perhaps the worst extreme of this is trying on the "Development method of the month" where a team will swing from RUP to XP to some other agile method within the lifecycle of a single project.

In short, almost any method will work for most teams provided that they are well-understood by the team members, followed rigorously, and adjusted carefully to deal with the specific natures of the technology and team that is using that method. For teams that have not adopted a method, or have not fully embraced the method that they have chosen, we would refer them to classic works like [Jacobson], [Beck1], or [Cockburn]. Another useful source of information is the recently announced OpenUP plug-in for the Eclipse Process Framework [Eclipse]. And so that we don't repeat too much of what has been said on this topic already, see [Hambrick] and [Beaton2]. (请参阅相关主题 。)

结论

In this brief summary we have taken you through the core patterns and best practices that can make Java EE development a manageable endeavor. While we have not shown all of the details necessary to put these patterns into practice, we have hopefully given you enough pointers and direction to help you determine where to go next.

致谢

Thanks to all of those who first documented these patterns and best practices (and whom we reference below), and also to John Martinek, Paul Ilechko, Bill Hines, Dave Artus and Roland Barcia for their help in reviewing this article.


翻译自: https://www.ibm.com/developerworks/websphere/techjournal/0701_botzum/0701_botzum.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值