首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件开发 >

【转】java项目构基建工具Maven

2013-09-29 
【转】java项目构建工具Mavenjava项目构建工具Maven-----------------------------------------------------

【转】java项目构建工具Maven

java项目构建工具Maven
---------------------------------------------------------------
title:java project build tool is great maven
author:chinayaosir
blog:http://blog.csdn.net/chinayaosir
qq:44633197
email:chinayaosir@126.com
---------------------------------------------------------------
文章目录

1.1java-maven简介
1.2java-maven来源
1.3java-maven安装
1.4java-maven插件
1.5java-maven命令
1.6java-maven入门

1.7java-maven书籍

---------------------------------------------------------------

1.1java-maven简介
c/c++软件自动编译有makefile,
程序源码管理有cvs,subverion,
linux应用程序管理yum,yast(它们自动管理程序版本和依赖)
windows程序管理有360软件管理
java源码编译有ant,
那么java项目工程里在有没有jar包管理和源码管理,程序编译三合一的优秀工具?
它就是伟大的maven!!!!

随着近两年Maven在国内的普及,越来越多的公司与项目开始接受并使用其作为项目构建与依赖管理工具,
Java开发人员用Maven来管理和维护java软件项目就越来越方便!
Apache Maven是一个基于java的apache ant的构建工具的替代者。
Maven这个单词来自于意第绪语,意为知识的积累,
最早在Jakata Turbine项目中它开始被用来试图简化构建过程。
当时有很多项目,它们的Ant build文件仅有细微的差别,而JAR文件都由CVS来维护。
于是Maven创始者开始了Maven这个项目,该项目的清晰定义包括,
一种很方便的发布项目信息的方式,以及一种在多个项目中共享JAR的方式。


作为Apache组织中的一个颇为成功的开源项目,Maven主要服务于基于Java平 台的项目构建、依赖管理和项目信息管理。
无论是小型的开源类库项目,还是大型的企业级应用;无论是传统的瀑布式开发,还是流行的敏捷模式,Maven都能大显身手。

