多种问题 一种解决方案:使用ANT管理部署应用服务器

    ANT在Java界和开源世界里面的地位大家都知道,虽然ANT在近年来不断受到Maven和一切其他工具的冲击,但仍然占据着统治地位,虽然Maven声称自己能为开发真提供更多的东西,但是貌似习惯ANT的人根本就不需要再增加什么功能,也就更省去一项学习成本,尤其是Maven在2系列发布以后不再像以往那样好评如潮,甚至出现质疑,使得我们更加安于现状的使用ANT :P.

    我这几年一共只使用过Tomcat、Weblogic和WebSphere这三个算是极为主流的应用服务器,它们也都为ANT提供了原生的支持,这样使得我在切换应用服务器部署的时候几乎不用耗费太多的精力去研究部署的问题(实际上使用Weblogic和WebSphere提供的一些更高级的功能还是会遇到麻烦,下文中会提到)。这样轻量级而又高效的工具谁不喜欢呢?我在这里除了把ANT管理三种应用服务器的配置文件给出还会结合我的一些实际排错经验,也希望有兴趣的朋友能够指出错误。

 

    利用ANT可以形成一个完整而清晰的工作模式,由专人构建好一个开发环境,并写出ANT脚本,提交到版本服务器,Team成员拿到ANT脚本以后执行ANT checkout tasks,开始工作。服务器上ANT脚本定期运行更新、同步服务器代码,让测试人员可以最快的模拟生产环境进行测试工作。

    按照习惯,一般都会把ANT的资源文件抽取出来命名为build.properties与build.xml放在同一目录下,我没有在文中给出,并不代表它不重要,个人认为一个好的ANT脚本是否能将build.properties这个文件写好是至关重要的,因为一个build.xml一般由团队的一个人负责写好Team使用就可以,大家不用关心里面的实现过程,只要保证每个人拿到这两个文件在本机上修改build.properties,然后执行ANT Tasks就可以开始干活,使得ANT自动化做到最佳。一般来说不是每个ANT属性都需要抽取出来,所以build.proerties里面应该包含的是经常需要变化如url、本机ID等等,再加上适当的注释即可。

