ant是著名的构建工具,maven则是著名的依赖管理工具,要说谁好用,我还真说不出来,因为各有各的擅长,maven对于从源码,编译一直到打包这块完全无可挑剔,因为约定大于配置,所以maven简单到最后只有一个命令maven clean install就搞定所有事情,最重要的是搞定包依赖;而ant则是一个相对万能的工具,有些像shell脚本,因为已经定义好了无数好用的task,而且还允许随意扩展。
有的情况需要利用两个工具的优势。比如,你需要一键运行一个jar包,如果放在无工具时代,你需要自己敲一串很长的命令(需要带上依赖的jar包),据我所知,maven也是不能直接运行jar的,所以只有ant可以;再比如,需要查找替换某个特殊的文件,然后才开始install,这个过程,maven应该也是不能做的(没有调查过写插件是不是可以)。但是叫ant管理包依赖……杀了我吧。
所以我们有了一个场景,需要结合二者。为了更好的自由控制,我选择的是ant调用maven,选用的插件是maven ant task,地址是
http://maven.apache.org/ant-tasks/
,而不是反过来maven调用ant,有另一个maven的插件antrun。
使用ant集成maven,如下的步骤很重要,即定义maven ant task这个插件的的tag去哪找,记得要把maven-ant-tasks-2.1.3.jar拷贝到跟build.xml同目录
<project name="test" default="deploy" xmlns:artifact="antlib:org.apache.maven.artifact.ant">
<path id="maven-ant-tasks.classpath" path="maven-ant-tasks-2.1.3.jar" />
<typedef resource="org/apache/maven/artifact/ant/antlib.xml"
uri="antlib:org.apache.maven.artifact.ant"
classpathref="maven-ant-tasks.classpath" />
<target name="git-update">
...
接下来就可以自由的使用maven的各种命令了,比如clean install,记住这里的arg一次只能写一个,不能写到一起去;另外,fork=true一定要加上,由于这个artifact:mvn这个task是集成java task,因而fork=”true”表示在一个新的jvm中去执行maven任务,之前的折腾了的问题就是因为没有这句,导致build成功后出现一个权限异常。
<target name="maven-clean-install">
<artifact:mvn pom="pom.xml" mavenHome="${maven.home}" fork="true">
<arg value="clean"/>
<span style="white-space:pre"> </span><arg value="install"/>
<arg value="-DskipTests"/>
</artifact:mvn>
</target>
顺便提一下
maven如何打一个可执行的包
,这个话题网上很多文章。比如
https://www.ibm.com/developerworks/cn/java/j-5things13/
其实主要的就是两个步骤:
1.是配置maven-jar-plugin,这个地方是帮助你生成manifest的,关于manifest,有两个地方比较重要,一个是main-class,一个是classpath。
如果你打算使用java -jar -classpath …这样的命令,那么最终classpath是不能生效的,因为java默认限制了jar的加载路径在当前可执行的jar里,因而需要在manifest里指定classpath。可以参考这些文章
http://www.zeali.net/entry/15
和
http://www.ibm.com/developerworks/cn/java/j-jar/
。pom的配置如下:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<span style="white-space:pre"> </span><classpathPrefix>lib/</classpathPrefix>
<span style="white-space:pre"> </span><mainClass>org........MainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
2. 这步完成之后第二步是利用maven的依赖管理帮你把依赖的包到copy到当前jar目录或者子目录。
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy</id>
<phase>install</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/lib
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
这两步完成后就可以直接用java -jar xxx.jar运行了。
当然了,我遇到的问题更特殊一点,因为我有一个jar是不在中央仓库中的,scope是system,因而maven的打包插件不会自动将这个jar加入manifest,导致运行起来会报错。(当然我可以建一个本地中央仓库,将该jar托管到本地仓库中也可以搞定)
查了很多资料,貌似在addClass过程中很难干预他的打包,想想也对,如果他能够将system scope的东西也打包进去,那还不乱套了。
所以我的解决办法是在执行之前使用ant做替换,简单讲就是先解压,替换,再压缩。整个过程看起来如下
<unzip dest="${test.start}/target/test-start-1.0">
<fileset dir="${test.start}/target/">
<include name="${test.start.name}"/>
</fileset>
</unzip>
<replace file="${test.start}/target/test-start-1.0/META-INF/MANIFEST.MF" token="${line.separator}${line.separator}" value=" lib/special.jar${line.separator}${line.separator}"/>
<zip destfile="${test.start}/target/${test.start.name}"
basedir="${test.start}/target/test-start-1.0"/>
需要注意的是,在ant中,换行符使用${line.separator},我用\r\n试了无效,其次,再次打包回来不能用jar这个task,否则他会自动生成manifest,你就白改了。
maven pom编辑后,jar包有了,但是Referenced Libraries没有这个新增jar包
解决办法如下:删除当前eclipse工程下的.classpath,mvn eclipse:eclipse 重新构建了.classpath,刷新Eclipse工程
maven类包冲突解决技巧 http://stamen.iteye.com/blog/2030552