BlogJava-破门点滴(Java技术版)-文章分类-开源项目http://www.blogjava.net/brokendoor/category/5347.html破门点滴(Java技术版)zh-cnWed, 28 Feb 2007 08:19:24 GMTWed, 28 Feb 2007 08:19:24 GMT60是否能让JAVA 和 .NET框架共存(转)http://www.blogjava.net/brokendoor/articles/37602.html破门破门Mon, 27 Mar 2006 06:38:00 GMThttp://www.blogjava.net/brokendoor/articles/37602.htmlhttp://www.blogjava.net/brokendoor/comments/37602.htmlhttp://www.blogjava.net/brokendoor/articles/37602.html#Feedback0http://www.blogjava.net/brokendoor/comments/commentRss/37602.htmlhttp://www.blogjava.net/brokendoor/services/trackbacks/37602.html

原创作者:Ashish Banerjee

翻译整理:51DOTNET CLUB(WWW.51DOTNET.COM)SLASH

目的:对JAVA与.NET框架共存的可能性做一个评估

目标受众:JAVA程序员和系统工程师

  

提要:

       首先是对JAVA 和 .NET平台的构成做一个分析,然后是我个人对JAVA如何形成的一个认识,接着是分析微软和SUN之间的合作与分歧,最后是JAVA与.NET合作的前景。

     
我个人强烈认为JAVA与.NET将在不久的未来逐步的统一起来。已经有很多关于整合JAVA和.NET的项目计划被提交到源码开放组织。在微软的MSDN,SUN 的JAVA站点,以及来自于ECMA 和 W3C.org的标准文档都可以看到有关内容。

  