1.Tomcat

   一般来说Tomcat的部署是最容易的,甚至以前我们部署的时候就仅仅是用war包扔到webapps目录下就收工,但是这对一个软件的生命周期管理是很不合理的,所以不要认为它简单就不用,它对后期维护产品是很重要的一个环节。

 

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project basedir="." default="init" name="${project.name}">
	<property file="./build.properties" />
	<property environment="env" />
	<property name="tomcat.home" value="${env.TOMCAT_HOME}" />
	<property name="debuglevel" value="source,lines,vars" />
	<property name="build.dir" value="${basedir}/build" />
	<property name="build.classes.dir" value="${build.dir}/classes" />

	<path id="classpath">
		<pathelement location="${tomcat.home}/common/lib/servlet-api.jar" />
		<pathelement location="${tomcat.home}/common/lib/jasper-runtime.jar" />
		<pathelement location="${tomcat.home}/common/lib/jsp-api.jar" />
		<pathelement location="${build.classes.dir}" />

		<fileset dir="${lib.dir}">
			<include name="**/*.jar" />
		</fileset>
	</path>

	<target name="init">
		<mkdir dir="WEB-INF/classes" />
		<taskdef name="install" classname="org.apache.catalina.ant.InstallTask">
			<classpath>
				<path location="${tomcat.home}/server/lib/catalina-ant.jar" />
			</classpath>
		</taskdef>

		<taskdef name="deploy" classname="org.apache.catalina.ant.DeployTask">
			<classpath>
				<path location="${tomcat.home}/server/lib/catalina-ant.jar" />
			</classpath>
		</taskdef>
		<taskdef name="undeploy" classname="org.apache.catalina.ant.UndeployTask">
			<classpath>
				<path location="${tomcat.home}/server/lib/catalina-ant.jar" />
			</classpath>
		</taskdef>
		<taskdef name="remove" classname="org.apache.catalina.ant.RemoveTask">
			<classpath>
				<path location="${tomcat.home}/server/lib/catalina-ant.jar" />
			</classpath>
		</taskdef>
		<taskdef name="reload" classname="org.apache.catalina.ant.ReloadTask">
			<classpath>
				<path location="${tomcat.home}/server/lib/catalina-ant.jar" />
			</classpath>
		</taskdef>
		<taskdef name="start" classname="org.apache.catalina.ant.StartTask">
			<classpath>
				<path location="${tomcat.home}/server/lib/catalina-ant.jar" />
			</classpath>
		</taskdef>
	</target>

	<target name="clean">
		<echo>----clean in ${project.name}----</echo>
		<delete dir="${build.classes.dir}" failοnerrοr="false" />
	</target>

	<target name="checkout">
		<echo>----checkout in ${project.name}----</echo>
		<echo>----checkout in tag ${cvs.tag}----</echo>
		<cvs cvsRoot="${cvs.root}" package="${cvs.package}" tag="${cvs.tag}" dest="." failοnerrοr="true" />
	</target>

	<target name="compile">
		<echo>----build in ${project.name}----</echo>
		<mkdir dir="${build.classes.dir}" />
		<echo>----compile src----</echo>
		<javac srcdir="${src.dir}" destdir="${build.classes.dir}" debug="on" optimize="off">
			<classpath>
				<path refid="classpath" />
			</classpath>
		</javac>
		<!--Copy resouces by manual-->
		<copy todir="${build.classes.dir}/">
			<fileset dir="${src.dir}" includes="*.properties" />
		</copy>
	</target>

	<target name="pack" depends="compile">
		<echo>build ${project.name}.war in ${project.name}</echo>
		<war destfile="${build.dir}/${project.name}.war" webxml="${src.dir}/../WEB-INF/web.xml">
			<classes dir="${build.classes.dir}" />
			<zipfileset dir="${src.dir}/../WEB-INF/jsp" prefix="WEB-INF/jsp">
				<include name="**/*.*" />
			</zipfileset>
			<!-- 添加所有项目需要的资源文件到这里,以下省略 -->
			<lib dir="${lib.dir}/" />
		</war>
	</target>
	<target name="install" description="Install application in Tomcat" depends="init,pack">
		<deploy url="${tomcat.manager.url}" username="${tomcat.manager.username}" password="${tomcat.manager.password}" path="/${webapp.name}" war="${build.dir}/${project.name}.war" />
	</target>
	<target name="remove" description="Remove application from Tomcat" depends="init">
		<undeploy url="${tomcat.manager.url}" username="${tomcat.manager.username}" password="${tomcat.manager.password}" path="/${webapp.name}" />
	</target>
</project>

 这是一个几乎没啥悬念的ANT配置文件,你去网上搜可以搜一大堆,因为在Tomcat上面几乎没有进行什么额外的操作,所以一个部署不外乎clean、compile、uninstall和install这些动作,简单的连基本的注释和echo都省略掉。在最早接触ANT的时候,这样一个帮你干体力活的东西你似乎总是找不到使用的理由,本来就可有可无嘛,Eclipse不全都给你做好了么,干嘛还花心思写脚本呢。不过这种疑问在大家在远程主机上部署过一次程序以后就再也不觉得ANT是多余的东西,人总是在不断学习和摸索中进步么。

 

