510 likes | 789 Vues
Antx 简介. Antx 的由来. 最早,我们用 Makefile 来 build 系统 Makefile 不适合 Java 的编译 后来,我们用 Ant 来 build 系统 开始时很不错 随着项目增多,出现困难 利用 beanshell 控制 Ant API ,将常用操作写成 plugin ,增加中心 repository 控制 即 Antx 1.0 简化了 Ant 的配置 但 beanshell-based plugin 很难掌握 利用 maven 1.0 中的 jelly 来控制 Ant API 即 Antx 2.0 简化了创建 plugin 的过程.
E N D
Antx的由来 • 最早,我们用Makefile来build系统 • Makefile不适合Java的编译 • 后来,我们用Ant来build系统 • 开始时很不错 • 随着项目增多,出现困难 • 利用beanshell控制Ant API,将常用操作写成plugin,增加中心repository控制 • 即Antx 1.0 • 简化了Ant的配置 • 但beanshell-based plugin很难掌握 • 利用maven 1.0中的jelly来控制Ant API • 即Antx 2.0 • 简化了创建plugin的过程
Antx和Ant • Ant是一套面向target的build系统 • Ant用户必须了解怎样做一件事,例如为了编译Java代码: <path id="classpath"> <fileset dir="${lib}" includes="*.jar"/> </path> <mkdir dir="${target.classes}"/> <javac srcdir="${src.java}" destdir="${target.classes}" debug="true" optimize="true" deprecation="true" encoding="GBK" source="1.4" target="1.4"> <classpath refid="classpath"/> </javac>
Antx和Ant • Antx是面向project的系统 • 用户不需要了解怎样build系统 • 用户只需要定义project • Project的目录结构 • Project所依赖的包 • Build选项,例如:用JDK1.4还是JDK5来编译 • 为了编译一个Java project,假设你的目录结构是符合标准的,你只需要打命令: antx java:compile
Antx的组成 • Plugin管理 • 目的是解决:How to do something? • 例如:java plugin解决了如何编译java代码 • 例如:war plugin解决了如何打war包 • 基本技术:基于Jelly script • 在Jelly中可直接使用任何Ant task • Project管理 • 目的是描述:What does the project look like? • 例如:源代码放在哪? • 例如:项目依赖哪些jar包? • 基本技术:纯XML描述(project.xml) • Repository管理 • 目标是管理:所有jar、war、ear等二进制包,及它们的依赖关系。
实战之前,先安装Antx • 前提条件 • JDK(推荐JDK5) • 设置JAVA_HOME环境变量 • 从SVN中checkout antx source svn co http://svn.alibaba-inc.com/repos/opentech/antx/trunk/ antx • 因为repository中包含很多第三方jar包,所以checkout需要一些时间 • Build antx source • 执行antx根目录下的build.bat或build.sh • 将antx/bin目录加入到PATH环境变量中 • 方便使用antx
定义一个简单的Antx项目:创建目录 • 先创建一个c:\myproject目录 • 在此目录下,创建标准的目录结构: antx gen • 目录结构如下: myproject │ project.jelly - 项目脚本文件 │ project.xml - 项目描述文件 │ ├─docs - 文档目录 │ └─src - 源代码目录 └─java - Java源代码目录
定义一个简单的Antx项目:修改project.xml • 修改项目描述文件:project.xml <project id="my/project"> <build> <dependencies> <include uri="jakarta/commons/lang"/> </dependencies> </build> </project>
定义一个简单的Antx项目:添加Java类 • 在src/java目录下, • 创建package: com\alibaba\myproject • 创建类文件:MyClass.java package com.alibaba.myproject; import org.apache.commons.lang.SystemUtils; public class MyClass { public String getGreeting() { return "hello, " + SystemUtils.USER_NAME; } }
定义一个简单的Antx项目:build项目 • 在myproject目录下, • 执行:antx jar java:compile: [mkdir] Created dir: C:\myproject\target\classes [javac] Compiling 1 source file to C:\myproject\target\classes jar:jar: [jar] Building jar: C:\myproject\target\my-project.jar • 设置默认的goal • 在project.jelly中设置: <project default="jar"> </project> • 执行:antx,效果同antx jar
定义一个简单的Antx项目:创建单元测试 • 在src/java.test目录下, • 创建package: com\alibaba\myproject • 创建类文件:MyClassTest.java package com.alibaba.myproject; import junit.framework.TestCase; public class MyClassTest extends TestCase { private MyClass myClass; protected void setUp() { myClass = new MyClass(); } public void testGetGreeting() { assertEquals("hello, " + System.getProperty("user.name"), myClass.getGreeting()); } }
定义一个简单的Antx项目:执行单元测试 • 在myproject目录下, • 执行:antx test [mkdir] Created dir: C:\myproject\target\test.report [junit] Running com.alibaba.myproject.MyClassTest [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
定义一个简单的Antx项目:用Eclipse来开发 • 在myproject目录下, • antx eclipse eclipse:project: [echo] Creating C:\myproject/.project ... eclipse:classpath: [echo] Creating C:\myproject/.classpath ... eclipse: [echo] 如果您现在正在使用eclipse,请在project上点击鼠标右键,选择“Refresh”以便刷新项目 • 在Eclipse中import项目 • 选择Existing projects into workspace
标准目标结构简介 myproject │ project.jelly - 项目脚本文件 │ project.xml - 项目描述文件 ├─docs - 文档目录 ├─src - 源目录 │ ├─descriptors - JEE描述符 │ │ ├─ear - application.xml │ │ ├─ejb - ejb-jar.xml │ │ ├─rar - ra.xml │ │ └─web - web.xml │ ├─java - Java代码目录 │ ├─java.test - Java测试代码目录 │ ├─conf - 配置文件目录 │ ├─conf.test - 用于测试的配置文件目录 │ └─webroot - Webapp根目录 │ ├─templates - webx模板目录 │ └─WEB-INF - 标准WEB-INF目录 └─target - 目标目录 └─classes - Java类二进制文件目录
中心Repository——项目的弹药库 • 重新看project.xml <dependencies> <include uri="jakarta/commons/lang"/> </dependencies> • 这个jakarta/commons/lang是什么意思? • 指向repository中的类库的URI • 全称为:jar:jakarta/commons/lang,类似还有:war:、ejb:、car:、ear:、rar: • 请看antx\repository\jakarta\commons\lang目录 • 其中的module.xml文件定义了jar包的位置、源代码、javadoc的位置、依赖性等信息。
项目之间的依赖:创建项目2 • 让我们创建另一个项目:myproject2 <project id="my/project2"> <build> <dependencies> <include uri="my/project"/> </dependencies> </build> </project>
项目之间的依赖:创建类 • 在src/java目录下, • 创建package: com\alibaba\myproject2 • 创建类文件:MyClass2.java package com.alibaba.myproject2; import com.alibaba.myproject.MyClass; public class MyClass2 { public static void main(String[] args) { System.out.println(new MyClass().getGreeting()); } }
项目之间的依赖:编译并运行 • 在myproject2目录下 • 执行:antx • 试运行命令: java –cp \myproject2\target\my-project2.jar; \myproject\target\my-project.jar; \antx\repository\jakarta\commons\lang\commons-lang-2.1.jarcom.alibaba.myproject2.MyClass2 • 结果:hello, baobao
project2怎么找到project1的jar呢? • 答案就是:通过repository • 请看$HOME\.antx\repository目录 • 有一个my\project\module.xml文件,告诉project2: • 去哪里取得uri="my/project"的jar包 • 注意: • 两个project的源目录之间没有任何关系 • 两个project只通过repository来通信 • 不得循环依赖 • project1必须在project2之前被build • project2间接依赖project1所依赖的一切
多项目开发模式的优点 • 鼓励划分模块 • 理顺依赖关系 • 二进制目标文件级的依赖——使开发者更专注于自己的项目 • 项目数量具备线性扩展性——项目数量的增加并不会增加单个项目的复杂度
改良多项目开发的模式 • 听起来不错,但在实际开发中存在问题 • 往往在一个大项目中,包含多个相关子项目 • 这些子项目通常一起编译、一起发布 • 如果项目A依赖项目B,当B修改后,必须先生成B.jar才能使A看到B所作的修改,这样很麻烦 • 对于这些关系较紧密的子项目,最好能够进行源码级的依赖。 • 一个项目往往依赖另一个team所开发的项目的成果 • 这种情况,应该使用二进制依赖 • 存在版本更新的问题 • 如何方便地build多个项目?
改良多项目开发的模式:三级repository • 第一级(所谓的1st party类库) • 位置:$HOME\.antx\repository • 用于关联关系较紧密的子项目 • 例如:同一个team在同一时间开发的若干子项目 • 该repository的内容只存在于本地,不需要被共享 • 第二级(所谓的2nd party类库) • 位置(默认):$HOME\.antx\repository.project • 用于关联关系较疏远的子项目 • 例如:不同team或不同时期开发的子项目 • 该repository的内容需要被team间共享 • 该repository的内容通常需要注明版本号 • 第三级(所谓的3rd party类库) • 位置:antx\repository • 用于定义第三方提供的类库 • 例如:Apache Jakarta类库 • 该repository随着antx更新而更新 • 该repository中的内容可以被注明版本号,也可以不注
2nd party repository • 可以在$HOME\antx.properties中改变默认值: antx.repository.project=YOUR_2ND_REPO_PATH • 取得toolkit类库 • 进入$HOME\.antx\repository.project目录(或者你所指定的YOUR_2ND_REPO_PATH目录) • 执行: svn co http://svn.toolkit.alibaba-inc.com/trunk/binary-release/toolkit • 在项目中使用toolkit • 在project.xml中写: <dependencies> <include uri="toolkit/webx/turbine"/> </dependencies>
改良多项目开发的模式:推荐的多项目目录结构改良多项目开发的模式:推荐的多项目目录结构 • 以Taobao网站为例(红色代表子项目,其中包含project.xml和project.jelly文件) taobao │ project.xml - 总控项目描述文件 │ ├─common - 共享utils子项目 │ └─utildefault goal:jar ├─dal - 数据访问层子项目,default goal:jar ├─biz - 业务层子项目 │ ├─auctiondefault goal:jar,deps:common/dal,common/util │ └─memberdefault goal:jar,deps:common/dal,common/util ├─web - WEB表现层子项目 │ ├─auctiondefault goal:car,deps:biz/auction │ └─memberdefault goal:car,deps:biz/member ├─bundle - 将所有项目打成一个war或ear的子项目 │ └─wardefault goal:war,deps:car:web/auction,car:web/member └─deploy - 布署环境子项目 default goal:deploy,deps:war:bundle/war
改良多项目开发的模式:简化project.xml • 一组相关的子项目,通常会有类似的项目定义 • 为了简化,可以这样写: <project id="taobao/dal" extends="../project.xml"> <build> <dependencies> … </dependencies> </build> </project>
改良多项目开发的模式:总控project.xml <project id="taobao/all" abstract="true"> <currentVersion>1.0</currentVersion> <build> <property name="java.compiler.source" value="1.5"/> <property name="java.compiler.target" value="1.5"/> </build> <projects name="taobao" version="1.0"> <project id="taobao/common/util" dir="common/util"/> <project id="taobao/dal" dir="dal"/> <project id="taobao/biz/auction" dir="biz/auction"/> <project id="taobao/biz/member" dir="biz/member"/> <project id="taobao/web/auction" dir="web/auction"/> <project id="taobao/web/member" dir="web/member"/> <project id="taobao/bundle/war" dir="bundle/war"/> <project id="taobao/deploy" dir="deploy"/> </projects> <projects name="toolkit-common" version="1.0"> <project id="toolkit/common/lang"/> ... </projects> <projects name="toolkit-webx" version="2.0"> <project id="toolkit/webx/framework"/> ... </projects> </project>
改良多项目开发的模式:build所有项目 • 在总项目的根目录下,执行: antx reactor • 反应堆:reactor,也可以理解为foreach project • 自动扫描目录,找出所有非abstract的project.xml • 分析其中的依赖关系,排出build顺序 • 例如:项目A依赖项目B,则B排在A之前 • 依次执行每个项目的build指令 • Reactor命令的格式 antx reactor goals=指令1,指令2,… projects=项目ID1,项目ID2,… nodeps=true|false • goals参数代表要对每个项目执行的指令, • 如果省略或值为“default”表示执行project.jelly中定义的default goal。 • projects参数代表要build的项目ID, • 如果省略,表示build所有项目。 • 注意,项目所依赖的项目也会被build,除非指定了nodeps=true。 • nodeps=true时,不build项目所依赖的其它项目。 • 你必须自己负责依赖关系。 • 如果省略,表示nodeps=false。
改良多项目开发的模式:在eclipse中开发多项目改良多项目开发的模式:在eclipse中开发多项目 • 利用antx reactor goals=eclipse,default命令生成所有子项目的eclipse项目文件 • 将所有子项目导入到eclipse中,最好创建一个working set • 凡在总控项目中同属一组的项目,都会被看作源码依赖 • 列在Project Properites中的Java Build Path > Projects中 • i.e.,项目A依赖A项目B,如果B的源代码被修改,不需要重新build B,A可直接取得B的修改 • 反之,则被看作二进制依赖 • 列在Project Properites中的Java Build Path > Libraries中
改良多项目开发的模式:reactor命令举例 • Build所有项目 antx reactor • 清除并重新build所有项目 antx reactor goals=clean,default • 生成/更新所有项目的eclipse项目文件 antx reactor goals=eclipse,default • 手工build指定项目(忽略依赖关系) antx reactor projects=project1,project2 nodeps=true • 发布所有项目 antx –p RELEASE reactor
改进Antx的性能 • Antx启动很慢,是什么原因? • 装载repository • 装载project • 解决方案 • Lazy-loading repository • 已解决 • Antx Console • antx –c • 原理很简单:执行完后不退出,第二次执行就很快了 • 使用Antx eclipse插件 • http://svn.alibaba-inc.com/repos/opentech/antxclipse/trunk/update/index.html • 原理同Antx Console
Antx Console的使用方法 • 查看帮助:help help|? - 帮助 quit|exit - 退出 antx - 执行antx命令 list|ls/dir - 列出所有项目 cd <project id|..|/> - 跳转至当前项目|上一级项目|根项目 load <project dir|*> - 装入指定目录下的项目|所有项目 profile <name> - 设置profile section <name> - 设置section
Antx Console的使用方法 • antx –c reactor • 执行完正常的reactor后,进入console模式 • 执行list命令可列出所有项目 • 用cd命令可进入指定项目 • antx –c • 直接进入console模式,不执行任何命令 • 此时内存中没有项目,欲装入所有项目,可执行antxreactor或antx reactor:list命令 • 直接装入某个项目的方法 • 进入console模式以后,执行: • load project_dir
Antx plugin简介 • 请看:$HOME\.antx\plugin目录 • 每一个目录代表一个plugin • 每个plugin定义了一组相关的操作方法 • 定义在plugin.jelly文件中 • 例如:antx-java定义了编译java的方法 • 例如:antx-jar定义了打jar包的方法 • 每个plugin定义了一组默认值 • 定义在project.xml文件中的<projectDefault>标签中 • 例如:antx-java定义了java.compiler.source的默认值是1.4,也就是说,如果项目的project.xml中不加指定,将以JDK1.4兼容的方式来编译源码。 • 查看该目录下plugin的源文件,是了解一个plugin功能、默认值的最佳方法。
Plugin: antx-clean • antx clean • 清除target目录 • 清除docs\api目录 • 清除docs\api.test目录
Plugin: antx-xar • antx jar|war|ear|rar|ejb|car|uberjar • jar —— 将java类打包 • war —— Java EE Web Application包 • ear —— Java EE Enterprise Application包 • rar —— Java EE Java Connector Adapter包 • ejb —— Java EE EJB包 • 类似jar, • 但对于特定服务器,可能会激发额外操作,例如weblogic:ejbc • car —— Webx Component包, • 结构类似war, • 但缺少WEB-INF/lib、WEB-INF/web.xml • 多个car可组合成一个war • uberjar —— 特殊的jar, • 利用classloader技术,将所有的依赖打包在一个普通的jar里,使之可单独执行 • 目前有严重的性能问题,有待改进
Plugin: antx-java • antx java • 编译Java源代码
Plugin: antx-test • antx test • 运行所有单元测试类 • 结果记录在target/test.report目录中
Plugin: antx-forrest • antx forrest • 根据docs\xdocs中的XML文档,在docs\site中生成HTML静态文档 • antx forrest:clean • 清除docs\site目录 • antx forrest:run • 运行jetty server,动态显示XML文档 • antx forrest:sync • 将当前编辑的XML文档同步到正在运行的jetty server中 • antx forrest:demo • 生成示范文档
Plugin: antx-gen • antx gen • 生成标准的目录结构 • antx gen:basic-test • 生成带单元测试的标准目录结构 • antx gen:car|ejb|ear|war|rar • 生成相应类型项目的标准目录结构
Plugin: antx-javadoc • antx javadoc • 生成API文档,在docs\api和docs\api.test目录下
Plugin: antx-plugin • antx plugin • 创建plugin jar包 • antx plugin:install • 安装plugin,使之可用
Plugin: antx-reactor • antx reactor • 前面已经介绍过了
Plugin: antx-eclipse • antx eclipse • 生成eclipse项目文件,包括: • .project • .classpath
Plugin: antx-config • antx config uris=… • 自动生成Xar包中的配置文件 • 解决什么问题: • 前面已经讲过,利用二进制发布应用的好处 • 然而带来一个问题:如果二进制发布包中包含一些个性化参数怎么办? • 例如:IP、域名、目录名、端口、用户名等 • 这些参数对每个人、每个运行环境都有可能不同 • 将这些参数固定在配置文件中显然不合适,应该自动生成 • 问题是自动生成必须发生在打包前,这和二进制发布的流程相矛盾 • Antx-config功能解决了这个问题: • 先发布,后配置 • 程序员提供配置的模板、变量名、变量的限定条件 • 配置员(要使用二进制发布的人)提供变量的值,并接受限定条件的检查 • 系统结合模板和变量值,生成个性化配置文件。 • 整个过程可以递归到每一层包中(ear中包含war,war中又包含jar)
Plugin: antx-config • 创建src/java/META-INF/autoconf/auto-config.xml <?xml version="1.0" encoding="gb2312"?> <config description="自动配置:my-project"> <group name="myproject"> <property name="myproject.workdir" description="工作目录"/> <property name="myproject.domain" defaultValue="localhost" description="用来访问myproject应用的一级域名"> <validator name="hostExist"/> </property> <property name="myproject.port" defaultValue="8080" description="用来访问myproject应用的端口"> <validator name="number"/> </property> </group> <script> <generate template="myconf.xml.vm" destfile="myconf.xml" charset="GBK"/> </script> </config>
Plugin: antx-config • 创建src/java/META-INF/autoconf/myconf.xml.vm <myconf> <workdir>$myproject_workdir</workdir> <url>http://www.$myproject_domain:$myproject_port/</url> </myconf> • Build并配置 • antx jar • antx config uris=my/project
执行自己的脚本 • 修改project.jelly <project default="jar"> <goal name="deploy" prereqs="jar,config"/> </project> • 修改project.xml <build> <property name="uris" value="my/project"/> … </build> • 执行:antx deploy