简介

     JAVA与.NET继续发展下去,可能的两种结果:其中的一种退出竞争或是两种共存,而共存的可能性更大。JAVA得以生存的原因在于它的时间优势:它已经发展了六年;它在大多数的操作系统上可以运行;它得到了业界领导者如ORACLE、IBM的支持;并且使用JAVA进行开发的项目计划几乎覆盖所有的应用程序领域。


     而.NET的优势在于微软拥有90%的桌面操作系统市场,同时微软也开始采用SUN的市场战略,即将其特有的技术标准化。如:在远程通信上它向IETF(InternetEngineering Task Force)和W3C(World Wide Web Consortium)提交了SOAP(SIMPLE OBJECT ACCESS PROTOCLE)(类似于RFC-REQUEST FORCOMMENT);向ECMA (European Computer Manufacturer's Association)提交了C#语言和通用运行时(COMMON RUNTIME)基础结构的标准。

  

JAVA平台的构架

      JAVA平台包括JAVA语言,以及一套虚拟机——如JVM、KVM、CVM等——通过它们实现在PC机,手提电脑或是嵌入式系统上运行JAVA的字节码。同时,JAVA平台还定义了一整套覆盖面很广的API,它们被用来与微软的API协调或是相互竞争。如JDBC对ODBC,JTAPI对TAPI,JDO对ADO等等。因此,简要来说,JAVA平台包括语言,虚拟机,以及API库。


      由于使用虚拟机机制,所以JAVA语言在所有的平台上只有唯一的版本,因此它使用RMI(远程方法调用Remote Method Invocation)协议进行远程通信;微软则在.NET框架中使用DCOM——正在逐步演变为SOAP(简单对象访问协议)。


      SUN最初对JAVA的宣传是“一次性代码编写,所有环境下运行”,但在推出了“J2EE” (Java 2 Enterprise Edition)和“J2ME” (Java 2 Micro Edition)后不得不收回了它最初的宣传,因为“一种尺码的鞋适合所有的脚”的解决方案并不能很好的工作。

   

.NET平台的构架

  

     .NET框架包括C++, VB.NET (VB 7.x) 和 C# 等一系列语言;与JAVA虚拟机类似的一套运行时环境;以及一套倾向与WINDOWS体系的API接口。其中的运行时环境可能存在于一个浏览器、或是一个WEB SERVER、或是在操作系统中。将来也许在SQL SERVER中也可能存在这样的运行时环境。另外需要提及的是微软的SOAP协议,它在继承了DCOM的一些特性的基础上发展起来,基于XML格式通过HTTP进行传输。SOAP的JAVA版本,可以在http://xml.apache.org上看到它的有关文档。

  

发展历程

  

JAVA最初来源于SUN的一套为机顶盒设计的语言,当时的名字是OAK,SUN将之更名,并将它放在INTERNET上作为开放源码共享。随着专门为网页设计的JAVA APPLET的出现,JAVA语言迅速在INTERNET上流行起来。当时的浏览器主要是NETSCAPE。当微软发现明天市场的主宰可能是浏览器而不是桌面系统时,开始着手对NETSCAPE进行收购,在收购计划失败后微软发展了自己的浏览器IE。



当时的INTERNET需要一种语言,而JAVA适时的出现了,由于它与C++的许多相似的语法,使得很多程序员转向了JAVA。而它确实具有很多优势,以至于在98年秋,它的反对者微软在MSDN中都宣称,JAVA是编写COM组件的最佳语言。


随着JAVA一起出现的还有LINUX操作系统和APACHE服务器。这三者的联合在服务器端的应用表现出强大的威力,以至WINDOWS NT在企业级服务器市场受到了很大的冲击。


98年出现的DHTML和JAVASCRIPT导致了JAVA APPLET在网页设计领域的淡出,在这里有两方面因素:一、大部分APPLET效果现在都可以由DHTML完成;二、而DHTML对带宽的要求更低。但是JAVA因为在服务器端的应用仍有市场,而得以继续发展。这是开发源码的支持者为JAVA添加了活力,首先是APACHE提出的SERVERLET 和 稍后出现的JSP,这些在.com网站的程序开发中占据了一席之地。


JAVA平台首先以SERVERLET,然后是JSP,最后是EJB(Enterprise Java Beans),逐步向企业级应用拓展。EJB是一个面向对象的事务进程系统,有些类似于微软的MTS(Microsoft Transaction Server)。事实上MTS和EJB都不是很成功,因为它们都无法达到INTERNET应用的规模。


     就我的观点来看,JAVA最失败的时刻是,SUN通过法律手段向微软索赔$2000万,并获得成功的时候。微软从那时开始制订自己的.NET计划,同时也宣布了JAVA作为独一无二的INTERNET 平台的地位的结束。

  

展望


现在,我们能看到到还只是一个很混乱的局面。而在未来,我们将看到.NET的成熟,以及它和JAVA的融合。


JAVA将继续保持它的特点:跨平台的服务器端应用,如WAP服务器,或者是电信领域的如JAIN(Java API for Intelligent Networks,同时它在嵌入式系统中将继续保持它的优势,象智能卡、移动电话、PDA等。而我们还将看到.NET的成熟,当然这种成熟需要时间,可能是相当长的一段时间,就好象当年JAVA成长那样。


ORACLE 8i 及其更老一些的版本,充当着一个JAVA 运行时的载体的角色,这使得JAVA 得以与ORACLE 数据库引擎紧密结合;同样,.NET体系也会与新版本的SQL SERVER,紧密的结合,这将包括一个VES (虚拟执行系统)执行引擎。这将使程序开发人员可以在SQL 语句和存储过程中嵌入C#和VB.NET 的成分。目前,你可以通过调用DLL函数来使用扩展存储过程,但数据库本身并没有一个面向对象的运行时引擎与之相匹配。

  

未来的标志.NET 成熟的里程碑

   

非微软产品,包括服务器,桌面或是便携式设备的操作系统如Solaris, Linux和Palm OS的.NET接口。与JAVA核心的整合。比如说,针对CLI(Common Language Infrastructure)的JAVA编译器,针对JAVA虚拟机的C#编译器。SQL SERVER 或是 ORACLE 等数据库产品中整合的VES 引擎。由中立的第三方开发的开放源码的,完善的.NET平台。


可以预见到,微软将会赞助一些开放源码的项目,以使.NET 向UNIX 平台扩展,而这将有助于一些开放源码组织减少它们对JAVA的偏爱。

  

JAVA的命运

  

     JAVA的一个主要目标是通信设备提供商,如NOKIA就在它的WAP SERVER 应用了JAVA。类似于70年代和80年代初,PC销售时硬件供应商将最终的应用程序绑定在操作系统中一起销售,JAVA现在也被绑定于通信设备中被销售。

     
它的另一个主要方向是JAIN(Java API for Advanced Intelligent Network),它主要是定义一套与协议(如CDMA,GSM,IMT2000)无关的API,以便于基于开放市场的组件开发。这使得ISV(独立软件供应商)可以以插件的形式提供通信服务,如可自动转接至最近的可拨通的国际呼叫中心的800免费电话。当然,JAIN也遇到了对手,想微软和不列颠通信提出的Parlay计划——它也被业界所支持。

    
另外,JAVA在嵌入式设备中也保持着领先的地位,如smart 3G 和 GPRS,在这里的移动电话系统采用的是J2ME(Java 2 Micro Edition),但是如果它不能很好的解决一些固有的问题,如载入时的延迟等,也许,很快,它就将被C#代替,如果.NET 能提供快速的运行环境,和广泛的业界支持。

  

.NET和JAVA的整合

   

无论从商业角度,还是开发者角度,甚至是源码开放组织的角度,.NET和JAVA的整合都显得很有必要,下面就二者的整合做出一个提前的估计(所有的相关项目被分为A、B、C三个组,以便于看清它们之间的关系,当然这些项目也完全可以被独立的操作):

JVM to CIL compiler (Group A)

Java API bridge for .NET API and lib. (Group A)

Java compiler for CLI (Group A)

CLI ports for Palm OS, Linux and Solaris (Group B)

.NET API and lib. bridge for Palm OS API (Group B)

.NET API and lib. bridge for POSIX (Group B)

CIL compiler to JVM (Group C)

.NET API and lib. bridge for Java API (Group C)

C# compiler for JVM (Group C)

    

A组的项目


    该组项目的主要目的是使现有的JAVA二进制代码能够在.NET平台上被执行。这意味着JAVA的二进制码(后缀为class 的文件)不用再从源代码进行重编译就能运行于.NET 平台了。当然这些class 文件在安装或执行时会被编译,就好象微软的运行时和JIT对微软中间语言所做的那样。

JVM to CIL compiler

     一个编译器,输入JAVA字节码,输出MSIL代码——它将被编译为可执行文件(如EXE,DLL,MSI等)

  

Java API bridge for .NET API and lib

     
在这里,JAVA API 与每一个相应 .NET API之间将建立一个映射,比如Java API中的java.io.File将被映射到 .NET的System.IO.File 类。相对于比较简单的IO类的映射,还有一些映射比较复杂,比如java.net包到.NET 的SYSTEM.NET的映射。这里存在的一个问题是:该项工作如果在C#中进行开发会比较方便。而假如在JAVA中实现,则需要有一个直接指向CLI(Common Language Interface)的编译器,它能生成符合CLS(Common Language Specification)标准的CIL(Common Intermediate Language)代码。

    
可以通过编写一个向导式的工具来避免一些烦琐的工作,例如,可以利用C# 或JAVA来编写一个基于XML格式的对象描述,用它生成一个框架代码,然后根据需要向其中手写添加其他代码。如果你确实打算进行这样的操作,在http://xml.apache.org站点你可以找到很多有用的资料。微软的过时的JAVA SDK中也有类似的工具可供参考——一个用来生成Jdirect(JDirect was the Microsoft's hack for implementing native interfaces)代码的工具,利用它可以实现访问本地WIN32 API。SDK中有该工具的源代码。顺便提一句,由于这里涉及到微软的一套独特的JAVA扩展标记,因此SUN和微软一直就此问题打着官司。

  

Java compiler for CLI

     它将JAVA源代码(使用.NET 框架API)编译为可执行文件的格式,如EXE,DLL等,这个工作是在最高的层面上对JAVA和.NET框架进行整合。这将为今后直接利用JAVA在.NET框架下创建应用打好基础。

     
对现有JAVA编译器的代码生成部分重写,将是此项工作一个比较便捷的解决方案。就我个人的意见,SUN会根据开放源代码的标准,开发这样的一套编译器。当然,这样的一些改造计划需要对一些JAVA类进行调整。

  

B组的项目

该组的项目将主要致力于为其他的平台如PALM OS、SOLARIS以及LINUX平台开发.NET 框架的端口。这些端口应该用C 来编写以适应速度和控制上的需要,另外采用       C 来开发还可以保留进行操作系统相关的系统级编程。


CLI ports for Palm OS, Linux and Solaris.

这部分内容事实上分为两个独立的部分:一、针对PALM OS;二、针对UNIX 系统。


对于PALM OS 来说,解决方案比较简单,开发可以在PC 环境下进行,然后利用数据线或是蓝牙传输到PALM 设备上。与之相关的.NET 框架针对PALM OS 设计的 API 将在下个部分详述。

    UNIX部分将利用JAVA开发,最后将PE(Portable Executeable)文件编译为COFF(Common Object File Format)格式,一种UNIX 可执行文件的格式。编译将在安装或是载入时进行。

  

.NET API and lib. bridge for Palm OS API.

这个.NET API bridge 应该以一种优化的方式被映射到PALM OS API上。连接器和装载设备的映射表驻留在PC 的网关上。通过数据线或蓝牙传输PALM OS 的可执行代码。它的实现将依赖于PALM OS 的驻留虚拟机 KVM(the Java 2 Micro edition)运行时,同时它还应该避免KVM设计中JAVA运行程序载入过慢的缺陷。另外这一套API 与 为WINDWOS CE 的 设计的不同,它不应舍弃那些资源占用较大的API 象System.Xml。.NET依赖于SOAP进行远程的方法调用。SOAP 基于 XML格式,因此它需要System.Xml的支持。如果没有,基于SOAP的分布式应用将无法工作。通过调用System.Xml API 的方法可以实现对PDA诸如WINDOWS CE 和 PALM OS上的应用程序或是一些服务器端的应用的远程操作。甚至可以在SOAP的基础上利用为WAP (Wireless Access Protocol)设计的WBXML (Wap Binary XML)标准与WAP 网关进行通信。

  

.NET API and lib. bridge for POSIX.

     这部分将对.NET API 和UNIX API进行映射,大量的 C 的编程工作将是一个困难,但更大的困难将来自于GUI 元素的处理上。这些UNIX平台会有很多GUI框架,比较安全的做法是给它们提供一个WIN32 API 的端口作为媒介。如果能以前文所述的MICROSOFT JAVA SDK的方法来进行映射的操作,那么将节省大量的编程工作。

  

C组的项目

  

该部分的内容致力于将.NET 框架应用于JAVA上。这将是一项艰苦的工作。当然,假如微软向ECMA提交一份标准规范,这项工作将变的比较实际一些。

  

CIL compiler to JVM

该项目将把.NET执行程序(PE)转换为.class格式的文件。但如果执行程序中有一些非受管代码,JVM将不接受它们。该项目的实现依赖于下面将要描述的.NET API bridge for Java 的实现。

  

.NET API and lib. bridge for Java API.

  

一个完全兼容的.NET API bridge几乎是不可能的,它需要依赖于微软向ECMA提交的标准中的一些参数。这项工作将由JAVA来实现,但与前文提到的Java API to .NET bridge一样,将有很多烦琐的工作。

  

C# compiler for JVM

   这项工作可以用JAVA或是C# 的任意一种来完成。比较容易实现的是利用JAVA,因为有SUN的JAVA编译器的许多代码可以被再利用。但我建议用C# 来实现该项工作,在.NET 框架中有许多基础的编译器可被利用。此项目依赖于.NET API bridge for Java的实现。

  

总结

    最后我要说的是将.net 与JAVA 整合不仅仅是微软与SUN的工作。所有的程序员也许都应对它进行关注。



破门 2006-03-27 14:38 发表评论
]]>
ANT十五大最佳实践http://www.blogjava.net/brokendoor/articles/24228.html破门破门Fri, 16 Dec 2005 07:48:00 GMThttp://www.blogjava.net/brokendoor/articles/24228.htmlhttp://www.blogjava.net/brokendoor/comments/24228.htmlhttp://www.blogjava.net/brokendoor/articles/24228.html#Feedback0http://www.blogjava.net/brokendoor/comments/commentRss/24228.htmlhttp://www.blogjava.net/brokendoor/services/trackbacks/24228.html

