<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 56, comments - 77, trackbacks - 0, articles - 1
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    Ant: 大規(guī)模應用中的應用

    Posted on 2008-01-12 22:03 切爾斯基 閱讀(4065) 評論(0)  編輯  收藏

    Large Scale 的應用通常意味著:

    1. 目錄較多, 層次較深

    2. 依賴較多, 構建腳本依賴的第三方Ant Task, 項目依賴的第三方庫等

    3. 測試較多, 構建時間反饋周期較長

    4. 需要在不同操作系統(tǒng)上運行

    5. 需要在不同團隊成員的機器上運行

    6. 由于以上原因, 導致Ant腳本較長

     

    1. 目錄較多, 層次較深

    通常有兩種風格的解決方案

    1. 一是使用Ant-Contrib中的<foreach>來遍歷子目錄并依次調用其中的構建腳本, 一般是缺省的target

    2. 另外一種是用Ant自身的<subant>命令來搜索構建腳本并調用特定的target

    第一種方案可看作深度優(yōu)先, 不同的子目錄通常是系統(tǒng)的不同組件, 這種方式是把單個組件全部構建完再構建另外的組件

    第二種方案可看作廣度優(yōu)先, 類似于模板方法, 要求每個子系統(tǒng)的構建腳本都要定義特定的約定的target, Root構建腳本會先調用所有構建腳本的某個target, 再調用另外的target

    當然也可以用<foreach>來實現(xiàn)第二種風格

    2. 依賴較多, 構建腳本依賴的第三方Ant Task, 項目依賴的第三方庫等

    1. 明確區(qū)分構建腳本的依賴和你的項目的依賴. 那些第三方的Ant Task通常你只會在構建過程中用到它們, 而不會在產(chǎn)品中用到, 如 Checkstyle, Emma 等, 把它們放在單獨的目錄中, 打包時不要理會它們. 關于區(qū)分不同依賴的經(jīng)驗, 參考<<CruiseControl Enterprise 最佳實踐 (2) : Keep your dependencies to yourself>>

    2. 使用 ivy 來管理你項目的依賴

    3. 清理不必要的依賴或干擾:

    1. 總是提供 <clean> target, 并借助工具保證在需要的時刻總是能夠得到執(zhí)行, 參見后面的章節(jié)

    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>

    另外你希望一次構建能夠發(fā)現(xiàn)盡可能多的問題, 而不是出現(xiàn)第一個問題后構建就停止, 這樣的話可以批量修復它們然后再重新運行一次構建, 而不是一遍一遍的運行構建來逐個找出錯誤

    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. 需要在不同操作系統(tǒng)上運行

    1. 利用 <exec> 的 os 或 osfamily 屬性來控制不同操作系統(tǒng)上的行為

    2. 路徑分隔符統(tǒng)一使用 "/"

    5. 需要在不同團隊成員的機器上運行, 每個人環(huán)境都不一樣

    其實這是配置管理的問題, 項目的所有文檔和依賴, 甚至包括Ant本身都應該包含在一個單根目錄下, 并且Check in到版本控制系統(tǒng)中. 里面所有涉及路徑的地方都使用相對路徑. 這樣項目就可以即拷即用

    但總有一些對外部環(huán)境的依賴, 這是就要借助 Ant 強大而合理的 immutable property 體系

    1. 所有可能變化的地方都使用 property 來引用

    2. 優(yōu)先使用 JVM 的系統(tǒng)屬性, 而不是環(huán)境變量

    3. 使用 user.properties 文件定義環(huán)境相關的property, 并在構建腳本中最先引入 <property file="${user.home}/user.properties" />

    4. 在引入 user.properties 之后, 為所有屬性定義合理的缺省值, 以處理 user.properties 不存在不完整的情況

    5. 后面兩步也可以用 <propertyfile> 來代替

    一個應用就是可以在命令行傳入用戶名和密碼而不是把它們寫在腳本中, 這樣就避免了安全和隱私問題

    其它的例子包括用 property 來定義 test filter, 或者來定義碰到第一次錯誤是退出還是繼續(xù)運行構建等

    關于目錄的處理

    1. 為根目錄定義屬性, 以此為起點定義子目錄的屬性

    2. 總是使用 ${basedir} 作為相對路徑的前綴. 這樣可以保證即使 Ant 的工作路徑不同, 只要傳遞了正確的 basedir 屬性, 所有的相對路徑還是正確的.

    3. 使用 location 定義路徑, 而不是 value. Ant會將 location 展開為絕對路徑, 這樣即使傳遞到另外的 Ant Project 中, 它的值也不會變

    6. 由于以上原因, 導致Ant腳本較長

    Ant不是Script Language, 你更應該像編寫產(chǎn)品代碼一樣認真對待它的編寫風格

    1. 前面說過通過命令行參數(shù)控制執(zhí)行的target, 參數(shù)多了, 就要有 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 的執(zhí)行, 而任何 Task 都可能出現(xiàn)異常, 這樣有些清理操作就得不到執(zhí)行. 解決方案:

      a. Ant-Contrib的 <trycatch>

      b. CruiseControl 的 AntPublisher. CruiseControl定義了構建結束后的操作, 參見 <<CruiseControl Enterprise 最佳實踐 (1) : Publish with a Publisher>>

    2. 缺乏依賴管理機制

      前面已經(jīng)提到, 借助 ivy 來管理, ivy 已經(jīng)成為了 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. 與用戶交互, 這在持續(xù)集成環(huán)境中應該不多: <input>

    2. 并發(fā)執(zhí)行: <parallel>, 通常用來執(zhí)行在后臺運行的任務

    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>

    這樣就可以動態(tài)的定義屬性

    <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的執(zhí)行而用來運行后臺程序. 但會帶來很多不好的地方,比如不能即時在console看到信息等. 并且壽命長于 Ant 在某些情況下不是我們期待的, 比如在 CruiseControl 的環(huán)境中運行 Ant, 如果Ant fork的進程沒有隨著Ant退出而退出, 那么CruiseControl會認為Ant進程還沒有結束, 從而一直在那里等待而不是執(zhí)行后面的 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 文檔中說明的系統(tǒng)屬性? -Duser.country=EN -Duser.language=US

    參考


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導航:
     
    主站蜘蛛池模板: 亚洲人成免费电影| 久久成人18免费网站| 亚洲一区二区三区高清不卡| 亚洲欧美综合精品成人导航| 中文字幕影片免费在线观看| 亚洲电影在线播放| 国产精品亚洲а∨天堂2021| 国产精品久久久久影院免费| 亚洲国产精品一区二区久久| 久久亚洲精品专区蓝色区| 国产成人免费网站| 亚洲综合丁香婷婷六月香| 免费无码肉片在线观看| 亚洲性在线看高清h片| 无人视频在线观看免费播放影院 | 久久久无码精品亚洲日韩软件| 91精品国产亚洲爽啪在线观看| 国产亚洲综合久久| 亚洲人成人无码网www国产| 国产成人无码免费网站| 亚洲情XO亚洲色XO无码| 国产成人免费视频| 亚洲一级黄色大片| yy6080亚洲一级理论| 中文字幕乱码一区二区免费| 激情内射亚洲一区二区三区| 成人免费午夜在线观看| 国产亚洲漂亮白嫩美女在线| 亚洲综合精品香蕉久久网| 亚洲AV无码专区亚洲AV桃| 亚洲欧洲日本在线| 久久国产精品成人片免费| 亚洲色欲啪啪久久WWW综合网| xvideos亚洲永久网址| 无码少妇精品一区二区免费动态| 亚洲人成电影院在线观看| 亚洲XX00视频| 99精品视频在线免费观看| 亚洲日韩v无码中文字幕 | 99在线视频免费观看| 午夜亚洲福利在线老司机|