Sky's blog

          我和我追逐的夢(mèng)

          常用鏈接

          統(tǒng)計(jì)

          其他鏈接

          友情鏈接

          最新評(píng)論

          初學(xué)maven(4)-使用maven ant task實(shí)現(xiàn)非標(biāo)準(zhǔn)打包

              maven很強(qiáng)大,但是總有些事情干起來(lái)不是得心應(yīng)手,沒(méi)有使用ant時(shí)那種想怎么干就怎么干的流暢感。尤其當(dāng)要打包一個(gè)特殊(相對(duì)maven的標(biāo)準(zhǔn)架構(gòu)而且)時(shí),常有不知所措的感覺(jué)。當(dāng)然這個(gè)應(yīng)該和自己對(duì)maven的了解不夠有關(guān),畢竟,“初學(xué)maven”嘛。

              但是maven在依賴管理方面實(shí)在是太強(qiáng)大了,太喜歡,退回原來(lái)的ant方式完全不可能,我想用過(guò)maven的人,一般是不會(huì)有回到原來(lái)在cvs,subversion中checkin/checkout n個(gè)jar包的時(shí)代,僅此一項(xiàng)理由就足夠繼續(xù)堅(jiān)持使用maven了。

              然而ant的靈活又難于忘懷,尤其是從ant的build.xml一路走來(lái)的人,總是回不知不覺(jué)間想到ant的美好。魚(yú)與熊掌,我都想要。最近想打包一個(gè)java應(yīng)用,很簡(jiǎn)單但即不是標(biāo)準(zhǔn)的j2ee appication也不是web application, 用maven完全不知道該怎么打包,package出來(lái)的完全不是我想要的,在網(wǎng)上四處google maven資料的時(shí)候,總有用回ant拉倒的沖動(dòng)。

              先交代一下背景吧,我要打包的程序,是這個(gè)樣子:

              demo1
              |____lib
              |_____demo1.jar
              |_____*****.jar
              |_____*****.jar
              |____config
              |_____*****.properties
              |_____*****.xml
              |____log
              |_____*****.log
              |____run.bat
              |____run.sh

              這個(gè)應(yīng)用的打包模式很簡(jiǎn)單,一個(gè)bat或者sh腳本用來(lái)執(zhí)行,lib目錄下存放所有的jar包,包括自己的源代碼編譯打包的jar和第三方包。config下是配置文件,這些文件需要在安裝時(shí)或者運(yùn)行前修改,比如監(jiān)聽(tīng)的端口啊,數(shù)據(jù)庫(kù)信息之類的。log目錄存放日志文件。最后打包的產(chǎn)物是一個(gè)zip包(或者tar,tar.gz)。

              遇到的問(wèn)題,就是maven標(biāo)準(zhǔn)的打包方式中根本不考慮類似的情況,什么jar,ear,war完全不適用。而且maven有些理念也詫異,比如maven標(biāo)準(zhǔn)的config目錄是src/main/config,但是這個(gè)目錄里面的配置文件默認(rèn)會(huì)打包到j(luò)ar包中,暈,都在jar里面了還讓人怎么改???
             
              本著盡量只用maven不用ant的想法,我在maven的資料中看了好久,沒(méi)有找到解決的方法。暈,難道大家都只打包標(biāo)準(zhǔn)的ear,jar,war,只有我這樣無(wú)聊的人才會(huì)有這種打包的需求?

              幾經(jīng)尋覓和探索,最后發(fā)現(xiàn),maven ant tasks似乎是一個(gè)不錯(cuò)的選擇。帶著mavenanttasks的官方文檔和google上搜到的幾篇文章,開(kāi)始嘗試,成功實(shí)現(xiàn)功能?,F(xiàn)在將過(guò)程和方法share給大家。

              首先建立java項(xiàng)目anttaskdemo1,按照maven的推薦,文件結(jié)構(gòu)如下:

              anttaskdemo1
              |____src/main/java
              |____src/main/config
              |____src/main/bin
              |____src/main/resources
              |____src/test/java
              |____src/test/resources
              |____target
              |____build.properties
              |____build.xml
              |____pom.xml

              其中src/main/java下放java代碼;src/main/resources下放一個(gè)*.properties文件,這個(gè)資源文件是打包到j(luò)ar中,內(nèi)容打包之后不需要改變的。src/main/config下放一個(gè)標(biāo)準(zhǔn)的log4j.xml,這個(gè)是有在安裝運(yùn)行前臨時(shí)修改的需要的。src/main/bin下放置可執(zhí)行文件。

              1. 首先看pom.xml,標(biāo)準(zhǔn)內(nèi)容,很簡(jiǎn)單,象征性的加入幾個(gè)依賴
                
          <dependency>
                      
          <groupId>commons-codec</groupId>
                      
          <artifactId>commons-codec</artifactId>
                      
          <version>1.3</version>
                  
          </dependency>
                  
          <dependency>
                      
          <groupId>log4j</groupId>
                      
          <artifactId>log4j</artifactId>
                      
          <version>1.2.13</version>
                      
          <scope>compile</scope>
                  
          </dependency>
                  
          <dependency>
                      
          <groupId>org.testng</groupId>
                      
          <artifactId>testng</artifactId>
                      
          <version>5.8</version>
                      
          <scope>test</scope>
                      
          <classifier>jdk15</classifier>
                  
          </dependency>

              其中commons-codec,log4j是需要打包到lib中的,運(yùn)行時(shí)需要。testng(或者更一般的junit)是用來(lái)單元測(cè)試的,不需要打包到lib中。請(qǐng)注意它的設(shè)置"<scope>test</scope>"。

              2. 然后看看build.properties文件,這個(gè)內(nèi)容不多:
             
          M2_REPO=G:/soft/maven/localRepository

          path.package=package
          path.target.name=anttaskdemo1
          path.package.lib=lib
          path.package.log=log
          path.package.config=config
          path.package.bin=

             
              M2_REPO稍后再詳談,后面的path.package之類的是最終打包時(shí)使用的幾個(gè)目錄名稱,對(duì)應(yīng)于最終打包的結(jié)構(gòu)。

              3. build.xml,這個(gè)內(nèi)容比較多。

             
          <?xml version="1.0" encoding="UTF-8"?>
          <project name="demo" default="all" xmlns:artifact="urn:maven-artifact-ant">
              
          <description>
              
          </description>
              
          <property file="build.properties" />

              
          <target name="init_maven">
                  
          <!--
                  remember to set M2_REPO before use this build.xml, for example in eclispe:
                  "Window→Preferences→Ant→Runtime", add a new property named "M2_REPO" and set it value point to the path of your maven
                  local repository; Or you can set it in build.properties.  You need do one (and only one) of them.
                  
          -->
                  
          <path id="maven-ant-tasks.classpath" path="${M2_REPO}/org/apache/maven/maven-ant-tasks/2.0.9/maven-ant-tasks-2.0.9.jar" />
                  
          <typedef resource="org/apache/maven/artifact/ant/antlib.xml" uri="urn:maven-artifact-ant" classpathref="maven-ant-tasks.classpath" />

                  
          <artifact:pom id="maven.project" file="pom.xml" />
                  
          <artifact:dependencies pathId="classpath.build" filesetid="maven.fileset.build">
                      
          <pom refid="maven.project" />
                  
          </artifact:dependencies>
                  
          <artifact:dependencies pathId="classpath.runtime" filesetid="maven.fileset.runtime" useScope="runtime">
                      
          <pom refid="maven.project" />
                  
          </artifact:dependencies>
              
          </target>

              
          <target name="all" depends="init_path, compile, jar, package, zip" description="do all">
                  
          <echo>begin to do all target to build the result package.</echo>
              
          </target>

              
          <target name="maven_info" depends="init_maven">
                  
          <echo>Maven build directory is ${maven.project.build.directory}</echo>
                  
          <echo>Maven build finalName is ${maven.project.build.finalName}</echo>
                  
          <echo>Maven build sourceDirectory directory is ${maven.project.build.sourceDirectory}</echo>
                  
          <echo>Maven build outputDirectory directory is ${maven.project.build.outputDirectory}</echo>
                  
          <echo>Maven build scriptSourceDirectory directory is ${maven.project.build.testSourceDirectory}</echo>
                  
          <echo>Maven build testOutputDirectory directory is ${maven.project.build.testOutputDirectory}</echo>
                  
          <echo>Maven build scriptSourceDirectory directory is ${maven.project.build.scriptSourceDirectory}</echo>
                  
          <echo>Maven build resourceDirectory directory is ${maven.project.build.resources}</echo>

                  
          <property name="target.jar.name" value="${maven.project.build.directory}/${maven.project.build.finalName}.jar" />
                  
          <echo>Maven build scriptSourceDirectory directory is ${target.jar.name}</echo>
              
          </target>

              
          <target name="clean" depends="init_maven">
                  
          <echo>clean build directory : ${maven.project.build.directory}</echo>
                  
          <delete dir="${maven.project.build.directory}" includes="**/*" />
              
          </target>

              
          <target name="init_path" depends="maven_info, clean">
                  
          <echo>make dir for java compile: ${maven.project.build.outputDirectory}</echo>
                  
          <mkdir dir="${maven.project.build.outputDirectory}" />
              
          </target>

              
          <target name="compile" description="description" depends="init_maven">
                  
          <javac srcdir="${maven.project.build.sourceDirectory}" destdir="${maven.project.build.outputDirectory}" classpathref="classpath.build" />
              
          </target>
              
          <target name="copyResource" depends="init_maven">
                  
          <copy todir="${maven.project.build.outputDirectory}">
                      
          <fileset dir="src/main/resources">
                      
          </fileset>
                  
          </copy>
              
          </target>

              
          <target name="jar" depends="compile, copyResource">
                  
          <delete file="${maven.project.build.directory}/${maven.project.build.finalName}.jar"  failonerror="false" />
                  
          <jar destfile="${maven.project.build.directory}/${maven.project.build.finalName}.jar" basedir="${maven.project.build.outputDirectory}">
                  
          </jar>
              
          </target>

              
          <target name="package" depends="package_prepare, copyLib, copyConfig, copyBin">
              
          </target>

              
          <target name="package_prepare" depends="init_maven">
                  
          <echo>clean package directory : ${maven.project.build.directory}/${path.package}</echo>
                  
          <delete dir="${maven.project.build.directory}/${path.package}" />
                  
          <mkdir dir="${maven.project.build.directory}/${path.package}" />
                  
          <mkdir dir="${maven.project.build.directory}/${path.package}/${path.target.name}" />
                  
          <mkdir dir="${maven.project.build.directory}/${path.package}/${path.target.name}/${path.package.lib}" />
                  
          <mkdir dir="${maven.project.build.directory}/${path.package}/${path.target.name}/${path.package.config}" />
                  
          <mkdir dir="${maven.project.build.directory}/${path.package}/${path.target.name}/${path.package.log}" />
              
          </target>

              
          <target name="copyLib" depends="init_maven">
                  
          <copy todir="${maven.project.build.directory}/${path.package}/${path.target.name}/${path.package.lib}">
                      
          <fileset refid="maven.fileset.runtime" />
                      
          <mapper type="flatten" />
                  
          </copy>
                  
          <copy todir="${maven.project.build.directory}/${path.package}/${path.target.name}/${path.package.lib}"
                      file
          ="${maven.project.build.directory}/${maven.project.build.finalName}.jar">

                  
          </copy>
              
          </target>
              
          <target name="copyConfig" depends="init_maven">
                  
          <copy todir="${maven.project.build.directory}/${path.package}/${path.target.name}/${path.package.config}">
                      
          <fileset dir="src/main/config">
                      
          </fileset>
                  
          </copy>
              
          </target>
              
          <target name="copyBin" depends="init_maven">
                  
          <copy todir="${maven.project.build.directory}/${path.package}/${path.target.name}/${path.package.bin}">
                      
          <fileset dir="src/main/bin">
                      
          </fileset>
                  
          </copy>
              
          </target>
              
          <target name="zip" depends="init_maven">
                  
          <zip destfile="${maven.project.build.directory}/${path.package}/${path.target.name}.zip">
                      
          <fileset dir="${maven.project.build.directory}/${path.package}/${path.target.name}"></fileset>
                  
          </zip>
              
          </target>
          </project>

              一步一步來(lái)講吧:

              3.1 最重要的一步,init_maven

              <target name="init_maven">
                  
          <!--
                  remember to set M2_REPO before use this build.xml, for example in eclispe:
                  "Window→Preferences→Ant→Runtime", add a new property named "M2_REPO" and set it value point to the path of your maven
                  local repository; Or you can set it in build.properties.  You need do one (and only one) of them.
                  
          -->
                  
          <path id="maven-ant-tasks.classpath" path="${M2_REPO}/org/apache/maven/maven-ant-tasks/2.0.9/maven-ant-tasks-2.0.9.jar" />
                  
          <typedef resource="org/apache/maven/artifact/ant/antlib.xml" uri="urn:maven-artifact-ant" classpathref="maven-ant-tasks.classpath" />

                  
          <artifact:pom id="maven.project" file="pom.xml" />
                  
          <artifact:dependencies pathId="classpath.build" filesetid="maven.fileset.build">
                      
          <pom refid="maven.project" />
                  
          </artifact:dependencies>
                  
          <artifact:dependencies pathId="classpath.runtime" filesetid="maven.fileset.runtime" useScope="runtime">
                      
          <pom refid="maven.project" />
                  
          </artifact:dependencies>
              
          </target>


              在ant中使用maven-ant-tasks,就需要裝載maven-ant-tasks的jar包,方法有兩種,一種是直接將maven-ant-tasks-2.0.9.jar放到ant的lib下,自然就可以直接使用。但是個(gè)人感覺(jué)不怎么喜歡這種方式,我采用的是第二種,在ant的build.xml文件中裝載:

                  <path id="maven-ant-tasks.classpath" path="${M2_REPO}/org/apache/maven/maven-ant-tasks/2.0.9/maven-ant-tasks-2.0.9.jar" />
                  
          <typedef resource="org/apache/maven/artifact/ant/antlib.xml" uri="urn:maven-artifact-ant" classpathref="maven-ant-tasks.classpath" />


              這樣就可以在后面使用maven-ant-tasks的task,比如artifact:pom,artifact:dependencies。<path />用于指定maven-ant-tasks-2.0.9.jar的路徑,這里就有點(diǎn)麻煩了:maven-ant-tasks-2.0.9.jar這個(gè)東西放哪里好呢?直接放到項(xiàng)目中,然后存放到cvs/svn?顯然不是一個(gè)好辦法??紤]到maven本來(lái)就是干保存jar這行的,交給maven好了。maven-ant-tasks-2.0.9.jar本來(lái)就是一個(gè)依賴,可以在http://mvnrepository.com/找到:
              http://mvnrepository.com/artifact/org.apache.maven/maven-ant-tasks
              pom內(nèi)容如下:
              <dependency>
              
          <groupId>org.apache.maven</groupId>
              
          <artifactId>maven-ant-tasks</artifactId>
              
          <version>2.0.9</version>
          </dependency>

              將這個(gè)內(nèi)容隨便找個(gè)空項(xiàng)目,加入后update一下dependency,在本地的maven repository中就會(huì)有它的jar文件。然后就可以直接使用它。
              ${M2_REPO},這個(gè)是eclipse中通用的指向maven local repository的變量,大家使用maven命令建立eclipse項(xiàng)目時(shí)會(huì)遇到它。我們?cè)谶@里可以直接使用這個(gè)變量來(lái)訪問(wèn)maven local repository。如果沒(méi)有建立這個(gè)變量,請(qǐng)自行建立,上面注釋中有詳細(xì)說(shuō)明。如果在eclispe之外比如命令行直接運(yùn)行ant打包,則可以通過(guò)設(shè)置build.properties文件中的“M2_REPO=G:/soft/maven/localRepository”來(lái)指定。(這里用到ant的一個(gè)特性,屬性一旦被賦值就不能修改,因此第一次賦值有效,在eclispe中運(yùn)行,M2_REPO會(huì)使用eclispe中設(shè)置的值,如果eclispe沒(méi)有設(shè)置或者命令行直接運(yùn)行,M2_REPO屬性會(huì)在build.properties文件裝載時(shí)設(shè)置。)

              裝載ok后,接著是調(diào)用artifact:pom和artifact:dependencies 任務(wù)來(lái)指定pom.xml文件,再得到dependencies信息,后面的編譯打包會(huì)使用到。注意useScope="runtime",這個(gè)是為了最后打包時(shí)使用,只復(fù)制runtie時(shí)需要的jar包。

              <target name="maven_info" />是用來(lái)打印maven相關(guān)的一些信息的,比如maven下的幾個(gè)build目錄。artifact:pom任務(wù)裝載了整個(gè)pom,因此在后面可以訪問(wèn)到pom的信息,比如${maven.project.build.sourceDirectory}是java源代碼目錄,${maven.project.build.finalName}是最終的名稱。

              pom的內(nèi)容可以參考這兩個(gè)官方資料:

              1) maven model
                  http://maven.apache.org/ref/2.0.9/maven-model/maven.html

              2) Introduction to the POM
                  http://maven.apache.org/guides/introduction/introduction-to-the-pom.html

              標(biāo)準(zhǔn)目錄布局可以參考這個(gè)官方資料:

                  http://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html

              3.2 compile

                  這里是maven ant task的精髓所在,
              <target name="compile" description="description" depends="init_maven">
                  
          <javac srcdir="${maven.project.build.sourceDirectory}" destdir="${maven.project.build.outputDirectory}" classpathref="classpath.build" />
              
          </target>

                  結(jié)合之前maven初始化時(shí)的情況:
                  <artifact:pom id="maven.project" file="pom.xml" />
                  
          <artifact:dependencies pathId="classpath.build" filesetid="maven.fileset.build">
                      
          <pom refid="maven.project" />
                  
          </artifact:dependencies>


              可以看到,我們的項(xiàng)目完全遵循maven的標(biāo)準(zhǔn)做法,然后ant通過(guò)訪問(wèn)pom來(lái)得到相關(guān)的路徑信息和classpath信息,完美結(jié)合。
              target copyResource 完成了將resource copy到outputDirectory的任務(wù),這里的resource都是classpath resource。
              注: 這個(gè)有個(gè)問(wèn)題,就是我沒(méi)有找到通過(guò)pom得到resouce目錄的方法,${maven.project.build.resources 只能得到pom文件中<resources/>, 對(duì)于里面包含的<resource>不知道該用什么方式來(lái)訪問(wèn),如默認(rèn)的:
              <resources>
                
          <resource>
                  
          <directory>src/main/resources</directory>
                
          </resource>
              
          </resources>

              我試過(guò)用${maven.project.build.resources[0];${maven.project.build.resources(0), ${maven.project.build.resources.0,${maven.project.build.resources.resource
          等都無(wú)效。找了很久都沒(méi)有找到資料,只好作罷。直接寫死src/main/resources吧。

              3.3 jar
                  和compile類似,標(biāo)準(zhǔn)的ant jar,然后通過(guò)訪問(wèn)pom來(lái)得到相關(guān)的路徑信息和打包文件名。注意這里的文件名和路徑和maven的做法一致,也就是說(shuō)和執(zhí)行maven的compile命令結(jié)果是一樣的。
              <target name="jar" depends="compile, copyResource">
                  
          <delete file="${maven.project.build.directory}/${maven.project.build.finalName}.jar"  failonerror="false" />
                  
          <jar destfile="${maven.project.build.directory}/${maven.project.build.finalName}.jar" basedir="${maven.project.build.outputDirectory}">
                  
          </jar>
              
          </target>


              3.4 package, zip
              package_prepare, copyLib, copyConfig, copyBin 這幾個(gè)target都簡(jiǎn)單,體力活而已。zip也是。

             
              4. 總結(jié)
             
                  上面的內(nèi)容雖多,但是總結(jié)起來(lái)就只有兩點(diǎn):
              1. maven ant task可以將maven的功能和ant的靈活性統(tǒng)一起來(lái),對(duì)于非標(biāo)準(zhǔn)的打包情況非常適用
              2. maven ant task的使用并不難,不過(guò)需要掌握不少maven的基本知識(shí),比如pom,標(biāo)準(zhǔn)目錄布局等。

                  另外,似乎,ant + Ivy會(huì)是更好的選擇?

          posted on 2008-12-29 16:37 sky ao 閱讀(9080) 評(píng)論(1)  編輯  收藏 所屬分類: project building

          評(píng)論

          # re: 初學(xué)maven(4)-使用maven ant task實(shí)現(xiàn)非標(biāo)準(zhǔn)打包 2008-12-29 21:17 夢(mèng)想在這里起飛

          我給大家介紹另外一個(gè)開(kāi)源的項(xiàng)目,開(kāi)源ireport報(bào)表

          也是基于這個(gè)打包的~!

          http://ireport.cubebi.com
            回復(fù)  更多評(píng)論   

          主站蜘蛛池模板: 乐东| 玉林市| 湘潭市| 兴宁市| 资兴市| 河南省| 岚皋县| 准格尔旗| 镇宁| 边坝县| 革吉县| 东乌| 哈巴河县| 同心县| 通化市| 江源县| 玉屏| 会宁县| 宜良县| 阳江市| 临朐县| 南城县| 宝清县| 青海省| 珠海市| 鹿泉市| 荥阳市| 桃园市| 涡阳县| 通海县| 顺义区| 京山县| 宝鸡市| 侯马市| 鞍山市| 泌阳县| 宜宾县| 屯昌县| 中西区| 土默特左旗| 九江市|