ANT十五大最佳实践

作者:Eric M. Burke, coauthor of Java Extreme Programming Cookbook

原文:http://www.onjava.com/pub/a/onjava/2003/12/17/ant_bestpractices.html

译者:徐彤MSN:xt121@hotmail.com

在Ant出现之前,构建和部署Java应用需要使用包括特定平台的脚本、Make文件、各种版本的IDE甚至手工操作的“大杂烩”。现在,几乎所有的开源Java项目都在使用Ant,大多数公司的内部项目也在使用Ant。Ant在这些项目中的广泛使用自然导致了读者对一整套Ant最佳实践的迫切需求。

本文总结了我喜爱的Ant技巧或最佳实践,多数是从我亲身经历的项目错误或我听说的其他人经历的 “恐怖”故事中得到灵感的。比如,有人告诉我有个项目把XDoclet 生成的代码放入带有锁定文件功能的版本控制工具中。当开发者修改源代码时,他必须记住手工检出(Check out)并锁定所有将要重新生成的文件。然后,手工运行代码生成器,只到这时他才能够让Ant编译代码,这一方法还存在如下一些问题:

  • 生成的代码无法存储在版本控制系统中。
  • Ant(本案例中是Xdoclet)应该自动确定下一次构建涉及的源文件,而不应由程序员手工确定。
  • Ant的构建文件应该定义好正确的任务依赖关系,这样程序员就不必为了完成构建而不得不按照特定顺序调用任务。