---------------------------------------------------------------
1.2java-maven来源
--------------------------------------------------
java构建
不管你是否意识到,构建(build)是每一位程序员每天都在做的工作。
早上来 到公司,我们做的第一件事情就是从源码库签出最新的源码,然后进行单元测试,
如果发现失败的测试,会找相关的同事一起调试,修复错误代码。
接着回到自己的 工作上来,编写自己的单元测试及产品代码,我们会感激IDE随时报出的编译错误提示。
忙到午饭时间,代码编写得差不多了,测试也通过了,开心地享用午餐然后休息。
下午先在昏昏沉沉中开了个例会,会议结束后喝杯咖啡继续工作。
刚才在会上经理要求看测试报告,于是找了相关工具集成进IDE,
生成了像 模像样的测试覆盖率报告,接着发了一封电子邮件给经理,松了口气。
谁料QA小组又发过来了几个bug,没办法,先本地重现再说,于是熟练地用IDE生成了 一个WAR包,部署到Web容器下,启动容器。
看到熟悉的界面了,遵循bug报告,一步步重现了bug……快下班的时候,bug修好了,提交代码,
通知 QA小组,在愉快中结束了一天的工作。
仔细总结一下,我们会发现,除了编写源代码,
我们每天有相当一部分时间花在了编译、运行单元测试、生成文档、打包和部署等烦琐且不起眼的工作上,这就是构建。
如果我们现在还手工这样做,那成本也太高了,于是有人用软件的方法让这一系列工作完全自动化,
使得软件的构建可以像全自动流水线一样,只需要一条简单的命令,所有烦琐的步骤都能够自动完成,很快就能得到最终结果。
--------------------------------------------------
Ant就是参考c make的makefle
Ant不是指蚂蚁,而是意指“另一个整洁的工具”(Another Neat Tool),
它最早用来构建著名的Tomcat,其作者James Duncan Davidson创作它的动机就是因为受不了Makefile的语法格式。
我们可以将Ant看成是一个Java版本的Make,也正因为使用了Java,Ant是跨平台的。
此外,Ant使用XML定义构建脚本,相对于Makefile来说,这也更加友好。
与Make类似,Ant有一个构建脚本build.xml,如下所示:
<target name="compile" description="compile the Java source code to class files">
<mkdir dir="classes"/>
<javac srcdir="." destdir="classes"/>
</target>
<target name="jar" depends="compile" description="create a Jar file ">
<jar destfile="hello.jar">
<fileset dir="classes" includes="**/*.class"/>
<manifest>
<attribute name="Main.Class" value="HelloProgram"/>
</manifest>
</jar>
</target>
</project>
build.xml的基本结构也是目标(target)、依赖(depends),以及实现目标的任务。
比如在上面的脚本中,jar目标用来创建应用程序jar文件,该目标依赖于compile目标,
后者执行的任务是创建一个名为classes的文件夹,编译当前目录的java文件至classes目录。
compile目标完成后,jar目标再执行自己的任务。
Ant有大量内置的用Java实现的任务,这保证了其跨平台的特质,同时,Ant也有特殊的任务exec来执行本地命令。
和Make一样,Ant也都是过程式的,开发者显式地指定每一个目标,以及完成该目标所需要执行的任务。
针对每一个项目,开发者都需要重新编写这一过程,这里其实隐含着很大的重复。
Maven是声明式的,项目构建过程和过程各个阶段所需的工作都由插件实现,
并且大部分插件都是现成的,开发者只需要声明项目的基本元素,Maven就执行内置的、完整的构建过程。这在很大程度上消除了重复。
Ant是没有依赖管理的,所以很长一段时间Ant用户都不得不手工管理依赖,这是一个令人头疼的问题。
幸运的是,Ant用户现在可以借助Ivy管理依赖。
而对于Maven用户来说,依赖管理是理所当然的
Maven不仅内置了依赖管理,更有一个可能拥有全世界最多Java开源软件包的中央仓库,
Maven用户无须进行任何配置就可以直接享用。
--------------------------------------------------
maven与ant的比较
第一:ant脚本是可以直接运行在maven中的。?
<project xmlns="http://maven.apache.org/POM/4.0.0"?
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"?
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0?
http://maven.apache.org/maven-v4_0_0.xsd">?
<modelVersion>4.0.0</modelVersion>?
<groupId>com.juvenxu.mvnbook</groupId>?
<artifactId>hello-world</artifactId>?
<version>1.0-SNAPSHOT</version>?
<name>Maven Hello World Project</name>?
<dependencies>?
<dependency>?
<groupId>junit</groupId>?
<artifactId>junit</artifactId>?
<version>4.7</version>?
<scope>test</scope>?
</dependency>?
</dependencies>?
</project>?

