精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
作者 | 正文 | ||||||||||||||||||||||||||||||
发表时间:2008-10-03
使用Maven创建应用介绍将要创建的应用名叫Proficio,拉丁语的"help"。 设置应用程序的目录结构在设置Proficio的目录结构时,注意Maven强调的实践标准化和构建模块化构建是很重要的。 这种实践自然将产生分离的可重用的开发工程。决定如何最优化的分解应用的原则叫做“分离关注点(Separation of Concerns)”原则,即SoC原则。 SoC有助于识别、封装、操作于有相关特殊概念、目标、任务或目的的软件片段。关注点是组织和分解软件的动力,更多的易于管理和理解的部分,每个都用于说明一个或多个特定关注点。 如上所述,Proficio样例工程将被设置为多个Maven模块:
在Proficio的顶层POM中,可以看到所有子模块元素。一个模块指向另一个Maven工程,实际上它是指向另一个POM。Proficio的顶层POM文件如下: <project> <modelVersion>4.0.0</modelVersion> <groupId>com.devzuz.mvnbook.proficio</groupId> <artifactId>proficio</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <name>Maven Proficio</name> <url>http://maven.apache.org</url> [...] <modules> <module>proficio-model</module> <module>proficio-api</module> <module>proficio-core</module> <module>proficio-stores</module> <module>proficio-cli</module> </modules> [...] </project> 上面的版本号1.0-SNAPSHOT。对于一个有多模块的应用,通常将所有模块一起发布,所有模块使用一个公共的版本号。这是推荐的一种方式。 注意上面的packaging元素,这里它被设置为pom。对于包含模块的POM文件,packaging必须设置为pom:这告诉Maven你准备创建一个模块集。 Proficio应用的模块打包类型:
proficio-stores模块有两个子模块。 使用工程继承Maven最重要的功能之一就是工程继承。使用工程继承允许你在一个地方规定组织机构信息,规定部署信息,或规定通用的依赖。由Proficio工程产生的每个工程的POM文件,每个的顶部都有: [...] <parent> <groupId>com.devzuz.mvnbook.proficio</groupId> <artifactId>proficio</artifactId> <version>1.0-SNAPSHOT</version> </parent> [...] 这个片段允许你从指定的顶层的POM继承。顶层POM中指定了依赖JUnit 3.8.1。在这种情况下子工程中不再申明这个依赖也可以使用这个包。 为了了解在继承处理时发生的东西可以执行mvn help:effective-pom命令。这个命令将显示出最终的POM。在proficio的子工程中执行这个命令时可以看到依赖中出现了JUnit 3.8.1。 管理依赖关系Maven可以让不同的工程共享程序包。 可以在顶层的POM中描述所有子工程共享的依赖。 例如Proficio的顶层POM: <project> [...] <dependencyManagement> <dependencies> <dependency> <groupId>com.devzuz.mvnbook.proficio</groupId> <artifactId>proficio-model</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>com.devzuz.mvnbook.proficio</groupId> <artifactId>proficio-api</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>com.devzuz.mvnbook.proficio</groupId> <artifactId>proficio-store-memory</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>com.devzuz.mvnbook.proficio</groupId> <artifactId>proficio-store-xstream</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>com.devzuz.mvnbook.proficio</groupId> <artifactId>proficio-core</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.codehaus.plexus</groupId> <artifactId>plexus-container-default</artifactId> <version>1.0-alpha-9</version> </dependency> </dependencies> </dependencyManagement> [...] </project> 注意${project.version}指定了版本,它与应用的版本对应。 在dependencyManagement一节,有多个Proficio依赖并且还依赖于Plexus IoC container。dependencyManagment元素与顶层POM的dependencies有重要区别。 dependencyManagement元素中包括的dependencies元素仅用于说明引用的版本号,对并不影响工程的依赖关系图,然而顶层的dependencies元素将影响依赖关系图。查看proficio-api模块的POM将只看到引用而没有指定版本: <project> [...] <dependencies> <dependency> <groupId>com.devzuz.mvnbook.proficio</groupId> <artifactId>proficio-model</artifactId> </dependency> </dependencies> </project> 这个依赖的版本号是从Proficio的顶层POM文件的dependencyManagement继承过来的。 dependencyManagement指定了引用proficio-model的版本号为1.0-SNAPSHOT(被设置 为${project.version})这个版本号将注入到上面的依赖中。dependencyManagement中说明的dependencies 只用于当某个依赖没有版本号的情况。 使用快照当开发的应用具有多个模块时,通常每个模块的版本都在变更。API可能正在经历变迁或你的实现正在发生改变,或者在进 行重构。你在构建时需要非常容易的实时获取最新版本,这是Maven的快照(snapshot)的概念。快照是Maven的一个artifact。查看 Proficio的顶层POM可以看到指定了快照版本。 <project> [...] <version>1.0-SNAPSHOT</version> <dependencyManagement> <dependencies> <dependency> <groupId>com.devzuz.mvnbook.proficio</groupId> <artifactId>proficio-model</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>com.devzuz.mvnbook.proficio</groupId> <artifactId>proficio-api</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.codehaus.plexus</groupId> <artifactId>plexus-container-default</artifactId> <version>1.0-alpha-9</version> </dependency> </dependencies> </dependencyManagement> [...] </project>
解决依赖冲突和使用版本号范围在Maven 2.0中通过引入依赖传递,使得可以在简单的POM文件中只指定你直接需要的依赖,并且Maven可以计算出完整的依赖关系图。但是,随着图的增涨,不可 避免的将产生一个或多个artifacts需要依赖的不同版本。这种情况下,Maven必须选择使用哪个版本。 Maven通常选择这个关系树中顶层的“最接近的版本(nearest)”,Maven选择版本号跨度最小的版本。如果在POM中指定了版本,则将被使用而不管其它的原因。但这种方式也有下面的限制:
手工解决冲突,可以从依赖树中移除不正确的版本,或者可以用正确的版本来覆盖掉树中的版本。移除不正确的版本需要在运行Maven时指定-X标识来找出不正确的版本。例如,如果在proficio-core模块运行mvn -X test将输出: proficio-core:1.0-SNAPSHOT junit:3.8.1 (selected for test) plexus-container-default:1.0-alpha-9 (selected for compile) plexus-utils:1.0.4 (selected for compile) classworlds:1.1-alpha-2 (selected for compile) junit:3.8.1 (not setting scope to compile; local scope test wins) proficio-api:1.0-SNAPSHOT (selected for compile) proficio-model:1.0-SNAPSHOT (selected for compile) plexus-utils:1.1 (selected for compile) 这样可以找出当前操作所使用的详细版本信息,一旦找出了不正确的版本,你可以将它从依赖关系图中移除。例如,这个例子中,plexus-utils出现了 两次,Proficio需要1.1版。为确保这个依赖,可以修改plexus-container-default的依赖,例如: <dependency> <groupId>org.codehaus.plexus</groupId> <artifactId>plexus-container-default</artifactId> <version>1.0-alpha-9</version> <exclusions> <exclusion> <groupId>org.codehaus.plexus</groupId> <artifactId>plexus-utils</artifactId> </exclusion> </exclusions> </dependency> 这保证了Maven将忽略1.04版的plexus-utils,而使用1.1版。 另一种方法确保在依赖中使用特定版本,是将它直接包含在POM中,例: <dependencies> <dependency> <groupId>org.codehaus.plexus</groupId> <artifactId>plexus-utils</artifactId> <version>1.1</version> <scope>runtime</scope> </dependency> </dependencies> 但是这种方式是不被推荐的除非你是在制作一个绑定了自己的依赖的artifact,并且它自身不会作为一个依赖(例如,是一个WAR文件)。原因是这种做法歪曲了真实的依赖关系图,在工程自身作为依赖被重用时将导致问题。 在这里指定了runtime作用范围。这是因为,在这种情况下,依赖只是用于打包而不是编译。实际上,如果依赖是在编译时需要,它应该总是出现在当前POM的依赖中——而不管另一个依赖是否使用了它。 上面的这些解决都只是理想化的,但它可以提高你自己的依赖的质量,避免你在构建自己的产品时的风险。这一点在构建一个应用程序框架时是非常重要的,因为它将广泛的被其它人使用。为达到这个目标,可以使用版本范围来替代这种方式。 当上面的plexus-utils的版本被设置为1.1时,标明首选依赖的是1.1版,但其它版本可能也能够接受。Maven并不知道哪个版本可以 工作,因此当与其它依赖冲突时,Maven确保所有的版本使用前面描述的“最近依赖(nearest dependency)”技术来决定使用哪个版本。 但是,你可能需要一个plexus-utils 1.1版中的功能。这时,依赖应该指定为下面的形式: <dependency> <groupId>org.codehaus.plexus</groupId> <artifactId>plexus-utils</artifactId> <version>[1.1,)</version> </dependency> 这表示在版本冲突时仍将使用nearest dependency技术,但是版本号必须符合给定的范围。如果版本不匹配,则下一个最接近的版本将被测试,如此继续。最后,如果没有匹配的版本,或本来 就没有冲突,则使用指定的版本[1.1,)。这表示将从仓库中获取最小的版本号大于或等于1.1的版本。 版本范围范例表:
通过指定使用的版本范围,使得构建时依赖管理机制更加可靠并且减少异常的情况。但应该避免过度的详细。例如,如果两个版本范围依赖图不交叉,那么构建将失败。 为了解版本范围是如何工作的,需要了解版本是怎样进行比较的。下面展示了Maven是如何分割版本号的。 1.0.1-20060211.131141-1 从左至右依次为: 1为主版本号 0为次版本号 1为Bug修正号 20060211.131141为限定版本号 1为构建号 在目前的版本方案中,快照版本是一种特殊的情况,在这种情况下限定号和构建号可以同时存在。在正式版本中,可以只提供限定号或只提供构建号。有意设 置的限定号标识出了一个较优先的版本(例如:alpha-1,beta-1,rc1)。对于快照版本,限定号必须是文本“snapshot”或时间戳。构 建号是一个自增号在发布时标明是补丁构建。 版本中的元素依次决定哪个版本较新——首先是主版本号,如果主版本号相等,则比较次版本号,接下来是Bug修正号,限定号,最后比较构建号。带限定 号的版本比不带限定号的版本要旧;比如1.2-beta比1.2旧。包含了构建号的版本比不带构建号的版本新;比如1.2-beta-1比1.2- beta新。某些情况下,版本可能会不匹配这个语法。在这些情况下,两个版本号将作为字符串进行比较。 当使用快照版本测试编译发布版本或自己测试发布测试版本时应该将它们部署到快照仓库,这将在第七章讨论。这保证了在版本范围中的beta版本才会使用,除非工程显式的申明了使用快照版本。 最后要注意的是当使用版本范围时版本更新是如何被决定的。这个机制与前面介绍的快照版本更新机制是相同的,即每天从版本库中更新一次版本。但是,这可以通过配置每个仓库来设置更新的频率,或在命令行使用-U参数强制Maven执行更新。 例: <repository> [...] <releases> <updatePolicy>interval:60</updatePolicy> </releases> </repository> 利用构建生命周期第二章中将Maven描述为一个正确调整插件执行方式或顺序的应用框架,这实际上就是Maven的默认构建生命周期。 Maven默认的构建生命周期对于大多数工程来说不需要增加任何内容就可以满足了——当然,有时工程需要增加不同的内容到Maven的默认构生命周期来满 足构建的需求。 例如,Proficio需要从model生成Java源码。Maven通过允许申明插件来满足这个需求,将它绑定到Maven默认生命周期的一个标准阶段——generate-sources阶段。 Maven的插件是为特定任务而创建的,这意味着插件将被绑定到默认的生命周期的一个特定阶段。在Proficio中,Modello插件被用于生 成Proficio的数据模型的Java源码。查看proficio-model的POM可以看到plugins元素配置了Modello插件。 <project> <parent> <groupId>com.devzuz.mvnbook.proficio</groupId> <artifactId>proficio</artifactId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>proficio-model</artifactId> <packaging>jar</packaging> <name>Proficio Model</name> <build> <plugins> <plugin> <groupId>org.codehaus.modello</groupId> <artifactId>modello-maven-plugin</artifactId> <version>1.0-alpha-5</version> <executions> <execution> <goals> <goal>java</goal> </goals> </execution> </executions> <configuration> <version>1.0.0</version> <packageWithVersion>false</packageWithVersion> <model>src/main/mdo/proficio.mdo</model> </configuration> </plugin> </plugins> </build> </project> 这与第二章中maven-compiler-plugin的申明非常相似,但这里可以看到额外的execution元素。Maven中的插件可以有多个goal,因此你需要指定你希望运行插件的哪个goal,这可以通过在execution中的goal元素来指定。 使用ProfilesProfile是Maven提供的用于创建构建生命周期中的不同环境变量、不同的平台、不同JVM、不同的测试数据 库、或引用不同的本地文件系统的方法。通常你可以在POM中封装,以保证构建的可移植性,但有时你需要考虑变化的交叉系统的情况,这也是Maven中引入 profile的原因。 Profile使用POM中的一个子集元素来指定,可以用多种方式来启用。Profile在构建时修改POM,意味着它将用于给不同的目标环境中的参数集(比如,在开发环境、测试环境、产品环境下应用服务器根路径)不同参数值。 Profile也可以很容易的实现团队中不同成员生成不同的构建结果。也可以通过profile阻止构建的移植性。Profile可以定义在下面三个地方:
优先级依次为POM文件、profiles.xml、settings.xml。这也是Maven中的基本原则。 settings.xml中设置profile会影响所有的构建,因此它适合“全局”的profiles。profiles.xml允许设置单个工 程的构建而不用修改POM。基于POM的profiles是首选方式,因为这样更具有移植性(它们将在布署时发布到仓库,对于源于仓库的子构建或依赖来说 也同样有效)。 因为移植性的原因,那些不会发布到仓库中的文件不允许修改任何基础构建。因此,profiles.xml和settings.xml只允许定义:
其它的信息必须在POM的profile中指定或在POM自身指定。例如,如果settings.xml中有一个profile它可以注入一个依 赖,你的工程运行需要settings注入的依赖,一旦这个工程部部署到仓库中它将不能解决它的依赖。因为其中一个依赖设置在settings.xml的 profile中了。 注意:respositories、pluginRepositories和properties也可以在POM内部的profiles指定。因此,在POM外部指定的profiles只允许使用POM内部指定的profiles选项的一个小的子集。 可以在POM中定义的profile:
构建元素的子集,由下面组成:
有多种方法启用profiles:
mvn -Pprofile1,profile2 install
<settings> [...] <profiles> <profile> <id>profile1</id> [...] </profile> </profiles> <activeProfiles> <activeProfile>profile1</activeProfile> </activeProfiles> [...] </settings>
<profile> <id>profile1</id> [...] <activation> <jdk>1.4</jdk> </activation> </profile>
<profile> <id>profile1</id> [...] <activation> <property> <name>debug</name> </property> </activation> </profile>
<profile> <id>profile1</id> [...] <activation> <property> <name>environment</name> <value>test</value> </property> </activation> </profile>
在熟悉profiles后,可以使用它组装不同的Proficio系统:一个配置方案是memory-base存储,另一个是XStream-based存储。这些将在proficio-cli模块中使用。proficio-cli模块的profile定义如下: <project> [...] <!-- Profiles for the two assemblies to create for deployment --> <profiles> <!-- Profile which creates an assembly using the memory based store --> <profile> <id>memory</id> <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptors> <descriptor>src/main/assembly/assembly-store-memory.xml</descriptor> </descriptors> </configuration> </plugin> </plugins> </build> <activation> <property> <name>memory</name> </property> </activation> </profile> <!-- Profile which creates an assembly using the xstream based store --> <profile> <id>xstream</id> <build> <plugins> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <descriptors> <descriptor>src/main/assembly/assembly-store-xstream.xml</descriptor> </descriptors> </configuration> </plugin> </plugins> </build> <activation> <property> <name>xstream</name> </property> </activation> </profile> </profiles> </project> 可以看到两个profiles:一个id为memory另一个id为xstream。在每个profile中你可以配置插件。也可以看到profile通 过一个系统属性进行激活。这个例子依赖于前面已经执行过的一些构建步骤,因此应该先在工程的顶级目录执行mvn install确保需要的组件被安装到本地仓库。 如果想基于memory-based存储进行构建,可以执行: mvn -Dmemory clean assembly:assembly 如果想基于XStream-based存储进行,可以执行: mvn -Dxstream clean assembly:assembly 这两种方式构建的结果都保存在target目录中,如果对输出使用jar tvf命令,可以看到memory-base方式构建时只包含了proficio-store-memory-1.0-SNAPSHOT.jar,当使用 XStream-based方式时,只包含了proficio-store-xstream-1.0-SNAPSHOT.jar。 部署应用当前Maven支持多种部署方式包括文件系统部署、SSH2部署、SFTP部署、FTP部署和外部SSH部署。为了进行部署,需要正确的配置POM中的distributionManagement元素,通常是在顶级POM中,因为子POM可以继承这些信息。 文件系统部署<project> [...] <distributionManagement> <repository> <id>proficio-repository</id> <name>Proficio Repository</name> <url>file://${basedir}/target/deploy</url> </repository> </distributionManagement> [...] </project> SSH2部署<project> [...] <distributionManagement> <repository> <id>proficio-repository</id> <name>Proficio Repository</name> <url>scp://sshserver.yourcompany.com/deploy</url> </repository> </distributionManagement> [...] </project> SFTP部署<project> [...] <distributionManagement> <repository> <id>proficio-repository</id> <name>Proficio Repository</name> <url>sftp://ftpserver.yourcompany.com/deploy</url> </repository> </distributionManagement> [...] </project> 外部SSH部署前面三个部署方式是包含在Maven内部的,因此只需要distributionMangement元素,但使用外部SSH命令部署则还要使用一个构建扩展。 <project> [...] <distributionManagement> <repository> <id>proficio-repository</id> <name>Proficio Repository</name> <url>scpexe://sshserver.yourcompany.com/deploy</url> </repository> </distributionManagement> <build> <extensions> <extension> <groupId>org.apache.maven.wagon</groupId> <artifactId>wagon-ssh-external</artifactId> <version>1.0-alpha-6</version> </extension> </extensions> </build> [...] </project> 这个构建扩展指定使用Wagon外部SSH提供都,它将你的文件移动到远程服务器上。Wagon是Maven中通用的用于传送的机制。 FTP部署FTP部署也必须指定一个构建扩展。 <project> [...] <distributionManagement> <repository> <id>proficio-repository</id> <name>Proficio Repository</name> <url>ftp://ftpserver.yourcompany.com/deploy</url> </repository> </distributionManagement> <build> <extensions> <extension> <groupId>org.apache.maven.wagon</groupId> <artifactId>wagon-ftp</artifactId> <version>1.0-alpha-6</version> </extension> </extensions> </build> [...] </project> 一旦配置完POM后,可以执行 mvn deploy 进行部署。 为应用程序创建Web站点前面已经完成了Proficio的构建、测试、部署,现在可以为这个应用创建一个标准的Web站点。对于Procio这样的应,推荐在顶级目录创建用于生成站点的资源目录。 所有用于生成站点的文件保存在src/site目录。src/site目录中也有子目录保存支持文档。Maven支持大量同的文件格式。 当前支持得最好的格式:
Maven也有限的支持:
在后面的章节将了解支持较好的那些格式,但你应该熟悉下面的目标:
查看Proficio应用的src/site可以看到站点的描述: <project name="Proficio"> <bannerLeft> <name>Proficio</name> <href>http://maven.apache.org/</href> </bannerLeft> <bannerRight> <name>Proficio</name> <src>http://maven.apache.org/images/apache-maven project.png</src> </bannerRight> <skin> <groupId>org.apache.maven.skins</groupId> <artifactId>maven-default-skin</artifactId> <version>1.0-SNAPSHOT</version> </skin> <publishDate format="dd MMM yyyy" /> <body> <links> <item name="Apache" href="http://www.apache.org/"/> <item name="Maven" href="http://maven.apache.org/"/> <item name="Continuum" href="http://maven.apache.org/continuum"/> </links> <head><meta name="faq" content="proficio"/></head> <menu name="Quick Links"> <item name="Features" href="/maven-features.html"/> </menu> <menu name="About Proficio"> <item name="What is Proficio?" href="/what-is-maven.html"/> </menu> ${reports} </body> </project> 这是一个相当标准的Web站点描述,每个元素的说明如下:
Maven中最流行的功能之一就是花较少的功夫就可以生成标准的报表。只要简单的在站点描述中包含${reports}引用,默认情况下是包含的,工程信息报表将自动生成的被添加上来。标准的工程信息报表包含下面的内容:
尽管标准报表很有用,通常你需要自定义工程的报表。报表的创建和显示控制是在POM的build/reports元素中。你可以选择生成报表的信息,只要列举出需要包含在站点中的报表即可。这个插件的配置方式如下: <project> [...] <reporting> [...] <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-project-info-reports-plugin</artifactId> <reportSets> <reportSet> <reports> <report>dependencies</report> <report>project-team</report> <report>mailing-list</report> <report>cim</report> <!-- Issue tracking report will be omitted <report>issue-tracking</report> --> <report>license</report> <report>scm</report> </reports> </reportSet> </reportSets> </plugin> </plugins> [...] </reporting> [...] </project> 执行 mvn site 生成站点。 生成的站点放在target目录下。如果有其它的资源,如图片、PDF等可以存放在src/site/resources。当站点被生成时src/site/resources将被复制到站点的顶级目录。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|||||||||||||||||||||||||||||||
返回顶楼 | |||||||||||||||||||||||||||||||
浏览 3088 次