当我开始一个新项目时,我首先编写Ant构建文件。Ant文件明确地定义构建的过程,并被团队中的每个程序员使用。本文所列的技巧基于这样的假定:Ant构建文件是一个必须仔细编写的重要文件,它应在版本控制系统中得到维护,并被定期进行重构。下面是我的十五大Ant最佳实践。

1. 采用一致的编码规范

Ant用户有的喜欢有的痛恨其构建文件的XML语法。与其跳进这一令人迷惑的争论中,不如让我们先看一些能保持XML构建文件简洁的方法。

首先也是最重要的,花费时间格式化你的XML让它看上去很清晰。不论XML是否美观,Ant都可以工作。但是丑陋的XML很难令人读懂。倘若你在任务之间留出空行,有规则的缩进,每行文字不超过90列左右,那么XML令人惊讶地易读。再加上使用能够高亮XML语法的优秀编辑器或IDE工具,你就不会有阅读的麻烦。

同样,精选含意明确、容易读懂的词汇来命名任务和属性。比如,dir.reports就比rpts特定的编码规范并不重要,只要拿出一套规范并坚持使用就行。

2. 将build.xml放在项目根目录中

Ant构建文件build.xml可以放在任何位置,但是放在项目顶级目录中可以保持项目简洁。这是最常用的规范,开发者能够在顶级目录中找到预期的build.xml。把构建文件放在根目录中,也能够使人容易了解项目目录树中不同目录之间的逻辑关系。以下是一个典型的项目目录层次:

