首先請允許我這樣說,作為開發或測試,你一定要具備這種本領。你可以手動打包、部署你的工程,但這不是最好的方法。最好的方式就是全自動化的方式。開發人員提交了程式碼後,可以自動構建、打包、部署到測試環境。測試通過後進入到模擬環境或是直接釋出的生產環境,這個過程可以是全自動的。但這個自動化的方式有一些公司用到了,但也有很多公司還不知道,他們的攻城師天天在做反覆、沒有多大意義的、浪費生命的事情。當然這種方式一般針對做自己的產品,如電商、通訊行業。而給其他公司或企業做專案的比較少利用這種方式,當然也可以利用這種方式,只是不能直接釋出到客戶的伺服器而已。當然有些公司是專門有人做這部分事情的!
說了這麼多也沒有什麼惡意,只是覺得這種方式可以大大提高效率,降低人力、物力、財力而已。勿噴,O(∩_∩)O哈哈~嘿嘿~
在部署專案或打包專案中,通常大家都是手動部署或打包的多。很多公司把這一任務交個了我們做開發的,其實這部分應該誰做呢?本質上應該是測試的來完成,但一些公司的測試不會做這個,慢慢的就變成了開發的事情。有些公司是人手比較少、不健全,所以一部分人自己承擔了這個事情。在我們手動打包的時,其實這是一個重複的、沒有技術含量的、耗費體力的活兒。一般步驟就是更新svn上程式碼、修改好相關的配置、編譯class、釋出到tomcat(web工程)、測試啟動無誤、手動打包。
而有一種比較簡單快速的方式就是利用meven或ant來完成這些工作,只要我們編寫好指令碼後。給相關的工作人員去執行這部分指令碼就可以完成打包,甚至是部署專案,這些都是so easy~!我個人也比較贊成使用這種方式,比較簡單、快速、重用性好,最難的可能編寫build指令碼,但這個指令碼其實也是很簡單的,它就想dos命令列,只不過它是用xml方式來完成命令列的而已。所以測試會寫ant的build指令碼這個也是應該的,如果你不會的話,還是建議你學習學習。反正是百益無一害的事情,何樂而不為呢!
一、基本流程
利用ant打包專案或打增量包的基本流程
值得一提的是jar包這個部分,這個步驟是為下面編譯增量包做準備的。因為增量包匯出的增量檔案,它依賴於整個專案的其他程式碼,如果沒有這些程式碼的支援是編譯不通過。然而又不能直接通過diff得到增量的class,所以只能匯出增量檔案後,通過引用全部工程的程式碼的class再進行編譯即可。
二、執行環境
1、安裝jdk,不會自己上網查其他的
2、如果你還沒有安裝ant,那麼你可以參考:http://www.cnblogs.com/hoojo/archive/2013/06/14/java_ant_project_target_task_run.html
會介紹一下ant的安裝和使用的方法。
3、這裡需要用到svn的ant相關工具包、命令支援。你需要下載svnant-1.3.1.zip,將裡面的lib庫放置在你的ant指令碼的編譯執行環境中。
4、因為某些專案使用到了泛型、annotation註解,使用javac有些程式碼是編譯不通過的,所以這裡使用了jdt的編譯方式。參考:使用eclipse JDT compile class 會有很詳細的介紹。
需要用到
jdtCompilerAdapter.jar
org.eclipse.jdt.compiler.tool_1.0.1.v_793_R33x.jar
org.eclipse.jdt.core_3.3.3.v_793_R33x.jar
org.eclipse.jdt.debug.ui_3.2.102.v20071002_r332.jar
複製到ant_home/lib目錄下,如果是利用eclipse執行指令碼就需要把它載入到執行環境中。可以參考上面的:使用eclipse JDT compile class
三、編寫ant的build指令碼
1、首先看看ant工程的目錄結構
簡單介紹下目錄結構:
src下面的ExportIncrementFiles.java是匯出增量檔案要用的,它在build命令increment中執行。它會讀取diff 比較後的檔案中的內容,並匯出檔案
dest 是checkout出來最新的svn的工程
dist 是編譯上面dest目錄中的工程,也是svn全量war的工程目錄和jar
increment_dest 是增量工程,也就是上面的ExportIncrementFiles工具匯出的工程
increment_dist 是編譯上面increment_dest 的工程,也是增量包的工程目錄
因為每個人的專案工程目錄結構不一樣,所以這個指令碼並不會通用,我這裡指標對自己的專案進行測試。
lib中是執行環境需要的jar庫,其中主要的就是svnlib 這個你可以去下載 svnant-1.3.1.zip 以及JDT編譯class的jar包,這個可以通過eclipse中的plugin中的jar包找到,可以參考:使用eclipse JDT compile class
increment.export.jar就是ExportIncrementFiles的class打成的jar包,這個是自己打的包,可以直接應用class也可以的,在increment命令引用,jar下載:http://download.csdn.net/detail/ibm_hoojo/6501165
build.properties是當前build的配置檔案
build.xml就是主要的ant指令碼
選中部分是打的war包,這個就可以部署了
patch.txt就是svn的diff 比較出的增量檔案的目錄路徑列表
2、ExportIncrementFiles.java 匯出增量檔案
package com.hoo.util;import java.io.BufferedReader;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.FileReader;/*** <b>function:</b> 匯出在增量的檔案* @author hoojo* @createDate 2013-11-2 下午10:00:01* @file ExportIncrementFiles.java* @package com.hoo.util* @project AntTest* @blog http://blog.csdn.net/IBM_hoojo* @email hoojo_@126.com* @version 1.0*/public class ExportIncrementFiles {/*** <b>function:</b> 匯出增量檔案* @author hoojo* @createDate 2013-11-2 下午10:15:43* @param configPath 增量檔案路徑配置目錄* @param baseDir 基本路徑 目標位置* @param destDir 增量檔案儲存位置* @throws Exception*/private static void export(String configPath, String baseDir, String destDir) throws Exception {String srcFile = baseDir + configPath;String desFile = destDir + configPath;int lastIndex = desFile.lastIndexOf("/");String desPath = desFile.substring(0, lastIndex);File srcF = new File(srcFile);if(srcF.exists()){//如果不存在這樣的原始檔,就不再拷貝,這個用來解決版本之間有刪除檔案的情況。File desF = new File(desFile);File desP = new File(desPath);if(!desP.exists()) {desP.mkdirs();}System.out.println(srcFile);FileInputStream fis = new FileInputStream(srcF);FileOutputStream fos = new FileOutputStream(desF);byte[] buf = new byte[1024];int len = 0;while((len = fis.read(buf)) != -1) {fos.write(buf,0,len);}fos.flush();fos.close();fis.close();}}/*** <b>function:</b> 主函式 執行匯出增量包任務* @author hoojo* @createDate 2013-11-2 下午10:00:01* @param args 引數1 增量包匯出檔案路徑,引數2 要匯出的檔案的所在目標位置,引數3 增量包匯出儲存的位置路徑*/public static void main(String[] args) {if (args.length > 0) {if (args.length == 1 && "help".equals(args[0])) {System.out.println("args[0] is Export Increment Files content path");System.out.println("args[1] is Export Increment Files target path");System.out.println("args[2] is Increment Files Export loaction");} else {String configPath = args[0];String baseDir = args[1];String destDir = args[2];try {BufferedReader br = new BufferedReader(new FileReader(configPath));String s = null;while((s = br.readLine()) != null) {s = s.trim();//去掉路徑前面的空格String str = destDir + s;if(!destDir.equals(str)){//過濾空行export(s, baseDir, destDir);}}br.close();} catch (Exception e) {e.printStackTrace();}}}}}
main函式引數看註釋,主要就是讀取patch.txt增量檔案路徑,匯出檔案到指定目錄的。
3、build 指令碼
<?xml version="1.0" encoding="UTF-8" ?><!-- createDate 2013-10-28 --><!-- author hoojo & http://blog.csdn.net/IBM_hoojo & http://hoojo.cnblogs.com --><project default="checkout" basedir="."><property file="build.properties"/><!-- svn 比較專案最新路徑 --><property name="svn.url" value="${svn._url}"/><!-- svn 備份路徑--><property name="bak.svn.url" value="${bak.svn._url}"/><property name="svn.username" value="${svn.username}"/><property name="svn.password" value="${svn.password}"/><!-- 專案名稱 --><property name="webapp" value="${webapp.name}"/><!-- 目標專案的Web 名稱(WEB-INF上一級的目錄名稱) --><property name="webroot" value="${web.root}"/><!-- svn改動檔案列表資訊 --><property name="compare.path.file" value="${increment.file}"/><!-- svn匯出/切出檔案存放目錄 --><property name="dest.path" location="dest/${webapp}"/><!-- svn匯出/切出檔案編譯後存放目錄 --><property name="dist.path" location="dist/${webapp}"/><!-- svn增量檔案儲存目錄 --><property name="increment.dest.path" location="increment_dest/${webapp}"/><!-- svn增量檔案編譯後儲存目錄 --><property name="increment.dist.path" location="increment_dist/${webapp}"/><!-- 利用jdt編譯class 解決泛型不能轉換的問題 需要將jdtCompilerAdapter.jarorg.eclipse.jdt.compiler.tool_1.0.1.v_793_R33x.jarorg.eclipse.jdt.core_3.3.3.v_793_R33x.jarorg.eclipse.jdt.debug.ui_3.2.102.v20071002_r332.jar複製到ant_home/lib目錄下<property name="build.compiler" value="org.eclipse.jdt.core.JDTCompilerAdapter"/>--><path id="svnant.classpath"><fileset dir="${basedir}"><include name="**/*.jar"/></fileset></path><path id="buildpath"><fileset dir="${dest.path}"><include name="**/lib/*.jar"/></fileset><fileset dir="C:/Program Files/Java/jdk1.6.0_13"><include name="**/*.jar"/></fileset></path><typedef resource="org/tigris/subversion/svnant/svnantlib.xml" classpathref="svnant.classpath"/><svnSetting id="svn.settings" javahl="false" svnkit="true" username="${svn.username}" password="${svn.password}" failonerror="true"/><target name="init" description="init clean dirs"><echo message="${svn.username}"/><echo message="${svn.password}"/><echo message="${webapp}"/><echo message="${webroot}"/><echo message="${compare.path.file}"/><delete dir="${dest.path}" failonerror="false" deleteonexit="true" excludes="**/lib"/><delete dir="${dist.path}" failonerror="false" deleteonexit="true" excludes="**/lib"/><delete file="${compare.path.file}" failonerror="false"/><delete dir="${increment.dest.path}" failonerror="false" deleteonexit="true"/><delete dir="${increment.dist.path}" failonerror="false" deleteonexit="true"/></target><!-- that is to test i svnant is available //--><target name="tool-available" depends="init"><echo message="run task test svnant is available"></echo><available resource="org/tigris/subversion/svnant/svnantlib.xml" classpathref="svnant.classpath" property="available.svnant"/><echo message="SVN-ANT is available = ${available.svnant}"></echo></target><!-- 比較差異 增量檔案 --><target name="diff" description="deff/compare project"><svn refid="svn.settings"><diffSummarize oldUrl="${bak.svn.url}" newUrl="${svn.url}" outFile="${compare.path.file}" recurse="true"/></svn></target><!-- 下載 切成 匯出 伺服器上最新程式碼 --><target name="checkout" depends="tool-available" description="checkout/export project code ${svn.url} "><echo message="checkout/export project code ${svn.url}"></echo><svn refid="svn.settings"><export srcUrl="${svn.url}" destPath="${dest.path}" revision="HEAD" force="true"/></svn></target><!-- javac編譯 --><target name="compile"><buildnumber/><echo>compile ${dest.path} ......</echo><delete dir="${dist.path}" failonerror="false" deleteonexit="true" excludes="**/lib"/><mkdir dir="${dist.path}/classes"/><javac nowarn="true" debug="${javac.debug}" debuglevel="${javac.debuglevel}" destdir="${dist.path}/classes" source="${javac.source}" target="${javac.target}" encoding="utf-8" fork="true" memoryMaximumSize="512m" includeantruntime="false"><src path="${dest.path}/src"/><!--<compilerarg value="-Xlint:unchecked"/><compilerarg value="-Xlint:deprecation"/><compilerarg value="-Xlint"/>--><classpath refid="buildpath"/><classpath refid="svnant.classpath"/></javac></target><!-- 利用JDT編譯 --><target name="compile_jdt"><buildnumber/><echo>compile ${dest_path} ......</echo><delete dir="${dist_path}" failonerror="false" deleteonexit="true" excludes="**/lib"/><mkdir dir="${dist_path}/classes"/><javac compiler="org.eclipse.jdt.core.JDTCompilerAdapter" nowarn="true" debug="${javac.debug}" debuglevel="${javac.debuglevel}" destdir="${dist_path}/classes" source="${javac.source}" target="${javac.target}" encoding="utf-8" fork="true" memoryMaximumSize="512m" includeantruntime="false"><src path="${dest_path}/src"/><classpath refid="buildpath"/><classpath refid="svnant.classpath"/></javac></target><!-- 利用JDT編譯SVN 最新專案 --><target name="compile_svn"><!-- 回撥任務 --><antcall target="compile_jdt"><param name="dest_path" value="${dest.path}"/><param name="dist_path" value="${dist.path}"/></antcall></target><!-- 將全部專案的class 建立jar包 --><target name="jar" depends="compile_svn"><jar destfile="${basedir}/lib/${webapp}.jar" level="9" compress="true" encoding="utf-8" basedir="${dist.path}/classes"><manifest><attribute name="Implementation-Version" value="Version: 2.2"/></manifest></jar></target><!-- 匯出增量檔案 --><target name="increment" depends="diff"><java classname="com.hoo.util.ExportIncrementFiles" classpath="${basedir}/lib/increment.export.jar" fork="true"><arg value="${compare.path.file}"/><arg value="${dest.path}/"/><arg value="${increment.dest.path}/"/></java></target><!-- 利用JDT編譯增量檔案 --><target name="compile_increment"><antcall target="compile_jdt"><param name="dest_path" value="${increment.dest.path}"/><param name="dist_path" value="${increment.dist.path}"/></antcall></target><!-- 全部打包 --><target name="war"><echo>create war file.......</echo><copy todir="${dist_path}" failonerror="false"><fileset dir="${dest_path}/${webroot}" includes="**"/></copy><move todir="${dist_path}/WEB-INF/classes" failonerror="false"><fileset dir="${dist_path}/classes" /></move><copy todir="${dist_path}/WEB-INF/classes" failonerror="false"><fileset dir="${dest_path}/src/main/" includes="**/*.xml, **/*.properties, **/*.xsd"/><fileset dir="${dest_path}/src/test/" includes="**/*.xml, **/*.properties, **/*.xsd"/><fileset dir="${dest_path}/src/resource/" includes="**/*.xml, **/*.properties, **/*.xsd"/></copy><!--得到當前日期--><tstamp><format property="DSTAMP" pattern="yyyyMMdd" locale="zh"/><format property="TSTAMP" pattern="HHmmss" locale="zh"/></tstamp><war destfile="${basedir}/${webapp}_${DSTAMP}_${TSTAMP}.war" basedir="${dist_path}" webxml="${dist_path}/WEB-INF/web.xml"/></target><!-- 全部打包 --><target name="war_svn"><antcall target="war"><param name="dest_path" value="${dest.path}"/><param name="dist_path" value="${dist.path}"/></antcall></target><!-- 全部打包 --><target name="war_increment"><copy todir="${increment.dist.path}/WEB-INF" file="${dest.path}/${webroot}/WEB-INF/web.xml"/><antcall target="war"><param name="dest_path" value="${increment.dest.path}"/><param name="dist_path" value="${increment.dist.path}"/></antcall></target><!-- svn 全量包 --><target name="svn_war" depends="checkout, compile_svn, war_svn"/><!-- 增量包 --><target name="increment_war" depends="checkout, increment, jar, compile_increment, war_increment"/></project>
4、build的配置檔案內容
#Mon, 04 Nov 2013 11:18:12 +0800svn._url=http://172.31.100.100/svn/iMVS_DataComm2bak.svn._url=http://172.31.100.100/svn/iMVS_DataCommsvn.username=hoojosvn.password=mypasswebapp.name=iMVS_DataCommweb.root=WebRootincrement.file=patch.txtjavac.debuglevel=source,lines,varsjavac.target=1.6javac.source=1.6javac.debug=true
執行svn_war任務可以打全部的包,也就是svn最新地址的專案工程包。
執行increment_war任務可以打增量包,也會形成一個war檔案。
如果你需要釋出到tomcat目錄,可以寫一個任務copy相關war包到tomcat的webapps的目錄下,這個很簡單~如果你需要呼叫tomcat的相關任務或命令,你需要在build指令碼中加入
<target name="_def_tomcat_tasks"><!-- tasks: deploy,undeploy,reload,stop,start,list,roles,resources --><taskdef name="deploy" classname="org.apache.catalina.ant.DeployTask" /><taskdef name="list" classname="org.apache.catalina.ant.ListTask" /><taskdef name="reload" classname="org.apache.catalina.ant.ReloadTask" /><taskdef name="resources" classname="org.apache.catalina.ant.ResourcesTask" /><taskdef name="roles" classname="org.apache.catalina.ant.RolesTask" /><taskdef name="start" classname="org.apache.catalina.ant.StartTask" /><taskdef name="stop" classname="org.apache.catalina.ant.StopTask" /><taskdef name="undeploy" classname="org.apache.catalina.ant.UndeployTask" /></target>
關於這些命令使用方法有興趣的可以自己研究研究。
四、總結
整個流程稍微有點複雜,只要思路清晰這個build指令碼還是很容易編寫的。前提是你要懂得Java釋出、編譯、部署的流程,很多人用eclipse或MyEclipse來發布工程,好像很簡單。其實在工具背後也是使用這些指令碼完成的,知道在使用者目錄下有一個 .m2的目錄麼,這個就是eclipse工具的meven的快取和配置的內容。所以當我們不使用這些ide的情況下,你怎麼編譯、部署你的專案呢~!這篇文章只是一個拋磚引玉的效果,希望能給大家一個啟示。在這之前,我在網上搜集了些資料也沒有找到打增量包的比較好的方法,全都是手動方式。
同時,在一些自動整合或持續整合的智慧工具中,也大量的使用到了這方面的技術。如果你想更智慧的完成這個專案的釋出、部署的話,這裡只是其中的第一步。有興趣的朋友可以研究下Continuous integration或Hudson等相關自動化整合技術應用。