`
bluestar
  • 浏览: 376521 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

(转)Ant: 大规模应用中的应用

    博客分类:
  • java
阅读更多

Large Scale 的应用通常意味着:

  1. 目录较多, 层次较深

  2. 依赖较多, 构建脚本依赖的第三方Ant Task, 项目依赖的第三方库等

  3. 测试较多, 构建时间反馈周期较长

  4. 需要在不同操作系统上运行

  5. 需要在不同团队成员的机器上运行

  6. 由于以上原因, 导致Ant脚本较长

1. 目录较多, 层次较深

通常有两种风格的解决方案

  1. 一是使用Ant-Contrib中的<foreach> 来遍历子目录并依次调用其中的构建脚本, 一般是缺省的target

  2. 另外一种是用Ant自身的<subant> 命令来搜索构建脚本并调用特定的target

第一种方案可看作深度优先, 不同的子目录通常是系统的不同组件, 这种方式是把单个组件全部构建完再构建另外的组件

第二种方案可看作广度优先, 类似于模板方法, 要求每个子系统的构建脚本都要定义特定的约定的target, Root构建脚本会先调用所有构建脚本的某个target, 再调用另外的target

当然也可以用<foreach> 来实现第二种风格

2. 依赖较多, 构建脚本依赖的第三方Ant Task, 项目依赖的第三方库等

  1. 明确区分构建脚本的依赖和你的项目的依赖. 那些第三方的Ant Task通常你只会在构建过程中用到它们, 而不会在产品中用到, 如 Checkstyle, Emma 等, 把它们放在单独的目录中, 打包时不要理会它们. 关于区分不同依赖的经验, 参考<<CruiseControl Enterprise 最佳实践 (2) : Keep your dependencies to yourself >>

  2. 使用 ivy 来管理你项目的依赖

  3. 清理不必要的依赖或干扰:

  1. 总是提供 <clean> target, 并借助工具保证在需要的时刻总是能够得到执行, 参见后面的章节

  2. 定义单独的目录来存放项目所有的输出, 通常是顶级目录下的名字叫做 target或者build或者dist之类的目录, 其内部的层次结构应该与源文件的目录结构一致

  3. 构建过程中拷贝需要的资源到上面定义的输出目录中, 而不是直接对资源操作

3. 测试较多, 构建反馈周期较长

一般你不会希望直到构建过程的末尾某个任务才失败, 这样你修正后不得不从头再跑一遍来校验, 有几种方式来来缩短反馈时间

  1. 一种是先运行最可能失败的任务, 利用前面提到的<subant><foreach>

  2. 一种是为每个任务都定义单独的target, 或用"property"来选择或忽略特定的target. 参见 target 的 if/unless 属性, 及 Condition 元素. 如用property来控制运行所有测试还是某个测试:

    <junit ...>

      <!-- ... -->

      <test name="${testcase}" if="testcase" />

      <batchtest todir="${test.data.dir}" unless="testcase" >

          <fileset dir="${test.classes.dir}" includes="**/*Test.class" />

      </batchtest>

    </junit>

另外你希望一次构建能够发现尽可能多的问题, 而不是出现第一个问题后构建就停止, 这样的话可以批量修复它们然后再重新运行一次构建, 而不是一遍一遍的运行构建来逐个找出错误

  1. 可以用一些任务提供的 haltonerror, haltonfailure, errorproperty 等来控制构建结束的时机和最后的结果, 如:

    <junit haltonerror="false" haltonfailure="false" errorProperty="test.failed" failureProperty="test.failed"

 ...>
        <!-- ... -->
    </junit>
    <fail if="test.failed"

>Tests failed.  Check log or reports for details</fail> 

4. 需要在不同操作系统上运行

  1. 利用 <exec > 的 os 或 osfamily 属性来控制不同操作系统上的行为

  2. 路径分隔符统一使用 "/"

5. 需要在不同团队成员的机器上运行, 每个人环境都不一样

其实这是配置管理的问题, 项目的所有文档和依赖, 甚至包括Ant本身都应该包含在一个单根目录下, 并且Check in到版本控制系统中. 里面所有涉及路径的地方都使用相对路径. 这样项目就可以即拷即用

但总有一些对外部环境的依赖, 这是就要借助 Ant 强大而合理的 immutable property 体系

  1. 所有可能变化的地方都使用 property 来引用

  2. 优先使用 JVM 的系统属性, 而不是环境变量

  3. 使用 user.properties 文件定义环境相关的property, 并在构建脚本中最先引入 < property file ="${ user.home} /user.properties" />

  4. 在引入 user.properties 之后, 为所有属性定义合理的缺省值, 以处理 user.properties 不存在不完整的情况

  5. 后面两步也可以用 <propertyfile> 来代替

一个应用就是可以在命令行传入用户名和密码而不是把它们写在脚本中, 这样就避免了安全和隐私问题

其它的例子包括用 property 来定义 test filter, 或者来定义碰到第一次错误是退出还是继续运行构建等

关于目录的处理

  1. 为根目录定义属性, 以此为起点定义子目录的属性

  2. 总是使用 ${basedir} 作为相对路径的前缀. 这样可以保证即使 Ant 的工作路径不同, 只要传递了正确的 basedir 属性, 所有的相对路径还是正确的.

  3. 使用 location 定义路径, 而不是 value. Ant会将 location 展开为绝对路径, 这样即使传递到另外的 Ant Project 中, 它的值也不会变

6. 由于以上原因, 导致Ant脚本较长

Ant不是Script Language, 你更应该像编写产品代码一样认真对待它的编写风格

  1. 前面说过通过命令行参数控制执行的target, 参数多了, 就要有 Usage, Help

    <target name="usage">
        <echo message="  Execute 'ant a' for a."/>
        <echo message="  Execute 'ant b' for b."/>
        <echo message="  Execute 'ant -Dtest.filter=**/*SeleniumTest.class' for specific test cases."/>
        <echo message="  Execute 'ant -Dsome.property=xxx' for xxx."/>
    </target> 
    <target name="help" depends="usage"/> 
  1. 模块化构建脚本, 使用 <macrodef>

  2. 抽取可复用的 macrodef 或 target 到单独的脚本中, 并在其它脚本中 import 这个可复用的文件, 这样有助于分离关注点, 使脚本更易维护

借助第三方工具来弥补Ant的局限

  1. 缺乏异常处理机制, 任何 BuildException 都会终止 Ant 的执行, 而任何 Task 都可能出现异常, 这样有些清理操作就得不到执行. 解决方案:

    a. Ant-Contrib的 <trycatch>

    b. CruiseControl 的 AntPublisher. CruiseControl定义了构建结束后的操作, 参见 <<CruiseControl Enterprise 最佳实践 (1) : Publish with a Publisher >>

  2. 缺乏依赖管理机制

    前面已经提到, 借助 ivy 来管理, ivy 已经成为了 Ant 的子项目

其它一些常用的风格

  1. Define tasks, datatypes, and properties before targets.

  2. Order attributes logically and consistently.

  3. Separate words in target names with a hyphen .

  4. Separate words with a dot (.) character in property names .

  5. Include an "all" target that builds it all.

  6. Define reusable paths.

  7. Use explicit classpaths wherever possible.

  8. Provide visual and XML test results. Use <formatter type="brief" usefile="false"/> , <formatter type="xml"/> and <junitreport>.

  9. 用以连字符(-)开头的target名字来定义无法从命令行调用的"内部"target

其它一些常用的技巧

  1. 与用户交互, 这在持续集成环境中应该不多: <input>

  2. 并发执行: <parallel> , 通常用来执行在后台运行的任务

  3. 递归的property定义. Ant 缺省并不支持 property 的递归展开, 如 ${${os}.${prop}}. 但任何事情都可以用一个额外的中间层解决, 这里可以借用的机制是 <macrodef>

Here is the macro (along lines suggested by Peter Reilly with reference to http://ant.apache.org/faq.html#propertyvalue-as-name-for-property :

<!-- Allows you define a new property with a value of ${${a}.${b}} which can't be done by the Property task alone.  -->
<macrodef name="dymanic-property">
    <attribute name="name"/>
    <attribute name="prop"/>
    <attribute name="os"/>
    <sequential>
        <property name="@{name}" value="${@{os}.@{prop}}"/>
    </sequential>

</macrodef>

这样就可以动态的定义属性

<macro.compose-property name="some.property" prop="${component} os="${targetOS}"/>

<do-something-with property="${some.property}"/>

诡异 的地方

  1. spawn, 不要使用spawn=true, 使用前面的<parallel>

    缺省spawn等于false, 这种情况下Ant退出时会把所有fork的进程都杀掉. 把spawn设置成true可以令进程寿命长于Ant, 从而可以不堵塞Ant的执行而用来运行后台程序. 但会带来很多不好的地方,比如不能即时在console看到信息等. 并且寿命长于 Ant 在某些情况下不是我们期待的, 比如在 CruiseControl 的环境中运行 Ant, 如果Ant fork的进程没有随着Ant退出而退出, 那么CruiseControl会认为Ant进程还没有结束, 从而一直在那里等待而不是执行后面的 Publishers.

    <parallel> 的<daemon>来运行后台程序

  2. unix上的通配符 (Windows上没问题): On Unix-like systems, wildcards are understood by shell intepreters, not by individual binary executables as /usr/bin/ls or shell scripts.

    <target name="list">
        <exec executable="sh">
        <arg value="-c"/>
        <arg value="ls /path/to/some/xml/files/*.xml"/>
        </exec>
    
        </target>
    
  3. 几个没在 jdk 文档中说明的系统属性
    ? -Duser.country=EN -Duser.language=US
    

参考

分享到:
评论

相关推荐

    新建文本文档 (2).txt

    新建文本文档 (2).txt

    Another-Redis-Desktop-Manager.1.5.2.exe

    Another-Redis-Desktop-Manager.1.5.2.exe

    (23149420)STM32F407驱动LCD12864代码 LCD12864带中文字库

    这个程序是用于stm32F407 驱动 12864 LCD使用的,lcd是带有中文字库版本的lcd。 关于这份代码 请参考我的csdn博客 https://jeason.blog.csdn.net/article/details/99691445 有问题您可以在博客下留言,我会尽快回复您的。内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。

    白色大气风格的电影下载网站模板下载.zip

    白色大气风格的电影下载网站模板下载.zip

    VB+ACCESS超市管理系统设计(源代码+系统)(20245h).7z

    1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于计算机科学与技术等相关专业,更为适合;

    VB+ACCESS学生公寓管理系统(源代码+系统)(2024vq).7z

    1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于计算机科学与技术等相关专业,更为适合;

    AI8051U第五节 - GPIO中断源代码

    AI8051U第五节 - GPIO中断源代码

    码上抓小说:Python爬虫搞定顶点小说全攻略

    内容概要: 想要轻松获取顶点小说网站上的最新章节吗?本资源将手把手教你如何用Python编写爬虫,从顶点小说网站抓取你喜爱的小说数据。我们将一起学习如何搭建爬虫环境、发送网络请求、解析网页内容、提取有用信息,并将这些数据保存下来。无论是为了个人娱乐还是数据分析,这个教程都能帮到你。 适用人群: 编程新手:想要通过动手实践来学习Python的小伙伴们。 技术爱好者:对网络爬虫和数据抓取感兴趣的技术发烧友。 书迷朋友们:想要一键获取小说最新章节的阅读爱好者。 学习者和研究者:需要大量文本数据进行分析或学术研究的朋友们。 使用场景及目标: 个人娱乐:在休闲时间,通过编写爬虫来获取自己喜欢的小说,享受编程带来的乐趣。 数据收集:为数据分析、内容创作或学术研究自动收集顶点小说网站上的文本数据。 技术提升:通过实际项目提升自己的Python编程技能,特别是在网络爬虫领域。 教育学习:作为教学材料,帮助学生理解网络爬虫的工作原理和应用场景。 其他说明: 本教程适合所有对Python爬虫感兴趣的朋友,即使你是编程小白也不用担心,我们会从零开始,一步步带你入门。

    白色扁平风格的原创素材类企业网站源码下载.zip

    白色扁平风格的原创素材类企业网站源码下载.zip

    白色扁平化风格的滑雪运动体育项目模板.zip

    白色扁平化风格的滑雪运动体育项目模板.zip

    白色创意风格的房地产建筑整站网站源码下载.zip

    白色创意风格的房地产建筑整站网站源码下载.zip

    白色大气风格响应式个人主页博客网站模板.zip

    白色大气风格响应式个人主页博客网站模板.zip

    多元统计分析重点.docx

    多元统计分析重点.docx

    白色大气风格的汽车4s店模板下载.zip

    白色大气风格的汽车4s店模板下载.zip

    白色扁平化的牛排汉堡西餐厅企业网站模板.zip

    白色扁平化的牛排汉堡西餐厅企业网站模板.zip

    圣诞树html展示代码资料.zip

    圣诞树html圣诞树html展示代码资料.zip

    sealos离线安装k8s集群镜像-part1

    sealos离线安装k8s集群镜像-part1 包含镜像列表如下: sealos离线安装包:sealos_5.0.0_linux_arm64.tar.gz 网络通信组建件cni: cni-plugins-linux-arm64-v0.8.7.tgz 监控数据的聚合器组件: metrics-server.tar IP地址管理和网络隔离组件: flannel.tar CNI 通信组件:cilium.tar k8s打包部署组件:helm.tar

    (33587448)Java版 愤怒的小鸟开源游戏

    内容来源于网络分享,如有侵权请联系我删除。另外如果没有积分的同学需要下载,请私信我。

    白色简洁风格的博客论坛后台系统源码下载.zip

    白色简洁风格的博客论坛后台系统源码下载.zip

    HTML与CSS实现简单圣诞树网页

    内容概要:本文介绍了使用 HTML 和 CSS 创建一个简单的圣诞树网页的方法。文章提供了一段示例代码,利用定位、边框技巧构建了树的基本结构,并通过背景色、边框色等设置了节日气氛。通过嵌套元素和定位来布置装饰物,如星星和红色小球。 适用人群:适用于对 HTML 与 CSS 基础有所了解的初学者。 使用场景及目标:旨在为网站设计师或前端开发人员提供节日氛围的设计灵感,帮助其学会使用 HTML 和 CSS 进行基础图形和布局设计。 其他说明:示例代码可以作为起点,在实际应用中可以通过增加 CSS 动画、交互功能等方式来丰富和完善设计。此外,也鼓励开发者尝试不同的样式和技术,比如 Flexbox 或 Grid 布局,提高页面的适应性和美观度。

Global site tag (gtag.js) - Google Analytics