[root dir]
  | build.xml 
  +--src 
  +--lib (包含第三方 JAR包) 
  +--build (由 build任务生成) 
  +--dist (由 build任务生成)

build.xml在顶级目录时,假设你处于项目某个子目录中,只要输入:ant -find compile 命令,不需要改变工作目录就能够以命令行方式编译代码。参数-find告诉Ant寻找存在于上级目录中的build.xml并执行。

3. 使用单一的构建文件

有人喜欢将一个大项目分解成几个小的构建文件,每个构建文件分担整个构建过程的一小部分工作。这确实是看法不同的问题,但是应该认识到,将构建文件分割会增加对整体构建过程的理解难度。要注意在单一构建文件能够清楚表现构建层次的情况下不要过工程化(over-engineer)。

即使你把项目划分为多个构建文件,也应使程序员能够在项目根目录下找到核心build.xml。尽管该文件只是将实际构建工作委派给下级构建文件,也应保证该文件可用。

4. 提供良好的帮助说明

应尽量使构建文件自文档化。增加任务描述是最简单的方法。当你输入ant -projecthelp时,你就可以看到带有描述的任务清单。比如,你可以这样定义任务:

<target name="compile"  
   description="Compiles code, output goes to the build dir.">

最简单的规则是把所有你想让程序员通过命令行就可以调用的任务都加上描述。对于一般用来执行中间处理过程的内部任务,比如生成代码或建立输出目录等,就无法使用描述属性。

