ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Apache Ant 1.9.16 离线构建指南:老项目编译打包实战

Apache Ant 1.9.16 离线构建指南:老项目编译打包实战 简介Apache Ant 1.9.16 二进制发行版面向 Java 项目开发者与构建工程师用于以 XML 描述构建流程自动化完成编译、打包、测试与部署替代手工重复操作。压缩包共 1617 个文件约 8.33MB以 1517 个 html 文档为主体辅以 23 个 jar 核心库与依赖、23 个 pom 元数据、若干 xsl、xml、cmd、bat、pl 脚本及 license、notice、readme 等说明文件覆盖多平台可执行脚本与运行时库。解压后目录结构清晰bin 提供 ant 与 ant.bat 命令行入口lib 存放运行所需 JARmanual 收录完整用户手册便于查阅任务用法与配置细节。已有 475 人学习下载适合需要理解 Ant 构建机制、编写 build.xml 或维护遗留 Java 项目的读者可据此掌握 target 依赖、javac 编译、jar 打包等典型任务的声明式写法并借助文档快速排查构建问题。1. 为什么 2024 年我还在用 apache-ant-1.9.16-bin.zip 搭老项目上周帮朋友救一个 2013 年的 Java 后台pom.xml 里全是systemPath指向本地 jarMaven 直接罢工。翻出项目根目录的 build.xml一行ant -f build.xml dist三分钟出包。这就是 apache-ant-1.9.16-bin.zip 存在的意义它不是给新项目炫技的是给那些构建脚本已经稳定运行十年、没人敢动、也动不起的老系统兜底的。这个压缩包是 Apache Ant 1.9.16 的二进制发行版解压即用不依赖 Maven 仓库不挑 JDK 版本1.5 到 8 都能跑Windows 下双击 ant.bat 就能编译。适合谁维护遗留 Java 系统的一线工程师、需要离线构建环境的内网开发、以及想搞懂「构建工具到底在干什么」的新手。下面我把这个包拆开从目录结构到 build.xml 写法再到我踩过的坑一次讲透。2. 拆开 apache-ant-1.9.16-bin.zip目录结构与启动脚本2.1 bin 目录里的脚本不是随便放的解压后第一层是apache-ant-1.9.16进去先看 bin。Windows 下你会看到ant.bat、ant.cmd、antRun.bat、antRun、lcp.bat、envset.cmd、antenv.cmd、runrc.cmd。很多人只认识 ant.bat其他文件直接忽略结果在复杂环境里翻车。我逐个说清楚。ant.bat是主入口但它本身不干活真正设置环境变量的是antenv.cmd。ant.bat第一行会调用antenv.cmd后者做三件事设ANT_HOME、把%ANT_HOME%\bin加进PATH、设JAVA_HOME检查。如果你机器上JAVA_HOME没配ant.bat 会直接报Unable to locate tools.jar这时候别去改 ant.bat去改antenv.cmd里的 JAVA_HOME 指向。lcp.bat是 classpath 拼接工具老 build.xml 里用exec调 Java 命令时经常引用它作用是帮你把一堆 jar 用分号拼成 classpath 字符串。antRun.bat是给exec任务在 Windows 下调脚本用的包装器Linux 下对应antRun。runrc.cmd和envset.cmd是给需要自定义环境变量的场景准备的一般项目用不到但内网离线环境要改代理或临时目录时会碰。Linux/Mac 下没有 .bat对应的是ant、antRun、lcp、envset.sh、antenv.sh。权限问题注意解压后ant可能没有执行权限chmod x bin/ant一下否则报Permission denied。2.2 lib 目录决定你能用哪些任务lib 下全是 jar核心是ant.jar它包含 Ant 所有内置任务javac、jar、copy、delete、mkdir 等。其他 jar 按需加载ant-junit.jar提供junit任务ant-junit4.jar支持 JUnit 4 注解ant-apache-bcel.jar支持字节码操作ant-apache-log4j.jar让 Ant 日志走 log4j。如果你 build.xml 里写了junit但报Could not create task or type: junit九成是 lib 下缺ant-junit.jar或者你用了-lib参数指向了错误的目录。一个容易忽略的点Ant 1.9.16 的 lib 里没有ant-junitlauncher.jar那是 1.10.x 才引入的。所以如果你从网上抄了一段用junitlauncher的 build.xml在 1.9.16 下必然报错。版本边界要清楚。2.3 manual 目录是离线救命稻草manual 目录是完整的 HTML 用户手册包含所有核心任务和可选任务的文档。内网环境没法上网查文档时直接浏览器打开manual/index.html比任何博客都准。我习惯把manual/Tasks/javac.html和manual/Tasks/exec.html加到书签调参数时直接翻。提示manual 里的示例代码可以直接复制到 build.xml 里改但注意示例用的 Ant 版本可能比你手上的新遇到不认识的属性先查manual/Tasks/下对应页面顶部的「Since Ant 1.x」标注。3. 用 build.xml 跑通第一个编译打包流程3.1 最小可用 build.xml 的四个要素Ant 的构建文件是 XML根元素project必须带name、default、basedir三个属性。default指定不传 target 时默认执行哪个basedir是相对路径的基准一般写.。下面是我给老项目写的最小模板直接抄?xml version1.0 encodingUTF-8? project nameLegacyApp defaultdist basedir. !-- 定义全局属性后面用 ${} 引用 -- property namesrc.dir valuesrc/ property namebuild.dir valuebuild/ property nameclasses.dir value${build.dir}/classes/ property namedist.dir value${build.dir}/dist/ property namelib.dir valuelib/ !-- 初始化清理并创建目录 -- target nameinit delete dir${build.dir}/ mkdir dir${classes.dir}/ mkdir dir${dist.dir}/ /target !-- 编译依赖 init -- target namecompile dependsinit javac srcdir${src.dir} destdir${classes.dir} encodingUTF-8 source1.8 target1.8 includeantruntimefalse classpath fileset dir${lib.dir} includes**/*.jar/ /classpath /javac /target !-- 打包依赖 compile -- target namedist dependscompile jar destfile${dist.dir}/legacy-app.jar basedir${classes.dir} manifest attribute nameMain-Class valuecom.example.Main/ /manifest /jar /target /project逻辑说明property定义变量${}引用。target是任务序列depends控制执行顺序。javac的includeantruntimefalse必须加否则 Ant 会把自身的 ant.jar 塞进 classpath导致编译时找不到类或版本冲突这是新手最常见的翻车点。fileset用通配符收集 lib 下所有 jar 作为 classpath。参数说明source和target指定 JDK 版本老项目写 1.6 或 1.7 都行但必须和你实际 JDK 匹配否则报invalid source release。encoding不写的话中文注释会乱码Windows 下默认 GBKLinux 下默认 UTF-8跨平台项目必须显式指定。3.2 命令行怎么调、环境变量怎么配Windows 下把apache-ant-1.9.16\bin加进系统 PATH然后ant -version验证。如果报ant 不是内部或外部命令检查 PATH 是否生效或者直接用绝对路径D:\apache-ant-1.9.16\bin\ant.bat。Linux/Mac 下编辑~/.bashrc或~/.zshrcexport ANT_HOME/opt/apache-ant-1.9.16 export PATH$ANT_HOME/bin:$PATH然后source ~/.bashrcant -version应输出Apache Ant(TM) version 1.9.16 compiled on ...。常用命令ant执行默认 targetant compile只执行 compileant -f /path/to/build.xml dist指定构建文件ant -Dkeyvalue传属性覆盖 build.xml 里的propertyant -verbose看详细日志ant -debug看调试日志输出巨长只在排查诡异问题时用。3.3 用 -D 传参实现多环境构建老项目经常要打测试包和生产包区别只是数据库地址不同。用-D传参最省事target namedist dependscompile property nameenv valuedev/ echo messageBuilding for env: ${env}/ jar destfile${dist.dir}/app-${env}.jar basedir${classes.dir}/ /target命令行ant -Denvprod dist就会打出app-prod.jar。注意property的不可变性如果 build.xml 里已经定义了env命令行-D传的值不会覆盖除非用property nameenv valuedev overridetrue/Ant 1.8 支持。这个坑我踩过调了半天以为 -D 没生效其实是 build.xml 里先定义了。4. 避坑与排查ant 1.9.16 的五个血泪经验4.1 现象Unable to locate tools.jar原因Ant 需要 JDK 而不是 JREJAVA_HOME指向了 JRE 目录或者根本没设。解决echo %JAVA_HOME%Windows或echo $JAVA_HOMELinux确认指向 JDK 根目录该目录下必须有lib/tools.jar。如果用的是 JDK 9tools.jar 被移除了Ant 1.9.16 在 JDK 9 以上会报这个错要么换 JDK 8要么升级 Ant 到 1.10.x。4.2 现象Class not found: javax.xml...或编译时找不到类原因javac没加includeantruntimefalseAnt 把自身的 ant.jar 和 xerces 等 XML 解析器塞进了 classpath和你项目的 jar 冲突。解决所有javac任务强制加includeantruntimefalse并在classpath里显式列出项目依赖。4.3 现象中文文件名或中文注释乱码原因javac没指定encodingAnt 用平台默认编码读源文件。Windows 默认 GBKLinux 默认 UTF-8跨平台必乱。解决javac encodingUTF-8同时确保源文件本身是 UTF-8 保存。如果源文件是 GBK就写encodingGBK但建议统一转 UTF-8。4.4 现象ant命令在 Windows 下报The system cannot find the path specified原因ANT_HOME路径里有空格比如C:\Program Files\apache-ant-1.9.16ant.bat 里拼接路径时没加引号。解决把 Ant 解压到无空格路径如C:\ant\apache-ant-1.9.16或者手动改antenv.cmd给路径加引号。这是 Windows 下的经典坑我一般直接放D:\tools\ant。4.5 现象exec任务在 Windows 下执行 shell 脚本失败原因Windows 没有 bashexec executablesh找不到 sh。解决用antRun.bat包装或者把脚本改成 .bat或者用exec executablecmd osWindows加arg value/c/。跨平台项目建议用condition判断 os分别写 Windows 和 Unix 的 exec 分支。5. 进阶用macrodef封装重复任务与离线构建技巧5.1 用 macrodef 把重复的 javac 配置收成一处老项目里经常有多个模块每个模块的javac配置一模一样改一个参数要改十处。用macrodef定义一次到处调用macrodef namecompile-module attribute namesrcdir/ attribute namedestdir/ sequential javac srcdir{srcdir} destdir{destdir} encodingUTF-8 source1.8 target1.8 includeantruntimefalse debugtrue classpath fileset dir${lib.dir} includes**/*.jar/ /classpath /javac /sequential /macrodef target namecompile-all compile-module srcdirmodule-a/src destdirbuild/a/ compile-module srcdirmodule-b/src destdirbuild/b/ /target注意macrodef里用{}引用属性不是${}。attribute定义参数名sequential包住实际任务。这样改编译参数只改 macrodef 一处所有模块同步生效。我接手老项目第一件事就是把重复的 javac 收成 macrodef后面维护省一半时间。5.2 离线构建把依赖 jar 全塞进 lib 目录内网环境没法连 Maven 仓库Ant 本身也不管依赖下载。我的做法是在 build.xml 里加一个fetch-depstarget用copy从本地共享目录把 jar 拷到lib/然后 compile 依赖这个 target。如果连共享目录都没有就手动把 jar 放进 lib用fileset全量引用。Ant 的path和fileset支持通配符不用一个个列 jar 名。target namefetch-deps copy todir${lib.dir} overwritefalse fileset dir/mnt/shared/jars includes**/*.jar/ /copy /targetoverwritefalse保证已存在的 jar 不被覆盖避免每次构建都拷一遍大文件。如果共享目录里 jar 有更新手动删掉 lib 下对应的再跑一次。5.3 验证构建结果用checksum和condition做自检构建完不验证等于没构建。我习惯在 dist target 末尾加一段自检target nameverify dependsdist available file${dist.dir}/legacy-app.jar propertyjar.exists/ fail unlessjar.exists messageJAR 未生成构建失败/ checksum file${dist.dir}/legacy-app.jar propertyjar.md5/ echo messageJAR MD5: ${jar.md5}/ /targetavailable检查文件是否存在fail在条件不满足时中断构建并报错。checksum算 MD5方便和运维核对包是否一致。这套组合拳加上去之后我再也没出现过「以为构建成功、结果部署时发现包是空的」这种事故。从那以后我每次拿到一个老项目的 build.xml都强制先跑一遍ant -verbose看它到底加载了哪些 jar、用了哪个 JDK、classpath 里有没有混进奇怪的东西然后再动第一行代码。希望帮到你。本文还有配套的精品资源点击获取
返回列表