2.Weblogic(参考:http://www.chinaitpower.com/2006Aug/2006-08-10/211545.html

    由于有项目机会,使用了一年的Weblogic,而且是在办公室控制几十公里外客户机房里面的服务器,让我真正的喜欢上了ANT,使用Tomcat的时候都只是发布一些Web应用,千篇一律,所以Weblogic上部署Web应用的部分我省掉,这次是在上面部署一个WebService应用

 

<?xml version="1.0" encoding="UTF-8"?>
<project name="iptv_wls_ws" default="all" basedir=".">
	<property environment="env" />

	<property file="./build.properties" />
	<property name="build.compiler" value="modern"/>
	<property name="src.dir" value="src"/>
	<property name="lib.dir" value="webapp/WEB-INF/lib"/>
	<property name="build.dir" value="build"/>
	<property name="applications.dir" value="${build.dir}/applications" />
	<property name="clientslib.dir" value="${build.dir}/clientslib"/>

	<property name="bea.home" value="${env.WL_HOME}"/>
	<property name="wls.dir" value="${bea.home}/server"/>
	<property name="wlslib.dir" value="${wls.dir}/lib"/>
	<property name="wlsext.dir" value="${wls.dir}/ext"/>

	<path id="classpath">
	<dirset dir="${build.dir}/classes">
		<include name="**"/>
	</dirset>
	<fileset dir="${wlslib.dir}">
		<include name="**/weblogic.jar"/>
		<include name="**/webservices.jar"/>
	</fileset>
	<fileset dir="${lib.dir}">
	    <include name="*.jar"/>
	</fileset>
	</path>
	
	<property name="javac.fork" value="no"/>
	<property name="javac.debug" value="no"/>
	<property name="javac.optimize" value="on"/>
	<property name="javac.listfiles" value="yes"/>
	<property name="javac.failonerror" value="yes"/>

	<target name="clean">
		<delete dir="${build.dir}"/>
	</target>

	<target name="mdir">
		<mkdir dir="${build.dir}"/>
		<mkdir dir="${build.dir}/classes"/>
		<mkdir dir="${build.dir}/autotype"/>
		<mkdir dir="${build.dir}/applications"/>
		<mkdir dir="${build.dir}/clientslib"/>
		<mkdir dir="${build.dir}/wsddfiles"/>
	</target>
	
	<target name="compile" depends="clean,mdir">
		<javac encoding="UTF-8" srcdir="${src.dir}" destdir="${build.dir}/classes">
			<classpath refid="classpath"/>
		</javac>
		<copy todir="${build.dir}/classes">
			<fileset dir="${src.dir}">
				<include name="*.xml"/>
				<include name="*.properties"/>
			</fileset>
		</copy>
	</target>

	<!-- 在WebService中构建自定义类型,以便WebService通过POJO创建XML文件格式 -->
	<target name="gentypeinfo" depends="compile">
		<autotype javatypes="demo.model.ModelName"
				encoding="soap"
				targetNamespace="${namespace}"
				packageName="demo.test"
				destDir="${build.dir}/autotype"
				keepGenerated="true">
			<classpath refid="classpath"/>
		</autotype>
		<copy todir="${build.dir}/classes">
			<fileset dir="${build.dir}/autotype">
				<include name="**/*.class"/>
			</fileset>
		</copy>
	</target>

	<!--使用Weblogic的WebService转换包生成标准WebService所需要的文件-->
	<target name="genwsdd" depends="gentypeinfo">
		<source2wsdd javaSource="${src.dir}/demo/ws/NewWS.java"
				typesInfo="${build.dir}/autotype/types.xml"
				ddFile="${build.dir}/wsddfiles/web-services.xml"
				wsdlFile="${build.dir}/wsddfiles/NewWS.wsdl"
				serviceURI="/NewWS">
			<classpath refid="classpath"/>
		</source2wsdd>
	</target>

	<!--生成测试用的客户端-->
	<target name="genclient" depends="genwsdd">
		<clientgen wsdl="${build.dir}/wsddfiles/NewWS.wsdl"
				packageName="client"
				clientJar="${clientslib.dir}/NewWS_clients.jar"
				keepGenerated="true">
			<classpath refid="classpath"/>
		</clientgen>
	</target>

	<target name="genwar" depends="genwsdd">
		<war destfile="${applications.dir}/NewWS.war" webxml="webapp/WEB-INF/web.xml">
			<classes dir="${build.dir}/classes"/>
			<fileset dir="${build.dir}/classes" includes="*.properties"/>
			<lib dir="webapp/WEB-INF/lib"/>
			<webinf dir="${build.dir}/wsddfiles">
				<include name="web-services.xml"/>
			</webinf>
			<webinf dir="webapp/WEB-INF">
				<include name="weblogic.xml"/>
			</webinf>
		</war>
	</target>

	<target name="genear" depends="genwar">
		<ear destfile="${applications.dir}/NewWS.ear" appxml="ddfiles/application.xml">
			<fileset dir="${build.dir}/applications" includes="*.war"/>
		</ear>
	</target>

        <target name="deploy" depends="genear">
                 <wldeploy
                                action="deploy"
                                verbose="true"
                                debug="true"
                                name="${weblogic.deploy.webservice.name}"
                          source="${applications.dir}/NewWS.ear"
                          user="${weblogic.manager.username}"
                          password="${weblogic.manager.password}"
                          adminurl="${weblogic.manager.url}"
                          targets="${weblogic.target.server}" />
        </target>

        <target name="undeploy">
                <wldeploy
                                action="undeploy" verbose="true" debug="true"    
                                name="${weblogic.deploy.webservice.name}"
                                user="${weblogic.manager.username}"
                                password="${weblogic.manager.password}"
                                adminurl="${weblogic.manager.url}"
                                targets="${weblogic.target.server}"
                                failοnerrοr="false" />
        </target>

</project>

 

 

这个ANT Tasks明显要复杂一些,但是也不难理解,仅仅是使用WebLogic提供的一些WebService工具生成一些符合WebService规范的文件,毕竟是商业化产品,它提供的WS支持肯定是没得说,同时也说明ANT的适用范围实在是太广泛,它可以帮你勤勤恳恳而且准确的做好很多任务,你的工作只是合理组织好资源启动ANT Tasks然后喝口咖啡等待Build Successful的通知。

 

3.WebSphere(参考:http://www.blogjava.net/Unmi/archive/2007/12/19/168750.html

                                 http://www-1.ibm.com/support/docview.wss?uid=swg21113221

   在经过上面两种应用服务器的洗礼之后,我逐渐离不开ANT,似乎在接受新的项目以后没有ANT我做什么东西都没信心,所以在新近接触的基于WebSphere的项目中我第一个感兴趣的任务就是ANT。不知道IBM为何产品那么难用(来自很多人的心声),还能卖的那么好,而且可以占领那么大份额的市场(最近一次看好像中间件市场WebSphere占的比重超过37%哦),所以这个ANT脚本异常的耗费时间,为了写好这个ANT Tasks,真是搜遍互联网、DeveloperWork以及IBM RedBooks。因为系统中涉及到EJB,部署过程中不再是简单的发布一下,更多的要依赖IBM提供的wsadmin工具进行配置管理(实际使用ANT进行调用),这对于不熟悉WebSphere生态环境的我来说无疑是一次考验,不过在调试过程中真的有令人着魔的感觉,写写ANT会让你得到与写其他程序代码不一样的快感 :P。

<?xml version="1.0" encoding="UTF-8"?>
<project name="Setup WAS Server">
	<property file="setupWASServer.properties" />
	<property file="build.properties" />
	<property name="was.install.root" value="C:/Progra~1/IBM/SDP70/runtimes/base_v61" />
	<property name="user.install.root" value="C:/Progra~1/IBM/SDP70/runtimes/base_v61" />
	
	<path id="j2ee.server.classpath">
		<fileset dir="${j2ee.server.location}/lib">
			<include name="**/*.jar"/>
		</fileset>
		<fileset file="${j2ee.server.location}/plugins/com.ibm.ws.runtime_6.1.0.jar">
			<include name="**/*.jar"/>
		</fileset>
	</path>
	
	<path id="j2ee.server.antpath">
		<fileset file="${j2ee.server.location}/plugins/com.ibm.ws.runtime_6.1.0.jar" />
	</path>
	
	<target name="wsTask">
		<taskdef name="wsStopApp" classname="com.ibm.websphere.ant.tasks.StopApplication" classpathref="j2ee.server.classpath" />
		<taskdef name="wsUninstallApp" classname="com.ibm.websphere.ant.tasks.UninstallApplication" classpathref="j2ee.server.classpath" />
		<taskdef name="wsInstallApp" classname="com.ibm.websphere.ant.tasks.InstallApplication" classpathref="j2ee.server.classpath" />
		<taskdef name="wsStartApp" classname="com.ibm.websphere.ant.tasks.StartApplication" classpathref="j2ee.server.classpath" />
		<taskdef name="wsAdmin" classname="com.ibm.websphere.ant.tasks.WsAdmin" classpathref="j2ee.server.classpath" />
		<taskdef name="wsStopServer" classname="com.ibm.websphere.ant.tasks.StopServer" classpathref="j2ee.server.classpath" />
		<taskdef name="wsStartServer" classname="com.ibm.websphere.ant.tasks.StartServer" classpathref="j2ee.server.classpath" />
	</target>	
	
	<!-- Stop Server -->
	<target name="stopServer" depends="wsTask" description="Stop Websphere Server">
		<echo>Stopping Student Hub WAS Server</echo>
		<wsStopServer
			server="${j2ee.server.instance}"
			nowait="false"
			quiet="false"
			replaceLog="false"
			trace="true"
			timeout="3000"
			conntype="${j2ee.server.conntype}"
			port="${j2ee.server.port}"
			wasHome="${j2ee.server.location}/profiles/${j2ee.server.profile}/bin"
			failοnerrοr="true"
		/>
	</target>
		
	<!-- Start Server -->
	<target name="startServer" depends="wsTask" description="Start Websphere Server">
		<echo>Starting Student Hub WAS Server - ${was.install.root}</echo>
		<wsStartServer
			server="${j2ee.server.instance}"
			nowait="false"
			quiet="false"
			replaceLog="false"
			trace="true"
			timeout="3000"
			wasHome="${j2ee.server.location}"
		/>
	</target>
	
	<target name="start" depends="wsTask" description="Start Websphere Server">
		<exec dir="." executable="${j2ee.server.location}/bin/startServer.bat">
	 		<arg value="server1" />
		</exec>
	</target>
	
	<property name="app.war.loadpolicy" value="SINGLE" />
	<property name="app.reload.enabled" value="true" />
	<property name="app.reload.interval" value="20" />
	<property name="app.class.load.mode" value="PARENT_LAST" />
	<property name="startApp.pu"  
		        value="$AdminControl invoke [$AdminControl queryNames type=ApplicationManager,process=server1,*] startApplication ${app.name}"/>
	<property name="setDeployments"  
		        value="set deployments [$AdminConfig getid /Deployment:${app.name}/]"/>
	<property name="setDeploymentsObject"  
		        value="set deploymentObject [$AdminConfig showAttribute $deployments deployedObject]"/>
	<property name="modifyWarClassLoaderPolicy"  
		        value="$AdminConfig modify $deploymentObject {{warClassLoaderPolicy SINGLE}}"/>
	<property name="setClassLoaderMode"
					value="set classloader [$AdminConfig showAttribute $deploymentObject classloader]" />
	<property name="modifyClassLoaderMode"  
		        value="$AdminConfig modify $classloader {{mode ${app.class.load.mode}}}"/>
	
	<target name="listapps" depends="wsTask" description="List installed Enterprise Applications">
		<!-- List all installed Enterprise Application the profile specified. -->
		<taskdef name="wsListApps" classname="com.ibm.websphere.ant.tasks.ListApplications" classpathref="j2ee.server.classpath" />
		<wsListApps 
			profilename="${j2ee.server.profile}" 
			wasHome="${j2ee.server.location}" 
			conntype="${j2ee.server.conntype}" 
			host="${j2ee.server.name}" 
			port="${j2ee.server.port}" 
			user="${j2ee.server.username}" 
			password="${j2ee.server.password}" />
	</target>
	
	<target name="wsSetWarLoadPolicy" depends="wsTask" description="set war load policy ${app.war.loadpolicy}">
		<echo>change WAR Classloader Policy {SINGLE=Application, MULTIPLE=Module} to ${app.war.loadpolicy}</echo>
		<wsAdmin  
			profilename="${j2ee.server.profile}" 
			user="${j2ee.server.username}"   
			command="${setDeployments};${setDeploymentsObject};${modifyWarClassLoaderPolicy}"
			password="${j2ee.server.password}" 
			host="${j2ee.server.name}"  
			conntype="${j2ee.server.conntype}" 
			port="${j2ee.server.port}" 
			wasHome="${j2ee.server.location}" >
        </wsAdmin> 
	</target>
	
	<target name="wsSetClassLoaderMode" depends="wsTask" description="set classloader mode to ${app.class.load.mode}">
		<echo>change class load moode to ${app.class.load.mode}</echo>
		<wsAdmin  
			profilename="${j2ee.server.profile}" 
			user="${j2ee.server.username}"   
			command="${setDeployments};${setDeploymentsObject};${setClassLoaderMode};${modifyClassLoaderMode}"
			password="${j2ee.server.password}" 
			host="${j2ee.server.name}"  
			conntype="${j2ee.server.conntype}" 
			port="${j2ee.server.port}" 
			wasHome="${j2ee.server.location}" >
        </wsAdmin> 
	</target>
	
	<target name="wsInstallApp" depends="wsTask" description="Install Application ${app.name}">  
		<wsInstallApp 
			profilename="${j2ee.server.profile}" 
			wasHome="${j2ee.server.location}" 
			ear="${root}/modules/${app.name}UIApp/deployment/puEar.ear" 
			conntype="${j2ee.server.conntype}" 
			host="${j2ee.server.name}" 
			port="${j2ee.server.port}" 
			user="${j2ee.server.username}" 
			password="${j2ee.server.password}"
			options="-appname ${app.name} -usedefaultbindings -reloadEnabled ${app.reload.enabled} -reloadInterval ${app.reload.interval} -BindJndiForEJBNonMessageBinding {{ puEJB Mgr puEjb.jar,META-INF/ejb-jar.xml pu/MgrHome }}}" 
			failοnerrοr="true" />
	</target>
	
	<target name="wsStartApp" depends="wsTask" description="Start Application ${app.name}">  
	        <echo>Start Application ${app.name} on server1.pu with wsadmin: ${startApp.pu}</echo>
		<wsAdmin  
			profilename="${j2ee.server.profile}" 
			user="${j2ee.server.username}"   
			command="${startApp.pu}"
			password="${j2ee.server.password}" 
			host="${j2ee.server.name}"  
			conntype="${j2ee.server.conntype}" 
			port="${j2ee.server.port}" 
			wasHome="${j2ee.server.location}" >
	        </wsAdmin>
	</target>
	
	<target name="uninstallapp" depends="wsTask" description="Uninstall an Enterprise Application">
		<wsUninstallApp 
			profilename="${j2ee.server.profile}" 
			wasHome="${j2ee.server.location}" 
			application="${app.name}" 
			conntype="${j2ee.server.conntype}" 
			host="${j2ee.server.name}" 
			port="${j2ee.server.port}" 
			user="${j2ee.server.username}" 
			password="${j2ee.server.password}" 
			failοnerrοr="false" />
	</target>

	<!-- 实际组合任务 -->
	<target name="installAndStart" description="Install and Start ${app.name}">  
		<antcall target="wsInstallApp"/>
		<antcall target="wsSetWarLoadPolicy" />
		<antcall target="wsSetClassLoaderMode" />
		<antcall target="wsStartApp"/>  
	</target>
</project>

   在这个相对更为复杂的ANT Tasks里面,我们可以更多的发现有关wsadmin的影子,因为我们在部署依赖容器的项目时必须要进行必要的配置,那么WebSphere下面就需要wsadmin或者自己定义Jython管理脚本,这样就更显示出原生支持的威力:WebSphere为的ANT工具包为开发者提供完整的管理接口,开发者则可以利用这样的管理接口完整的实现对容器的控制。但是强大的开发接口还提高了对开发者的要求:你至少要了解wsadmin的基本管理或者Jython开发接口,并且对WebSphere的容器目录结构以及属性有所了解。

    这个ANT脚本写成耗时很长,这里给出一些我的调试错误经历:

    1)在调用wsadmin的时候,一定要增加profile这个参数,它是用来指定你的project部署在的实际位置,而文档上并没有标注该配置项被必须,结果我在这里浪费了不少时间,因为在ANT里面执行这个任务它除了给出两行wsadmin执行动作命令的提示以外不会做任何事情,然后你就一直对着屏幕发呆……

    2)了解wsadmin是在做什么对于完成这个ANT Tasks至关重要,因为你如果你不知道它在干什么那你也就无从下手,所以可以考虑先去找这个文件:$WS_HOME/profiles/$APP_SER_NAME/log/$SER_NAME/commandAssistanceJythonCommands_admin.log,这个日志文件是记录你在ADMIN_CONSOLE点击配置的时候系统实际生成的Jython命令,这样如果你不知道你在控制台做的操作到底干的什么,就来查这个日志文件,比如里面比较多的AdminApp.list(),这样你再略微转化下就是可以执行的wsadmin命令(如果你是用Jython作批量任务那就更方便了)。

    3)wsadmin命令参数有很多,特别是对于deploymentObjects这个对象,一个CELL里面的所有东西都会包含在一个叫deployment.xml的文件里面,你在控制台里面配置什么东西其实就是修改这个文件(多数属性在此),起初不知道只能在控制台里面呼$Help,但那可想而知有多困难,后来废了不少周折找到这个文件,发现wsadmin一直就在忙乎着改这个文件,一目了然,你想改什么改改命令参数就可以,一切变得如此通透。

   这个ANT Tasks里面还有一个让我好气又好笑的antcall命令:ANT1.6.3版本以后增加的任务,以往大家要实现组合任务,基本都是写depends, 而我比较笨,在网上抄来的脚本(看看上面的代码就知道多数我都是抄来的),没有写我也不写,然后浪费很多时间在那里自己执行ant clean,ant compile。其实1.6.3版本我们也早就有使用过,只是网上互相抄来抄去的代码都不知道是什么年代的范本,导致我干了很多愚蠢的工作,正所谓“尽信书不如无书”,在信息海洋里面还得多点自己的识别能力,原创是提高这种识别能力一种方法。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值