这时,可以通过在构建文件中加入XML注释来处理。或者专门定义一个help任务,当程序员输入ant help时来显示详细的使用说明。

<target name="help" description="Display detailed usage information">
  <echo>Detailed help...</echo></target>

5. 提供清除任务

每个构建文件都应包含一个清除任务,用来删除所有生成的文件和目录,使系统回到构建文件执行前的初始状态。执行清空任务后还存在的文件都应处在版本控制系统的管理之下。比如:

<target name="clean"
    description="Destroys all generated files and dirs.">
  <delete dir="${dir.build}"/>
  <delete dir="${dir.dist}"/>
</target>

除非是在产生整个系统版本的特殊任务中,否则不要自动调用clean任务。当程序员仅仅执行编译任务或其他任务时,他们不需要构建文件事先执行既令人讨厌又没有必要的清空任务。要相信程序员能够确定何时需要清空所有文件。

6. 使用ANT管理任务从属关系

假设你的应用由Swing GUI组件、Web界面、EJB层和公共应用代码组成。在大型系统中,你需要清晰地定义每个Java包属于系统的哪一层。否则任何一点修改都要被迫重新编译成百上千个文件。糟糕的任务从属关系管理会导致过度复杂而脆弱的系统。改变GUI面板的设计不应造成Servlet和EJB的重编译。

当系统变得庞大后,稍不注意就可能将依赖于客户端的代码引入到服务端。这是因为典型的IDE项目文件编译任何文件都使用单一的classpath。而Ant能让你更有效地控制构建活动。

设计你的Ant构建文件编译大型项目的步骤:首先,编译公共应用代码,将编译结果打成JAR包文件。然后,编译上一层的项目代码,编译时依靠第一步产生的JAR文件。不断重复这一过程,直到最高层的代码编译完成。

分步构建强化了任务从属关系管理。如果你工作在底层Java框架上,偶然引用到高层的GUI模板组件,这时代码不需要编译。这是由于构建文件在编译底层框架时在源路径中没有包含高层GUI面板组件的代码。

7. 定义并重用文件路径

如果文件路径在一个地方一次性集中定义,并在整个构建文件中得到重用,那么构建文件更易于理解。以下是这样做的一个例子:

<project name="sample" default="compile" basedir=".">
  <path id="classpath.common">
    <pathelement location="${jdom.jar.withpath}"/>
    ...etc  </path>
  <path id="classpath.client">
    <pathelement location="${guistuff.jar.withpath}"/>
    <pathelement location="${another.jar.withpath}"/>
    <!-- reuse the common classpath -->
    <path refid="classpath.common"/>
  </path>
  <target name="compile.common" depends="prepare">
    <javac destdir="${dir.build}" srcdir="${dir.src}">
          <classpath refid="classpath.common"/>
          <include name="com/oreilly/common/**"/>
    </javac>
  </target>
</project>

当项目不断增长构建日益复杂时,这一技术越发体现出其价值。你可能需要为编译不同层次的应用定义各自的文件路径,比如运行单元测试的、运行应用程序的、运行Xdoclet的、生成JavaDocs的等等不同路径。这种组件化路径定义的方法比为每个任务单独定义路径要优越得多。否则,很容易丢失任务从属关系的轨迹。

