Javafreely 的 Maven 实践
本文主要参考了 maven 官网的getting started 教程。
下载和安装
参考 http://maven.apache.org/download.cgi
1. 确保系统中安装了 JDK 1.5 或以上版本.
2. 下载 apache-maven-3.0.5-bin.zip.
3. 解压到 D:\apache-maven-3.0.5.
4. 在系统中增加 M2_HOME 环境变量用户变量,指向Maven 的解压位置,如这里的 “D:\apache-maven-3.0.5”.
5. 增加环境变量 M2, 指向 “%M2_HOME%\bin”. 6
6. 还有一个可选的环境变量 “MAVEN_OPTS”,指定JVM 属性。如 “-Xms256m -Xmm512m”.
7. Path 环境变量中增加 %M2%.
8. 确保 JAVA_HOME 存在且指向正确位置,确保 %JAVA_HOME%\bin 在Path 环境变量中.
9. 命令行执行 “mvn --version” 验证maven 正确安装。
Maven 的作用
Maven 是一个项目管理工具,用于管理:
构建、文档、报表、依赖、配置管理、版本和发布等。
一般来说Maven 使用默认配置即可,如果需要更改cache 位置 或者位于一个HTTP 代理后面,就需要建立配置,可以参考
http://maven.apache.org/guides/mini/guide-configuring-maven.html
第一个 Maven 项目
Architype 的相关内容参考:
http://maven.apache.org/guides/introduction/introduction-to-archetypes.html
1. 建立目录 D:\mvnprojects
2. 命令行进入 D:\mvnprojets,执行
mvn archetype:generate \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DgroupId=com.mycompany.app \
-DartifactId=my-app
可以再 D:\mvnprojects 目录下看到一个目录my-app。目录名根据项目名称得到。My-app 的目录结构为:
my-app
|-- pom.xml
`-- src
|-- main
| `-- java
| `-- com
| `-- mycompany
| `-- app
| `-- App.java
`-- test
`-- java
`-- com
`-- mycompany
`-- app
`-- AppTest.java
文档对象模型(POM)
Pom.xml 包含该项目的项目对象模型 (Project Object Model). 内容如下:
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>my-app</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
我们对该文件中的内容进行简单说明。
project: pom.xml 文件的顶层元素。
modelVersion: POM 使用的对象模型版本。
groupId: 创建项目的组织等的唯一标识。
artifactId: primary artifact 的base name。项目的primary artifact一般是一个jar文件,secondary artifacts 也使用artifactId 作为名字的一部分。
packaging: 打包方式,如jar、war、ear等。
version: 项目产生的artifact 版本
name: 项目的显示名字
url: 从哪儿可以找到项目。
description: 项目的基本描述信息。
编译和测试
1. “cd my-app”.
2. “mvn compile”. 第一次执行该命令,maven 需要下载需要的plugin,因此执行时间可能会比较长。后面执行就会比较快了。
3. 编译执行unit test. “mvn test”. 如果只要编译,可以 “mvn test-compile”.
程序代码和测试代码分别位于 my-app\classes 和 my-app\test-classes 目录下。
打包和安装
1. “mvn package”.
2. “mvn install”. 需要注意的是,这里install 仅仅指将jar 文件安装到repository 中去。
3. 向jar 文件中增加 resource。只需要向增加相应的目录结构。
my-app
|-- pom.xml
`-- src
|-- main
| |-- java
| | `-- com
| | `-- mycompany
| | `-- app
| | `-- App.java
| `-- resources
| `-- META-INF
| `-- application.properties
`-- test
`-- java
`-- com
`-- mycompany
`-- app
`-- AppTest.java
则 “mvn package” 之后jar 的目录结构为:
|-- META-INF
| |-- MANIFEST.MF
| |-- application.properties
| `-- maven
| `-- com.mycompany.app
| `-- my-app
| |-- pom.properties
| `-- pom.xml
`-- com
`-- mycompany
`-- app
`-- App.class
${basedir}/src/main/resources 目录下的内容会在jar 文件的根目录下的 META-INF 中出现。另外jar 文件包中还会有pom.xml 和 pom.properties 文件。
4. 向unit test 类路径下增加resources,可以使用如下结构:
my-app
|-- pom.xml
`-- src
|-- main
| |-- java
| | `-- com
| | `-- mycompany
| | `-- app
| | `-- App.java
| `-- resources
| `-- META-INF
| |-- application.properties
`-- test
|-- java
| `-- com
| `-- mycompany
| `-- app
| `-- AppTest.java
`-- resources
`-- test.properties
那么在测试中可以使用
InputStream is = getClass().getResourceAsStream(“/test.properties”);
//
过滤资源文件
资源文件又是会包含一些build 时才能知道的值。Maven 通过过滤来实现这点。例如我们在resources 目录下有如下的资源文件:
# application.properties
application.name=${pom.name}
application.version=${pom.version}
其中application.name 和 application.version 不是静态值,需要编译时才确定。这里 ${属性名} 是build 时才确定的变量。为了让maven 在拷贝resource 的时候(build 过程的一步)过滤资源,可以讲filtering 设为true。如下所示:
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Maven Quick Start Archetype</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
可以看到我们增加了几个elements: build、resources、resource,并将resource 下的filtering 设为 true了。实际上这个值默认是false,可以不用写。但需要enable 过滤的时候需要将其设为true。
Resource 文件中可以引用 pom.xml 文件中定义的属性。如在本例中 ${pom.name} 为项目名,${pom.version} 指版本号(1.0-SNAPSHOT),${pom.build.finalName} 代表文件的final name。一些pom 的元素具有默认值。而settings.xml 文件中的引用可以用${settings.propertyName} 表示,propertyName 代表settings.xml 中定义的元素。
使用上面的pom.xml,则上面的资源文件被打包后看起来是这样的:
# application.properties
application.name=Maven Quick Start Archetype
application.version=1.0-SNAPSHOT
除了引用 pom.xml 和settings.xml 文件中的元素内容作为属性名外,还可以引用一个外部文件来定义属性。如可以定义一个属性文件:
# filter.properties
my.filter.value=hello!
这个属性文件定义了一个属性 “my.filter.value”,其值为 “hello!”。
为了使用这个属性,需要在pom.xml 文件中设置:
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Maven Quick Start Archetype</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<filters>
<filter>src/main/filters/filter.properties</filter>
</filters>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
</project>
在资源文件中可以使用这个属性:
# application.properties
application.name=${pom.name}
application.version=${pom.version}
message=${my.filter.value}
除了将属性定义在外部文件,还可以直接在pom.xml 中定义属性:
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Maven Quick Start Archetype</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</build>
<properties>
<my.filter.value>hello</my.filter.value>
</properties>
</project>
另外,资源文件中也可以使用系统属性或jvm 中或命令行定义的属性:
# application.properties
java.version=${java.version}
command.line.prop=${command.line.prop}
这时就可以这样执行命令:
mvn process-resources "-Dcommand.line.prop=hello again"。
使用外部依赖
参考:
http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
本部分简单进行介绍。
看下面这个pom.xml 文件:
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Maven Quick Start Archetype</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
显示项目只有一个依赖,即JUnit。对每个外部依赖,至少定义4项:groupId,artifactId,version和scope。groupId、artifactId 和version 与依赖项目的pom.xml 文件中定义的内容一样,而scope 显示了你的项目如何使用依赖项目,其可选值包括compile、test、runtime。
有了 pom.xml 中定义的依赖信息,当build project 的时候,maven 就可以引用这些依赖。Maven 从local repository 中(默认位置是 ~/.m2/repository)寻找依赖。Mvn 的install执行的就是将项目添加到local repository 的操作。若从 local repository 找不到依赖项目,maven将试图从一个remote repository 下载依赖项目。默认是从 http://repo.maven.apache.org/maven2/ ,也可以自己设置remote repository。
接下来,我们看看如何将向项目中加入一个依赖项目。以log4j 为例。首先我们需要知道log4j 的groupId、artifactId、version。可以用google中搜索“site:www.ibiblio.org maven2 log4j”来找到一个目录 “/maven2/log4j/log4j”(或者 “/pub/packages/maven2/log4j/log4j”),我们可以找到一个 maven-metadata.xml 文件,其内容大概类似:
<metadata>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.1.3</version>
<versioning>
<versions>
<version>1.1.3</version>
<version>1.2.4</version>
<version>1.2.5</version>
<version>1.2.6</version>
<version>1.2.7</version>
<version>1.2.8</version>
<version>1.2.11</version>
<version>1.2.9</version>
<version>1.2.12</version>
</versions>
</versioning>
</metadata>
找到我们需要的信息之后,就可以将依赖添加到我们项目的pom.xml 中:
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Maven Quick Start Archetype</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.12</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
部署我的jar 文件到 remote repository
需要在 pom.xml 文件中配置 repository url,并在settings.xml 中配置连接到该URL 的认证信息。我们不多介绍。
Maven 的文档生成系统
参考
http://maven.apache.org/guides/mini/guide-site.html
构建其他类型的项目
可以用如下方式生成一个简单的web 应用:
mvn archetype:generate \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DarchetypeArtifactId=maven-archetype-webapp \
-DgroupId=com.mycompany.app \
-DartifactId=my-webapp
注意 archetypeArtifactId 参数。
生成的项目描述符如下:
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-webapp</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>my-webapp</finalName>
</build>
</project>
Packaging 元素说明将打包为war 文件而不是jar 文件。
执行:
mvn clean package
可以再 target 目录下生成 my-webapp.war 文件。
一次构建多个项目
从以上步骤中,我们已经创建了两个project: my-app 和 my-webapp。
1. 生成一个父 pom.xml 文件。
+- pom.xml
+- my-app
| +- pom.xml
| +- src
| +- main
| +- java
+- my-webapp
| +- pom.xml
| +- src
| +- main
| +- webapp
这个父 pom.xml 的内容为:
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<modules>
<module>my-app</module>
<module>my-webapp</module>
</modules>
</project>
2. My-webapp 会依赖my-app 产生的jar。因此 my-webapp/pom.xml 中增加dependency:
<dependencies>
<dependency>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
...
</dependencies>
3. 在my-app 和 my-webapp 子目录的pom.xml 中增加以下parent 元素:
<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/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>app</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
...
4. 在顶层目录(my-app 目录、my-webapp 目录的父目录)运行 “mvn clean install”。
你会发现 虽然项目依赖于 junit ,但是my-webapp 中并没有junit。这是由于 限制scope 为test(<scope>test</scope>)。