Ant的“宏”- macrodef
案例
<target name="ejbca:install" depends="check:bootstrapdone, ejbca:init" description="Install">
<echo message="Initializing CA with ${ca.name} '${ca.dn}' ${ca.tokentype} ${ca.tokenpassword} ${ca.keyspec} ${ca.keytype} ${ca.validity} ${ca.policy} ${ca.signaturealgorithm} ${ca.tokenproperties}..."/>
<ejbca:cli name="ca" arg='init "${ca.name}" "${ca.dn}" ${ca.tokentype} ${ca.tokenpassword} ${ca.keyspec} ${ca.keytype} ${ca.validity} ${ca.policy} ${ca.signaturealgorithm} ${ca.tokenproperties}'/>
</target>
<echo message="Initializing CA with ${ca.name} '${ca.dn}' ${ca.tokentype} ${ca.tokenpassword} ${ca.keyspec} ${ca.keytype} ${ca.validity} ${ca.policy} ${ca.signaturealgorithm} ${ca.tokenproperties}..."/>
<ejbca:cli name="ca" arg='init "${ca.name}" "${ca.dn}" ${ca.tokentype} ${ca.tokenpassword} ${ca.keyspec} ${ca.keytype} ${ca.validity} ${ca.policy} ${ca.signaturealgorithm} ${ca.tokenproperties}'/>
</target>
<macrodef name="cli" uri="ejbca">
<attribute name="name"/>
<attribute name="arg"/>
<sequential>
<echo message="@{name} @{arg}"/>
<java classname="[email protected]{name}" classpathref="classpath" fork="true">
<arg line="@{arg}"/>
</java>
</sequential>
</macrodef>
相关资料
假设 web 应用程序拥有依赖于目标系统的不同的 web 部署描述符,并为开发环境使用了一个不同的 JSP 集合以及一个不同的资料库集合。配置信息将放在属性中,创建 web 存档的任务看起来将类似于
<target name="war" depends="jar">
<war destfile="${war.name}"
webxml="${web.xml}">
<lib refid="support-libraries"/>
<lib file="${jar.name}"/>
<fileset dir="${jsps}"/>
</war>
</target>
<war destfile="${war.name}"
webxml="${web.xml}">
<lib refid="support-libraries"/>
<lib file="${jar.name}"/>
<fileset dir="${jsps}"/>
</war>
</target>
其中 support-libraries 是引用一个在其它位置定义的 <fileset> ,该引用指向您的应用程序所需的附加资料库的一个公共集合。
如果您只想一次创建一个 web 存档,那么您只需要正确地设置属性。比如说,您可以从一个您的目标专有的属性文件中加载它们。
利用 Ant 1.5 创建存档
现在,假定您想为测试系统和生产系统同时创建存档,以确保您真正为两个系统打包了相同的应用程序。利用 Ant 1.5,您可能使用 <antcall> 来调用拥有不同属性设置的 "war" 目标,类似:
<target name="production-wars">
<antcall target="war">
<param name="war.name" value="${staging.war.name}"/>
<param name="web.xml" value="${staging.web.xml}"/>
</antcall>
<antcall target="war">
<param name="war.name" value="${production.war.name}"/>
<param name="web.xml" value="${production.web.xml}"/>
</antcall>
</target>
<antcall target="war">
<param name="war.name" value="${staging.war.name}"/>
<param name="web.xml" value="${staging.web.xml}"/>
</antcall>
<antcall target="war">
<param name="war.name" value="${production.war.name}"/>
<param name="web.xml" value="${production.web.xml}"/>
</antcall>
</target>
当然,这假定两个目标系统都将使用相同的 jar 和 JSP。
但这种方法有一个主要缺点 — 就是速度慢。<antcall> 重新分析编译文件,并为每一次调用重新运行调用的目标所依赖的所有目标。在上面的例子中,"jar" 目标将被运行两次。我们希望这对第二次调用没有影响,因为 "war" 目标依赖于它。
利用 Ant 1.6 创建存档
使用 Ant 1.6,您可以忘掉用 <antcall> 来实现宏的方法,相反您可以通过参数化现有的任务来创建一个新的任务。因而上面的例子将变为:
<macrodef name="makewar">
<attribute name="webxml"/>
<attribute name="destfile"/>
<sequential>
<war destfile="@{destfile}"
webxml="@{webxml}">
<lib refid="support-libraries"/>
<lib file="${jar.name}"/>
<fileset dir="${jsps}"/>
</war>
</sequential>
</macrodef>
<attribute name="webxml"/>
<attribute name="destfile"/>
<sequential>
<war destfile="@{destfile}"
webxml="@{webxml}">
<lib refid="support-libraries"/>
<lib file="${jar.name}"/>
<fileset dir="${jsps}"/>
</war>
</sequential>
</macrodef>
这定义了一个名称为 makewar 的任务,该任务可以和任何其它的任务一样使用。该任务有两个必需的属性,webxml 和 destfile。要使属性可选,我们必需在任务定义中提供一个默认值。这个示例假定 ${jar.name} 和 ${jsps} 在编译期间为常量,从而它们仍然作为属性指定。注意,属性在使用任务时展开而不是在定义宏的地方展开。
所用任务的特性几乎完全和属性一样,它们通过 @{} 而不是 ${} 展开。与属性不同,它们是可变的,也就是说,它们的值可以(并将)随着每一次调用而改变。它们也只在您的宏定义程序块内部可用。这意味着如果您的宏定义还包含了另一个定义了宏的任务,那么您内部的宏将看不到包含的宏的属性。
于是新的 production-wars 目标将类似于:
<target name="production-wars">
<makewar destfile="${staging.war.name}"
webxml="${staging.web.xml}"/>
<makewar destfile="${production.war.name}"
webxml="${production.web.xml}"/>
</target>
<makewar destfile="${staging.war.name}"
webxml="${staging.web.xml}"/>
<makewar destfile="${production.war.name}"
webxml="${production.web.xml}"/>
</target>
这个新的代码段不仅执行得快一些,而且也更易读,因为属性名称提供了更多的信息。
宏任务还可以定义嵌套的元素。<makewar> 定义中的 <war> 任务的嵌套 <fileset> 可以是这种嵌套元素的一种。可能开发目标需要一些额外的文件或想从不同的位置中挑选 JSP 或资源。以下代码段将一个可选的嵌套 <morefiles> 元素添加到了 <makewar> 任务中
<macrodef name="makewar">
<attribute name="webxml"/>
<attribute name="destfile"/>
<element name="morefiles" optional="true"/>
<sequential>
<war destfile="@{destfile}"
webxml="@{webxml}">
<lib refid="support-libraries"/>
<lib file="${jar.name}"/>
<fileset dir="${jsps}"/>
<morefiles/>
</war>
</sequential>
</macrodef>
<attribute name="webxml"/>
<attribute name="destfile"/>
<element name="morefiles" optional="true"/>
<sequential>
<war destfile="@{destfile}"
webxml="@{webxml}">
<lib refid="support-libraries"/>
<lib file="${jar.name}"/>
<fileset dir="${jsps}"/>
<morefiles/>
</war>
</sequential>
</macrodef>
调用将类似于:
<makewar destfile="${development.war.name}"
webxml="${development.web.xml}">
<morefiles>
<fileset dir="${development.resources}"/>
<lib refid="development-support-libraries"/>
</morefiles>
</makewar>
webxml="${development.web.xml}">
<morefiles>
<fileset dir="${development.resources}"/>
<lib refid="development-support-libraries"/>
</morefiles>
</makewar>
这就像 <morefiles> 的嵌套元素直接在 <war> 任务内部使用的效果一样。
即使迄今为止的示例仅显示了包装单个任务的 <macrodef>,但它不限于此。
下面的宏不仅将创建 web 存档,还将确保包含最终存档的目录在试图写入之前存在。在一个实际的编译文件中,您可能在调用任务之前使用一个设置目标来完成这个操作。
<macrodef name="makewar">
<attribute name="webxml"/>
<attribute name="destfile"/>
<element name="morefiles" optional="true"/>
<sequential>
<dirname property="@{destfile}.parent"
file="@{destfile}"/>
<mkdir dir="${@{destfile}.parent}"/>
<war destfile="@{destfile}"
webxml="@{webxml}">
<lib refid="support-libraries"/>
<lib file="${jar.name}"/>
<fileset dir="${jsps}"/>
<morefiles/>
</war>
</sequential>
</macrodef>
<attribute name="webxml"/>
<attribute name="destfile"/>
<element name="morefiles" optional="true"/>
<sequential>
<dirname property="@{destfile}.parent"
file="@{destfile}"/>
<mkdir dir="${@{destfile}.parent}"/>
<war destfile="@{destfile}"
webxml="@{webxml}">
<lib refid="support-libraries"/>
<lib file="${jar.name}"/>
<fileset dir="${jsps}"/>
<morefiles/>
</war>
</sequential>
</macrodef>
这里注意两件事情:
首先,特性在属性展开之前展开,因此结构 ${@{destfile}.parent} 将展开一个名称包含了 destfile 特性的值和 ".parent" 后缀的属性。这意味着您可以将特性展开嵌入到属性展开中,而不是将属性展开嵌入特性展开中。
其次,这个宏定义了属性,该属性的名称基于一个特性的值,因为 Ant 中的属性是全局的并且不可改变。第一次尝试使用
<dirname property="parent" file="@{destfile}"/>
相反将不会在 "production-wars" 目标中的第二次 <makewar> 调用产生期望的结果。第一次调用将定义一个新的名称为 parent 的属性,该属性指向父目录 ${staging.war.name}。第二次调用将查看这个属性但不会修改它的值。
提示:如果您查看您的编译文件时发现使用了 <antcall> 代替宏,那么强烈建议您考虑使用 macrodef 将其转换成真正的宏。性能影响可能非常显著,并且还可能产生更易读和更易于维护的编译文件。
©著作权归作者所有:来自51CTO博客作者danni505的原创作品,如需转载,请注明出处,否则将追究法律责任
0
收藏
推荐专栏更多
猜你喜欢
我的友情链接
Oracle数据库下的大数据表做分区以提高数据读取效率
Java线程:线程的调度-休眠
我们不得不面对的中年职场危机
职场终极密籍--记我的职业生涯
用光影魔术手制作一寸照片(8张一寸)
我的IT职场生涯: 毕业4年,月薪过万
Linux关闭休眠和屏保模式
年薪从0到10万-我的IT职场经验总结
Windows7删除休眠文件hiberfil.sys节省大量C盘空间
致IT同仁 — IT人士常犯的17个职场错误
“跳槽加薪”现象,无奈的职场规则
Spring Boot 中 10 行代码构建 RESTful 风格应用
Java核心库实现AOP过程
RabbitMQ如何保证队列里的消息99.99%被消费?
几种简单的负载均衡算法及其Java代码实现
RabbitMQ如何保证消息99.99%被发送成功?
IT兄弟连 JavaWeb教程 经典案例
在阿里架构师眼中构建一个较为通用的业务技术架构就是如此简单
Spring Boot 整合 Mybatis 的完整 Web 案例
扫一扫,领取大礼包
转载于:https://blog.51cto.com/danni505/174508
Ctrl+Enter 发布
发布
取消