代码中添加了dependencies元素,该元素下可以包含多个dependency元素以声明项目的依赖,
这里我们添加了一个依赖——groupId是junit,artifactId是junit,version是4.7。
前面我们提到groupId、artifactId和version是任何一个Maven项目最基本的坐标,
JUnit也不例外,有了这段声明,Maven就能够自动下载junit-4.7.jar。
也许你会问,Maven从哪里下载这个jar呢?在Maven之前,我们可以去JUnit的官网下载分发包。
而现在有了Maven,它会自动访问中央仓库(http://repo1.maven.org/maven2/),下载需要的文件。
读者也可以自己访问该仓库,打开路径junit/junit/4.7/,就能看到junit-4.7.pom和junit-4.7.jar。
上述POM代码中还有一个值为test的元素scope,scope为依赖范围,
若依赖范围为test则表示该依赖只对测试有效,换句话说,测试代码中的import JUnit代码是没有问题的,
但是如果我们在主代码中用import JUnit代码,就会造成编译错误。
如果不声明依赖范围,那么默认值就是compile,表示该依赖对主代码和测试代码都有效。
配置了测试依赖,接着就可以编写测试类,
回顾一下前面的HelloWorld类,现在我们要测试该类的sayHello()方法,
检查其返回值是否为“Hello Maven”。在src/test/java目录下创建文件,
其内容如代码清单3-4:
代码清单3-4:Hello World的测试代码
Java代码?
package com.juvenxu.mvnbook.helloworld;?
import static org.junit.Assert.assertEquals;?
import org.junit.Test;?
public class HelloWorldTest?
{?
@Test?
public void testSayHello()?
{?
HelloWorld helloWorld = new HelloWorld();?

String result = helloWorld.sayHello();?

assertEquals( "Hello Maven", result );?
}?
}?

一个典型的单元测试包含三个步骤:
一,准备测试类及数据;
二,执行要测试的行为;
三,检查结果。
上述样例中,我们首先初始化了一个要测试的HelloWorld实例,
接着执行该实例的sayHello()方法并保存结果到result变量中,
最后使用JUnit框架的Assert类检查结果是否为我们期望的”Hello Maven”。
在JUnit 3中,约定所有需要执行测试的方法都以test开头,这里我们使用了JUnit 4,
在JUnit 4中,需要执行的测试方法都应该以@Test进行标注。
测试用例编写完毕之后就可以调用Maven执行测试,运行 mvn clean test :
Java代码?
[INFO] Scanning for projects...?
[INFO] ------------------------------------?
[INFO] Building Maven Hello World Project?
[INFO] task-segment: [clean, test]?
[INFO] ------------------------------------?
[INFO] [clean:clean {execution: default-clean}]?
[INFO] Deleting directory D:\git-juven\mvnbook\code\hello-world\target?
[INFO] [resources:resources {execution: default-resources}]?
Downloading: http://repo1.maven.org/maven2/junit/junit/4.7/junit-4.7.pom?
1K downloaded (junit-4.7.pom)?
[INFO] [compiler:compile {execution: default-compile}]?
[INFO] Compiling 1 source file to D: \code\hello-world\target\classes?
[INFO] [resources:testResources {execution: default-testResources}]?
Downloading: http://repo1.maven.org/maven2/junit/junit/4.7/junit-4.7.jar?
226K downloaded (junit-4.7.jar)?
[INFO] [compiler:testCompile {execution: default-testCompile}]?
[INFO] Compiling 1 source file to D:\ code\hello-world\target\test-classes?
[INFO] ------------------------------------?
[ERROR] BUILD FAILURE?
[INFO] ------------------------------------?
[INFO] Compilation failure?
D:\code\hello-world\src\test\java\com\juvenxu\mvnbook\helloworld\HelloWorldTest.java:[8,5] -source 1.3 中不支持注释?
(请使用 -source 5 或更高版本以启用注释)?
@Test?
[INFO] ------------------------------------?
[INFO] For more information, run Maven with the -e switch?
…?


不幸的是构建失败了,不过我们先耐心分析一下这段输出(为了本书的简洁,一些不重要的信息我用省略号略去了)。
命令行输入的是mvn clean test,而Maven实际执行的可不止这两个任务,
还有clean:clean、resources:resources、compiler:compile、resources:testResources以及compiler:testCompile。
暂时我们需要了解的是,在Maven执行测试(test)之前,
它会先自动执行项目主资源处理,主代码编译,测试资源处理,测试代码编译等工作,
这是Maven生命周期的一个特性,本书后续章节会详细解释Maven的生命周期。
从输出中我们还看到:Maven从中央仓库下载了junit-4.7.pom和junit-4.7.jar
这两个文件到本地仓库(~/.m2/repository)中,供所有Maven项目使用。
构建在执行compiler:testCompile任务的时候失败了,Maven输出提示我们需要使用-source 5或更高版本以启动注释,
也就是前面提到的JUnit 4的@Test注解。这是Maven初学者常常会遇到的一个问题。
由于历史原因,Maven的核心插件之一compiler插件默认只支持编译Java 1.3,
因此我们需要配置该插件使其支持Java 5,见代码清单3-5:
代码清单3-5:配置maven-compiler-plugin支持Java 5
Java代码?
<project>?
…?
<build>?
<plugins>?
<plugin>?
<groupId>org.apache.maven.plugins</groupId>?
<artifactId>maven-compiler-plugin</artifactId>?
<configuration>?
<source>1.5</source>?
<target>1.5</target>?
</configuration>?
</plugin>?
</plugins>?
</build>?
…?
</project>?

该POM省略了除插件配置以外的其他部分,我们暂且不去关心插件配置的细节,只需要知道compiler插件支持Java 5的编译。
现在再执行mvn clean test,输出如下:
Java代码?
…?
[INFO] [compiler:testCompile {execution: default-testCompile}]?
[INFO] Compiling 1 source file to D: \code\hello-world\target\test-classes?
[INFO] [surefire:test {execution: default-test}]?
[INFO] Surefire report directory: D:\code\hello-world\target\surefire-reports?
-------------------------------------------------------?
T E S T S?
-------------------------------------------------------?
Running com.juvenxu.mvnbook.helloworld.HelloWorldTest?
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.055 sec?
Results :?
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0?
[INFO] ------------------------------------?
[INFO] BUILD SUCCESSFUL?
[INFO] ------------------------------------?
…?

我们看到compiler:testCompile任务执行成功了,测试代码通过编译之后在target/test-classes下生成了二进制文件,
紧接着surefire:test任务运行测试,surefire是Maven世界中负责执行测试的插件,
这里它运行测试用例HelloWorldTest,并且输出测试报告。显然,我们的测试通过了——BUILD SUCCESSFUL。
---------------------------------------
3.4 打包和运行?

将项目进行编译、测试之后,下一个重要步骤就是打包(package)。
Hello World的POM中没有指定打包类型,使用默认打包类型jar,
我们可以简单地执行命令 mvn clean package 进行打包,
可以看到如下输出:
Java代码?
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0?
[INFO] [jar:jar {execution: default-jar}]?
[INFO] Building jar: D:\code\hello-world\target\hello-world-1.0-SNAPSHOT.jar?
[INFO]?
--------------------------------?
[INFO] BUILD SUCCESSFUL?
…?
类似地,Maven会在打包之前执行编译、测试等操作。
这里我们看到jar:jar任务负责打包,实际上就是jar插件的jar目标将项目主代码打包成一个名为hello-world-1.0-SNAPSHOT.jar的文件,
该文件也位于target/输出目录中,它是根据artifact-version.jar规则进行命名的,
如有需要,我们还可以使用finalName来自定义该文件的名称,这里暂且不展开,本书后面会详细解释。
至此,我们得到了项目的输出,如果有需要的话,就可以复制这个jar文件到其他项目的Classpath中从而使用HelloWorld类。
但是,如何才能让其他的Maven项目直接引用这个jar呢?
我们还需要一个安装的步骤,执行 mvn clean install:
Java代码?
…?
[INFO] [jar:jar {execution: default-jar}]?
[INFO] Building jar: D: \code\hello-world\target\hello-world-1.0-SNAPSHOT.jar?
[INFO] [install:install {execution: default-install}]?
[INFO] Installing D:\code\hello-world\target\hello-world-1.0-SNAPSHOT.jar to?
C:\Users\juven\.m2\repository\com\juvenxu\mvnbook\hello-world\1.0-SNAPSHOT\hello-world-1.0-SNAPSHOT.jar?
[INFO]?
------------------------------------?
[INFO] BUILD SUCCESSFUL?
…?
在打包之后,我们又执行了安装任务install:install,
从输出我们看到该任务将项目输出的jar安装到了Maven本地仓库中,
我们可以打开相应的文件夹看到Hello World项目的pom和jar。
之前讲述JUnit的POM及jar的下载的时候,我们说只有构件被下载到本地仓库后,才能由所有Maven项目使用,
这里是同样的道理,只有将Hello World的构件安装到本地仓库之后,其他Maven项目才能使用它。
我们已经将体验了Maven最主要的命令:mvn clean compile、mvn clean test、mvn clean package、mvn clean install。
执行test之前是会先执行compile的,执行package之前是会先执行test的,
而类似地,install之前会执行package。我们可以在任何一个Maven项目中执行这些命令,而且我们已经清楚它们是用来做什么的。

到目前为止,我们还没有运行Hello World项目,不要忘了HelloWorld类可是有一个main方法的。
默认打包生成的jar是不能够直接运行的,因为带有main方法的类信息不会添加到manifest中
(我们可以打开jar文件中的META-INF/MANIFEST.MF文件,将无法看到Main-Class一行)。
为了生成可执行的jar文件,我们需要借助maven-shade-plugin,配置该插件如下:
Java代码?
<plugin>?
<groupId>org.apache.maven.plugins</groupId>?
<artifactId>maven-shade-plugin</artifactId>?
<version>1.2.1</version>?
<executions>?
<execution>?
<phase>package</phase>?
<goals>?
<goal>shade</goal>?
</goals>?
<configuration>?
<transformers>?
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">?
<mainClass>com.juvenxu.mvnbook.helloworld.HelloWorld</mainClass>?
</transformer>?
</transformers>?
</configuration>?
</execution>?
</executions>?
</plugin>?

plugin元素在POM中的相对位置应该在<project><build><plugins>下面。
我们配置了mainClass为com.juvenxu.mvnbook.helloworld.HelloWorld,项目在打包时会将该信息放到MANIFEST中。
现在执行 mvn clean install ,待构建完成之后打开target/目录,
我们可以看到hello-world-1.0-SNAPSHOT.jar和original-hello-world-1.0-SNAPSHOT.jar,
前者是带有Main-Class信息的可运行jar,后者是原始的jar,
打开hello-world-1.0-SNAPSHOT.jar的META-INF/MANIFEST.MF,可以看到它包含这样一行信息:
Main-Class: com.juvenxu.mvnbook.helloworld.HelloWorld
现在,我们在项目根目录中执行该jar文件:
D: \code\hello-world>java -jar target\hello-world-1.0-SNAPSHOT.jar
Hello Maven
控制台输出为Hello Maven,这正是我们所期望的。
本小节介绍了Hello World项目,侧重点是Maven而非Java代码本身,
介绍了POM、Maven项目结构、以及如何编译、测试、打包,等等。
------------------------------------------------------
3.5 使用Archetype生成项目骨架?
Hello World项目中有一些Maven的约定:
在项目的根目录中放置pom.xml,
在src/main/java目录中放置项目的主代码,
在src/test/java中放置项目的测试代码。
我们称这些基本的目录结构和pom.xml文件内容称为项目的骨架,
当你第一次创建项目骨架的时候,你还会饶有兴趣地去体会这些默认约定背后的思想,
第二次,第三次,你也许还会满意自己的熟练程度,但第四、第五次做同样的事情,就会让程序员恼火了,
为此Maven提供了Archetype以帮助我们快速勾勒出项目骨架。
还是以Hello World为例,我们使用maven archetype来创建该项目的骨架,离开当前的Maven项目目录。
如果是Maven 3,简单的运行:
mvn archetype:generate
我们实际上是在运行插件maven-archetype-plugin,
注意冒号的分隔,其格式为 groupId:artifactId:version:goal ,
org.apache.maven.plugins 是maven官方插件的groupId,maven-archetype-plugin?
是archetype插件的artifactId,2.0-alpha-5 是目前该插件最新的稳定版,generate是我们要使用的插件目标。
紧接着我们会看到一段长长的输出,有很多可用的archetype供我们选择,
包括著名的Appfuse项目的archetype,JPA项目的archetype等等。
每一个archetype前面都会对应有一个编号,同时命令行会提示一个默认的编号,
其对应的archetype为maven-archetype-quickstart,我们直接回车以选择该archetype,
紧接着Maven会提示我们输入要创建项目的groupId、artifactId、 version、以及包名package,如下输入并确认:
Java代码?
Define value for groupId: : com.juvenxu.mvnbook?
Define value for artifactId: : hello-world?
Define value for version: 1.0-SNAPSHOT: :?
Define value for package: com.juvenxu.mvnbook: : com.juvenxu.mvnbook.helloworld?
Confirm properties configuration:?
groupId: com.juvenxu.mvnbook?
artifactId: hello-world?
version: 1.0-SNAPSHOT?
package: com.juvenxu.mvnbook.helloworld?
Y: : Y?

Archetype插件将根据我们提供的信息创建项目骨架。
在当前目录下,Archetype插件会创建一个名为hello-world(我们定义的artifactId)的子目录,
从中可以看到项目的基本结构:基本的pom.xml已经被创建,里面包含了必要的信息以及一个junit依赖;
主代码目录src/main/java已经被创建,在该目录下还有一个Java类com.juvenxu.mvnbook.helloworld.App,
注意这里使用到了我们刚才定义的包名,而这个类也仅仅只有一个简单的输出Hello World!的main方法;
测试代码目录src/test/java也被创建好了,并且包含了一个测试用例com.juvenxu.mvnbook.helloworld.AppTest。
Archetype可以帮助我们迅速地构建起项目的骨架,
在前面的例子中,我们完全可以在Archetype生成的骨架的基础上开发Hello World项目以节省我们大量时间。
此外,我们这里仅仅是看到了一个最简单的archetype,
如果你有很多项目拥有类似的自定义项目结构以及配置文件,
你完全可以一劳永逸地开发自己的archetype,然后在这些项目中使用自定义的archetype来快速生成项目骨架

---------------------------------------------------------------

1.7java-maven书籍

Maven实战 许晓斌 (2012-12出版)

?

转自:http://blog.csdn.net/chinayaosir/article/details/8978103

热点排行