8. 定义恰当的任务从属关系

假设dist任务从属于jar任务,那么哪个任务从属于compile任务哪个任务从属于prepare任务呢?Ant构建文件最终定义了任务的从属关系图,它必须被仔细地定义和维护。

应该定期检查任务的从属关系以保证构建工作得到正确执行。大的构建文件随着时间推移趋向于增加更多的任务,所以到最后可能由于不必要的从属关系导致构建工作非常困难。比如,你可能发现在程序员只需编译一些没有使用EJB的GUI代码时又重新生成了EJB代码。

以“优化”的名义忽略任务的从属关系是另一种常见的错误。这种错误迫使程序员为了得到恰当的结果必须记住并按照特定的顺序调用一串任务。更好的做法是:提供描述清晰的公共任务,这些任务包含正确的任务从属关系;另外提供一套“专家”任务让你能够手工执行个别的构建步骤,这些任务不提供完整的构建过程,但是让那些专家用户在快速而恼人的编码期间能够跳过某些步骤。

9.使用属性

任何需要配置或可能发生变化的信息都应作为Ant属性定义下来。对于在构建文件中多次出现的值也同样处理。属性既可以在构建文件头部定义,也可以为了更好的灵活性而在单独的属性文件中定义。以下是在构建文件中定义属性的样式:

<project name="sample" default="compile" basedir=".">
  <property name="dir.build" value="build"/>
  <property name="dir.src" value="src"/>
  <property name="jdom.home" value="../java-tools/jdom-b8"/>
  <property name="jdom.jar" value="jdom.jar"/>
  <property name="jdom.jar.withpath"
                    value="${jdom.home}/build/${jdom.jar}"/>
    etc...
</project>

或者你可以使用属性文件:

<project name="sample" default="compile" basedir=".">
  <property file="sample.properties"/>
   etc...
</project>

在属性文件 sample.properties中:

dir.build=build
dir.src=src
jdom.home=../java-tools/jdom-b8
jdom.jar=jdom.jarjdom.jar.withpath=${jdom.home}/build/${jdom.jar}

用一个独立的文件定义属性是有好处的,它可以清晰地定义构建中的可配置部分。另外,在开发者工作在不同操作系统的情况下,你可以在不同的平台上提供该文件的不同版本。

10. 保持构建过程独立

为了最大限度的扩展性,不要应用外部路径和库文件。最重要的是不要依赖于程序员的CLASSPATH设置。取而代之的是,在构建文件中使用相对路径并定义自己的路径。如果你引用了绝对路径如C:\java\tools,其他开发者未必使用与你相同的目录结构,所以就无法使用你的构建文件。

如果你部署开放源码项目,应该提供包含编译代码所需的所有JAR文件的发行版本。当然,这是在遵守许可协议的基础上。对于内部项目,相关的JAR文件都应在版本控制系统的管理中,并捡出(check out)到大家都知道的位置。

当你必须引用外部路径时,应将路径定义为属性。使程序员能够用适合他们自己的机器环境的参数重载这些属性。你也可以使用以下语法引用环境变量:

<property environment="env"/>
<property name="dir.jboss" value="${env.JBOSS_HOME}"/>

11. 使用版本控制系统

构建文件是一个重要的制品,应该像代码一样进行版本控制。当你标记你的代码时,也应用同样的标签标记构建文件。这样当你需要回溯到旧版本并进行构建时,能够使用相应版本的构建文件。

除构建文件之外,你还应在版本控制中维护第三方JAR文件。同样,这使你能够重新构建旧版本的软件。这也能够更容易保证所有开发者拥有一致的JAR文件,因为他们都是同构建文件一起从版本控制系统中捡出的。

通常应避免在版本控制系统中存放构建成果。倘若你的源代码很好地得到了版本控制,那么通过构建过程你能够重新生成任何版本的产品。

12. 把Ant作为“最小公分母”

假设你的开发团队使用IDE工具,当程序员通过点击图标就能够构建整个应用时为什么还要为Ant而烦恼呢?

