在不久前的一段时间内,Java
开发人员在准备一个新的企业 Java 开发项目时,事先就知道将要使用的工具。当时,一切都很简单:J2EE 是新的,HTML
浏览器是公认的用户界面标准,而复杂性(至少从推测的角度而言)已成为过去的事情。而如今,事情变得如此复杂。
“开发人员面对的选择令人眼花缭乱。”
开发人员面对的选择令人眼花缭乱,从“轻型容器”(如 Spring、NanoContainer
或 HiveMind)到“web 框架”(如 WebWork、Tapestry(一个基于 JSF 的 UI,类似于
Oracle 的新应用程序开发框架 (Oracle ADF))或 Velocity)。这些选择还增加了一系列新的
J2EE 规范,或者说是通过 JAXM、SAAJ、JAX-RPC 或 JAX 对“Web 服务”和相应的新技术术语“面向服务的体系结构”赋予了新的价值(更不用提“WS-*”规范、工具和库了),Java
开发人员可以完成所有工作,这真是一个奇迹。
No Fluff Just Stuff 软件论文系列的演讲者 Ben Galbraith
将此现象称作“Java 框架不确定性原则”:“您刚刚选择了一个框架,某个其他框架的新版本便发布了,从而迫使您对选择框架重新分析。”而且这种情况的复杂程度也无以复加了:只需将核心
J2EE 和 J2SE 类混合在一起使用。毕竟,我们被告知 EJB 是 J2EE 的“核心”,并且考虑一个没有
EJB 的企业 Java 项目将是一个愚蠢的想法,这只是昨天的事。究竟泛型如何改变您的 J2EE 编码体验?并且到底是谁让所有
Java 管理扩展成了路障?
到底是怎么了?最初明确专注于创建一个由单项优势工具和库构成的平台的行业何以在如此短的时间内变得如此零乱?我们何时需要在传统的“J2EE”工具(如
EJB)与新型“Web 服务”(如 JAXRPC 和 WS-Security)工具之间进行选择?更重要的是,我们现在如何做才能避免
Ben 的 Java 框架不确定性原则而又不违背 Java 首先应遵循的供应商无关原则?
此问题主要在于了解最能满足需要的技术,而最好的方法是首先了解应用程序的需要。了解应用程序的需要后,即可清楚地界定应选用的相应技术。
本文将简要概述最先进的 J2EE、与其相关的技术以及 Java 开发人员当今面临的某些体系结构挑战。
我们如今要走向何处?
很多不同类型的 Java 程序在“企业 Java”的名义下趋于变得臃肿,在深入讨论前,这也许有助于将它们与其他类型的
Java 应用程序区分开。如果我们从传统的“3 层”方法开始(即将表示、业务逻辑和数据访问划分为三个一致的设计层次),则我们实际上可以确定五种“企业”Java
应用程序:烟囱、宝石、聚合器、集成器和企业应用程序。
“我们实际上可以确定五种“企业”Java 应用程序:烟囱、宝石、聚合器、集成器和企业应用程序”。
烟囱烟囱应用程序(也称作“竖井”)可能是开发人员最容易接受的应用程序,这是因为它是一种我们一再开发的应用程序:它是传统的“单数据库、单
UI”应用程序,就绝对数量而言,它是当前构建最广的一种 IT 应用程序。它通常是根据某个部门经理或副经理的需要(即寻找某个特定工具或应用程序来收集、操作和显示某种当前未收集、操作和显示的数据)而开始创建的,为此将组建一个团队(规模通常不超过三到四个人,往往只有一个人)来收集需求、建立用例、构建数据库、对业务逻辑进行编码、将其部署到选择作为此应用程序的生产服务器的机器并不断地监视它。
当然,此名称得自您在白板上绘制的三个框(表示系统的逻辑层 — 表示层、业务逻辑层和数据访问层)所形成的图像
— 它们构成了一条垂直线,不由使人想起将燃烧木头的火炉中产生的烟排出到房间外面的旧式“烟囱”。(顺便说一下,对于将该术语用作贬义术语的用户而言,请记住,您在一生中将使用的许多最重要的系统(如
ATM 机、主要船运公司场地上的包裹定位器等)都是烟囱系统。
有一点可能比较令人吃惊的是,J2EE 软件套件并不能完全满足构建简单烟囱系统的开发人员的需要。当只需要一个表示层,且只有一个资源用于存储和检索数据时,J2EE
套件(尤其是 EJB)就显得“碍事”了。更诱人的方法是考虑轻型框架,因为它们并不那么专注于部署描述符,并且就 JNDI、JMS
之类而言也没什么不便的。它只是通过 web 浏览器进行的基本请求/响应通信,通常构建在类似 Struts 或相似的
MVC 样式 web 框架中,并与一组核心的传统 Java 对象(有时与单个机器上运行的表示层和业务逻辑层(而非数据库本身))进行通信。(您可能奇怪此处为什么没有使用术语“数据库”。原因很简单,虽然大多数项目使用数据库(而且还是关系数据库)存储数据,但数据存储通常是原有系统、商业软件程序包或形如
CICS 大型机、SAP 或 BizTalk 的“中介”技术。使用更一般的术语“资源”有助于强调这样一个看法:后端实现确实与本讨论无关。)
烟囱应用程序的另一个优势是它们通常是“独立的” — 也就是说不涉及其他应用程序。几乎不需要遵守任何已建立的安全、可靠性或管理标准,这是因为此应用程序所确立的所有内容都将成为标准(至少对此应用程序而言是这样,这正是此范围的关键所在)。开发人员经常利用此事实来构建正好适合于此应用程序的基础架构,从而消除了通常针对企业
Java 应用程序的指责:它们太复杂了,以至于无法使用和维护。
尽管人们希望如此,但 J2EE 的设计并非是针对烟囱应用程序的 — 当然,一个基于
J2EE 的应用程序可以构建此类应用程序(并且有上千个示例可以作为此事实的证据),事实上有点像用牛刀杀鸡。基于
J2EE 的应用程序实施了一定程度的层划分,但有时这种划分对于解决手头的问题显得有些矫枉过正,如传统的“10 用户”烟囱系统。当然,问题是
10 用户烟囱系统通常有一种另人不悦的趋势,即转变为其他四个版本中的某个版本,这样将使事情变得很糟。就像某位哲学家说的那样“没有哪个人是孤立的”,我们也可以很轻松和准确地说“没有哪个系统是孤立的”。至少在短期内是这样。(当然,如果系统无法完成其预期的目标,那它就无法与任何其他系统集成,并且可能停产,但我们将假设那不是预期的目标。)
珠宝 我们并不是说这是 IT 环境的成功和骄傲或五种应用程序样式中“最好”的一个,但珠宝样式的应用程序是结合了多个表示层的应用程序(因此,它的名称--“珠宝”表示有很多面可供查看)。但请注意,给定表示层可能根本不是供用户查看的;公司当前经常探讨的一个层是其基于
Web 服务的应用程序前端,它并非为人使用而设。尽管如此,该 Web 服务仍表示一个表示层,这是因为它从根本上执行同一操作:获取输入并从其下面的核心业务逻辑层中提供输出。
由于一度曾存在的某些假设突然间不复存在了,珠宝应用程序对传统编程模型进行了一些有趣的转变。例如,当考虑一个
Web 服务前端时,突然必须以某种平台和语言无关的方式(对此,XML 模式是当前可以选择的工具)定义类型,而理想情况下,“一次且仅此一次”规则(也称作“不重复自身”原则)将允许我们直接通过基于
HTML 的表示层用来与业务逻辑层通信的同一类型构建此类型。这就是某些 JAX* 规范的用武之地--例如,Java
API for XML Binding 有助于定义一个以非常模糊的方式进行“对象到 XML 以及 XML 到对象”转换的标准方法,而
Java API for XML RPC (JAX-RPC) 定义一种使用 WSDL、SOAP 和 XML 构建可互操作的请求-响应远程通信层的方法。
尽管任何事物都不能阻止开发人员从其最爱的轻型容器中使 JAX* 规范,而 J2EE
1.4 规范直接将 JAXRPC 和 JAXB 整合到它的总体技术套件中,从而使您可以将 EJB 无状态会话 bean
提供为 WSL 1.1/SOAP 1.1 RPC/encoded Web 服务。(请注意,根据 WS-Interoperability
Basic Profile 规范,RPC/编码的服务正式不支持文档/文字服务;人们普遍期望此差别在 JAX* 和
J2EE 规范的下个版本中得到解决,具体的实现应大概在开发人员实际指出RPC/编码的服务和文档/文字服务之间的差别时推出。)此外,商业应用服务器供应商正竭尽全力确保其产品不仅完全与
J2EE 标准兼容,而且还与 Web 服务标准兼容。显而易见,这种情况下用“兼容且具竞争力”来形容供应商的动机(包括
J2EE 的主要竞争对手,来自西北太平洋的那家不知名的软件公司的动机)再恰当不过。
顺便说的是,打算构建 Web 服务表示 facet 时,值得一提的是,最好使用
JAXB 或 Oracle 的开发人员工具包将系统的模型对象直接提供为 XML 类型,并将整个 Web 服务前端代码生成为大型
WSDL 文档。尽管这起初似乎是某个用户的业务逻辑层的良好验证(毕竟,如果表示层中真的没有什么业务规则,那么采用此方法其实并不困难),但
Web 服务技术套件中的限制很快便使这个期望变得很难实现。
例如,考虑基于引用的对象与 XML 的关系:应如何最佳地表示一个在 XML 中值为空的
java.util.Date 引用?尤其是在 .NET 中,Date 根本不是基于引用的对象,而是“值类型”,这意味着它的作用类似于
int 在 Java 中的作用吗?当尝试表示 XML 对象的复杂循环图时,事情将变得非常棘手,这就是为什么原来反对
RPC/编码的服务的原因之一。这是 WS-* 套件背后所要做的所有工作,但即使某个团队决定“走自己的路”并构建他们自己的
XML-over-HTTP 系统,他们也要面对同一核心问题。正在尝试将对象-XML 映射整合到核心产品(如 Oracle
Toplink)中,但到目前为止,它们仍处于初始阶段。
同时,我们不能忽略那些旨在填补传统的基于浏览器应用程序中的大漏洞以实现“更大的响应性”的新潮表示层方法(“智能”客户端或“富”客户端”)。HTML
尽管有很多优点,但也存在一些根本性的缺点,很容易地就想到了两个:
最小公分母角度。HTML 最初用于尽可能晚地推迟表示决策,标准 HTML 中实际上只有非常少的元素保证在任何给定系统上的呈现外观。为页面生成器提供更大控制(如
CSS)的尝试已经取得了多方面的成功,尤其是在跨不同浏览器方面。
表示代码必须与内容一起发送。由于浏览器本身不了解应用程序,因此必须在每个网络往返中向服务器发送表示代码和内容。此方法有两个负面影响,一个是带宽较低(每个客户端的消耗越高,同一硬件的客户端数越少),另一个是可用性遭到破坏(如果服务器或介入的任何拓扑出现故障,则应用程序将不存在)。
为实现此目的,企业应用程序供应商正积极考虑将表示层代码置于最终用户的机器中,以便完全或部分消除
HTML 的两个主要缺点。这创造了一些有趣的部署暗示,但许多商店正寻求同时创建瘦客户端和富客户端表示层—富客户端用于公司防火墙的内部,而瘦客户端用于公司的外部(再次证明您不能太富或太瘦)。此方法招致了必须处理两个不同框架的麻烦,但至少我们愿意拥有一种将数据从用户输入传递到后端存储库的统一方法,而且最好能够针对“富”客户端和“瘦”客户端将这种传递进行某种形式的标准化
— 由此便产生了 JSR 227,一个通用的数据绑定框架。
“我们愿意拥有一个将数据从用户输入传递到后端存储库的统一方法;因此,便产生了
JSR 227。”
聚合器正如系统可以提供多个“入口点”一样,如果您愿意,系统还可以建立在多个后端的基础上,从而从不同的资源收集数据并按一致和有意义的方式显示它。(既然显示和操作的数据是多个资源/数据库的聚合,因此也就有了术语“聚合器”。)并且,在开始创建此聚合数据的操作和存储用例的
30 秒之后,显而易见的是,必须使用某种类型的原子性以便两个数据库所做的修改保持同步。这正是 Java 事务 API(以及它之前的
X/A 规范)的用途,而事务处理和业务逻辑的交叉部分则是 EJB 产生的原因。
但它不仅仅是事务。多个资源所带来的不仅仅是两个不同的数据库 — 有时,系统需要的可靠性要高于单个数据库机器所能提供的可靠性。毕竟,系统中任何位置的单个机器只表示单个故障点,而且通常情况下(除所有“热交换”故障切换情况以外),我们只需关闭数据库以对其执行某些预定的维护
— 可能包括新的模式更改以满足代码变换。Java 命名和目录接口 (JNDI) 用作所有“查找”操作的单个 API,从实际底层物理数据库机器中提供一个间接层,这意味着如果不缓存
JNDI 查找结果,则管理员可以更改 JNDI 入口,以从一台机器指向不同的机器,同时 J2EE 应用程序将简单地进行相应的调整,从而将创建一个无缝和透明的指向新数据库的“开关”,这在没有间接层的情况下是无法实现的。
集成器
当需要连接两个单独维护的业务逻辑集合时,集成器系统将发挥作用,并且必须开始考虑烟囱系统从不需要的互操作性。例如,如果必须执行传统的请求-响应服务,那么如何执行请求和响应?开发人员通常立刻求助于
WS-* 服务,但如上所述,WS-* 规范有时太多(并且在当前实现中太不成熟),以至于无法可靠地满足集成/互操作性的需要。而
J2EE 规范通过要求每个 EJB 容器符合 CORBA 调用(意味着任何 CORBA 客户端可以与 EJB 容器中封装的业务逻辑交互)再次满足了此需要。
但并非所有集成均以请求-响应的方式进行。为避免 RPC 和请求-响应通信的异步本质中暗藏的瓶颈,许多系统选择使用基于消息的方法相互集成。基于消息的方法是
Java 消息服务规范(以及关联的实现,如 Oracle 的高级队列)以及/或 Java API for XML
Messaging (JAXM) 及其关联的 SOAP API for Attachments in Java
(SAAJ)(用于执行“使用尖括号的消息传递”)的用武之地。
数据库本身还用作集成层,但与传统 RPC 或消息驱动系统并不相同。很多情况下,集成和互操作性仅仅体现在将程序“A”中的数据传递到程序“B”,而数据库(以及其他资源)通常用作不同平台(尤其是
J2EE 和 .NET)的有用(和理解充分)的中介语言。尽管它并不满足所有互操作性的需要,但对于许多系统而言,此方法刚好满足需要
— 它具有自身的好处,尤其是当业务逻辑(通过存储过程)嵌入到数据库中时。此外,.NET 无需了解如何调用驻留在
EJB 服务器中的 Java 代码,Java 也无需了解如何调用驻留在 COM+ ServicedComponent
中的 .NET 代码,或如何在两者之间共享单个分布式事务 ID,等等。尤其是考虑到这样一个事实:Oracle 允许您在
Java 而非 PL/SQL 中编写存储过程,从而简化了存储过程的编写。
企业应用程序 最后,我们了解一下“真正的”企业应用程序,它是以下三个层的多个
facet 的融合:表示层、逻辑层和数据访问层。传统的企业系统需要使用遍布多个应用程序、语言或平台的业务规则集合以各种格式显示多个资源中的数据。企业应用程序最具复杂性,而这正是
J2EE 的强项。此外,由于伴随复杂性而来的是强大的功能(和灵活性),因此表面上“过于复杂的”J2EE 规范及其关联技术变得更为合适。
例如,门户通常就属于此类别,这是因为它们通常需要在所有三个层实现多重性 — 对于表示层,体现在门户通常组合了公司各个部分(或部门,或不同的公司,甚至可能是不同的移动家庭)的不同
web 应用程序,对于业务逻辑层,体现在特定“portlet”有时将需要调用由不同的 portlet 的后端提供的功能,对于数据访问层,体现在大多数
portlet 拥有自身的用于交互的数据库(或数据库集,目的是使事物更有意义),但更有趣的是,给定用户的会话通常需要跟踪进程中的信息,即使用户在各种
portlet 之间来回移动。在许多方面,门户及其关联 portlet 是企业应用程序的典范。
“在许多方面,门户及其关联 portlet 是企业应用程序的典范。” 它将我们至于何处?
此类分类本身就足够出色了,因此会让技术哲人们陶醉好一段时间,但这究竟与构建如今的企业
Java 应用程序有多大关系呢?
首先也是最重要的是,企业 Java 开发人员必须尽快确定他们被要求构建的应用程序属于以上五种应用程序的哪一种。如果是传统的烟囱系统,则选择哪种技术并不像其他四个应用程序那样重要。当出现
Web 服务问题时,将其看作是其他表示层(意味着您现在在查看珠宝应用程序)而不仅仅看作是 Struts 代码与业务逻辑之间使用的模型对象扩展。实际上,在很多方面,模型视图控制器模式是表示层本身的一部分,而并不是延伸到业务逻辑层的什么东西,这是因为执行有效的“不同”表示层通常将要求我们针对如何与后端交互进行不同的选择,如(对于
Web 服务)将系统的“面向对象”的本质抛在后面。
当出现多个数据库或其他后端问题时,请考虑故障可分性和使用分布式事务实现可分性的需要,以及拥有一个良好的间接可热交换层来访问资源的故障切换建议。当现有系统之间的集成成为问题时,请记住除
Web 服务以外还有很多选择(尽管 Web 服务方法比较实用并且通常被看作是标准),并记住消息驱动的系统以及是否可以将业务逻辑置于数据库本身中以便其他需要与该系统交互的平台更容易地访问此数据库。
请记住,J2EE 只是用于实现某个目标的方法,对于任何技术的武断看法通常将失去技术作为总体的意义。例如,不要试图在烟囱系统上使用
EJB,这是因为 EJB 主要适用于事务处理(尤其是两个阶段的提交事务处理,此种事务处理比较占用资源并且必须在作为同一事务一部分的两个或更多资源中获取可分性),但当聚合器应用程序依靠您执行操作时不要忽略它的使用。当
JMS(和消息驱动 bean,当需要事务处理时)的异步本质更适合于此目的时,不要尝试将所有内容编写为会话 bean。等等。
其次,一定要始终确切地牢记应用程序的性能和可伸缩性目标(参见我的《高效企业 Java》一书)。尽管这对于以任何语言编写的任何应用程序通常都很重要,但在企业
Java 领域中更重要,这是因为企业 Java 开发人员有那么多的技术可以选择。您的系统需要为每个用户操作提供亚秒级响应?基于浏览器的应用程序(尤其是跨广域网应用程序)很难实现此目标,这是因为
HTML 浏览器通常需要大约一秒的时间来处理甚至是中等复杂的 HTML 页;或许一个更好的方法是考虑通过 JavaWebStart
提交的“富客户端”前端,以便使跨网络传送的数据数量尽可能得小,以及接收数据的时间尽可能得短(以避免分析表示元素)。
是否需要在整个互联网上拥有预测的 100 万个用户?用户界面肯定需要改变,而
Java 在普通用户的 PC 上的低普及率使 WebStart 并不切合实际,或许 applet 或传统的 HTML
更为合适。但扩展到此用户数目意味着开发人员需要特别留意在高峰负载下每个请求的响应时间,或许以不同的方式构建用户界面可以避免频繁的服务器回程。等等。
第三,请记住,Java 开发人员的工具套件在不断的改进,过去五年中的大部分工作一直在朝
J2EE 领域的方向进行,想方设法使定义 J2EE 组件更简单、更容易。大型商业供应商在该领域的优势超过开源项目,这是因为供应商可以围绕他们的商业服务创建完整的端到端开发经历,其中开放源项目只是浅尝辄止。例如,将
Oracle ADF 中提供的某些新功能与尝试在 Eclipse 中构建 JSF 应用程序进行比较。或者,将在
JDeveloper 中定义 Web 服务与在 Axis 编写 .wsdd 文件进行对比。工具越来越完善,我们只能期望此趋势得以继续,因为这要看供应商有没有兴趣使其继续了。
“工具越来越完善,我们只能期望此趋势得以继续,因为这要看供应商有没有兴趣使其继续了。”
最后但并非不重要的,在本系列的后续文章中留意此技术领域,这些后续文章将介绍从建模和设计到调试以优化/监视代码(这将比您现在定义的性能和可伸缩性目标简单很多)等主题。
最重要的是要放松。生命太短暂了。
结论
尽管企业 Java 领域有时像一组令人眼花缭乱的规范、实现,而实际上似乎迎合短暂流行风格的各种标准和框架已经做好充分的准备并意识到,对于五种类型的应用程序的任何一种而言,任何可用的
Java/J2EE 技术都可以工作(并出色地工作)。
|