IDE的问题是一个关于团队一致性和重现性的问题。几乎所有的IDE设计初衷都是为了提高程序员的个人生产率,而不是开发团队的持续构建。典型的IDE要求每个程序员定义自己的项目文件。程序员可能拥有不同的目录结构,可能使用不同版本的库文件,还可能工作在不同的平台上。这将导致出现这种情况:在Bob那里运行良好的代码,到Sally那里就无法运行。

不管你的开发团队使用何种IDE,一定要建立所有程序员都能够使用的Ant构建文件。要建立一个程序员在将新代码提交版本控制系统前必须执行Ant构建文件的规则。这将确保代码是经过同一个Ant构建文件构建的。当出现问题时,要使用项目标准的Ant构建文件,而不是通过某个IDE来执行一个干净的构建。

程序员可以自由选择任何他们习惯使用的IDE工具或编辑器。但是Ant应作为公共基线以保证代码永远是可构建的。

13. 使用zipfileset属性

人们经常使用Ant产生WAR、JAR、ZIP和 EAR文件。这些文件通常都要求有一个特定的内部目录结构,但其往往与你的源代码和编译环境的目录结构不匹配。

一个最常用的方法是写一个Ant任务,按照期望的目录结构把一大堆文件拷贝到临时目录中,然后生成压缩文件。这不是最有效的方法。使用zipfileset属性是更好的解决方案。它让你从任何位置选择文件,然后把它们按照不同目录结构放进压缩文件中。以下是一个例子:

<ear earfile="${dir.dist.server}/payroll.ear"
    appxml="${dir.resources}/application.xml">
  <fileset dir="${dir.build}" includes="commonServer.jar"/>
  <fileset dir="${dir.build}">
    <include name="payroll-ejb.jar"/>
  </fileset>
  <zipfileset dir="${dir.build}" prefix="lib">
    <include name="hr.jar"/>
    <include name="billing.jar"/>
  </zipfileset>
  <fileset dir=".">
    <include name="lib/jdom.jar"/>
    <include name="lib/log4j.jar"/>
    <include name="lib/ojdbc14.jar"/>
  </fileset>
  <zipfileset dir="${dir.generated.src}" prefix="META-INF">
    <include name="jboss-app.xml"/>
  </zipfileset>
</ear>

在这个例子中,所有JAR文件都放在EAR文件包的lib目录中。hr.jar和billing.jar是从构建目录拷贝过来的。因此我们使用zipfileset属性把它们移动到EAR文件包内部的lib目录。prefix属性指定了其在EAR文件中的目标路径。

14. 测试Clean任务

假设你的构建文件中有clean和compile的任务,执行以下的测试。第一步,执行ant clean;第二步,执行ant compile;第三步,再执行ant compile。第三步应该不作任何事情。如果文件再次被编译,说明你的构建文件有问题。

构建文件应该只在与输出文件相关联的输入文件发生变化时执行任务。一个构建文件在不必执行诸如编译、拷贝或其他工作任务的时候执行这些任务是低效的。当项目规模增长时,即使是小的低效工作也会成为大的问题。

15. 避免特定平台的Ant封装

不管什么原因,有人喜欢用简单的、名称叫做compile之类的批文件或脚本装载他们的产品。当你去看脚本的内容你会发现以下内容:

ant compile

其实开发人员都很熟悉Ant,并且完全能够自己键入ant compile。请不要仅仅为了调用Ant而使用特定平台的脚本。这只会使其他人在首次使用你的脚本时增加学习和理解的烦扰。除此之外,你不可能提供适用于每个操作系统的脚本,这是真正烦扰其他用户的地方。

总结

太多的公司依靠手工方法和特别程序来编译代码和生成软件发布版本。那些不使用Ant或类似工具定义构建过程的开发团队,花费了太多的时间来捕捉代码编译过程中出现的问题:在某些开发者那里编译成功的代码,到另一些开发者那里却失败了。

生成并维护构建脚本不是一项富有魅力的工作,但却是一项必需的工作。一个好的Ant构建文件将使你能够集中到更喜欢的工作——写代码中去!

参考



破门 2005-12-16 15:48 发表评论
]]>