项目结构

Maven 项目结构

就像 Make 的 Makefile,Ant 的 build.xml 一样,Maven 项目的核心是 pom.xml。首先创建一个名为 hello-world 的文件夹,打开该文件夹,新建一个名为 pom.xml 的文件,输入其内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<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.wx.mvn</groupId>
  <artifactId>hello-world</artifactId>
  <version>1.0-SNAPSHOT</version>
  <name>Maven Hello World Project</name>
</project>

文件结构

  • 代码的第一行是 XML 头,指定了该 xml 文档的版本和编码方式。紧接着是 project 元素,project 是所有 pom.xml 的根元素,它还声明了一些 POM 相关的命名空间及 xsd 元素,虽然这些属性不是必须的,但使用这些属性能够让第三方工具(如 IDE 中的 XML 编辑器)帮助我们快速编辑 POM。
  • 根元素下的第一个子元素 modelVersion 指定了当前 POM 模型的版本,对于 Maven 2 及 Maven 3 来说,它只能是 4.0.0。这段代码中最重要的是 groupId,artifactId 和 version 三行。这三个元素定义了一个项目基本的坐标,在 Maven 的世界,任何的 jar、pom 或者 war 都是以基于这些基本的坐标进行区分的。
  • groupId 定义了项目属于哪个组,这个组往往和项目所在的组织或公司存在关联,譬如你在 googlecode 上建立了一个名为 myapp 的项目,那么 groupId 就应该是 com.googlecode.myapp,如果你的公司是 mycom,有一个项目为 myapp,那么 groupId 就应该是 com.mycom.myapp。
  • artifactId 定义了当前 Maven 项目在组中唯一的 ID,我们为这个 Hello World 项目定义 artifactId 为 hello-world,本书其他章节代码会被分配其他的 artifactId。而在前面的 groupId 为 com.googlecode.myapp 的例子中,你可能会为不同的子项目(模块)分配 artifactId,如:myapp-util、myapp-domain、myapp-web 等等。
  • version 指定了 Hello World 项目当前的版本——1.0-SNAPSHOT。SNAPSHOT 意为快照,说明该项目还处于开发中,是不稳定的版本。随着项目的发展,version 会不断更新,如升级为 1.0、1.1-SNAPSHOT、1.1、2.0 等等。

  • 最后一个 name 元素声明了一个对于用户更为友好的项目名称,虽然这不是必须的,但我还是推荐为每个 POM 声明 name,以方便信息交流。没有任何实际的 Java 代码,我们就能够定义一个 Maven 项目的 POM,这体现了 Maven 的一大优点,它能让项目对象模型最大程度地与实际代码相独立,我们可以称之为解耦,或者正交性,这在很大程度上避免了 Java 代码和 POM 代码的相互影响。比如当项目需要升级版本时,只需要修改 POM,而不需要更改 Java 代码;而在 POM 稳定之后,日常的 Java 代码开发工作基本不涉及 POM 的修改。

变量替换

在 pom.xml 定义 properties 标签

<properties>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 <spring.version>1.2.6</spring.version>
 <developer.organization><![CDATA[xy公司]]></developer.organization>
</properties>

以上内容就改成了

<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-core</artifactId>
 <version>${spring.version}</version>
</dependency>
<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-aop</artifactId>
 <version>${spring.version}</version>
</dependency>

也可以使用 maven-properties 插件来支持外部变量

目录结构

项目主代码和测试代码不同,项目的主代码会被打包到最终的构件中(比如 jar),而测试代码只在运行测试时用到,不会被打包。默认情况下,Maven 假设项目主代码位于 src/main/java 目录,我们遵循 Maven 的约定,创建该目录,然后在该目录下创建文件 com/wx/mvn/helloworld/HelloWorld.java,其内容如下:

package com.wx.mvn.helloworld;

public class HelloWorld {

  public String sayHello() {
    return "Hello Maven";
  }

  public static void main(String[] args) {
    System.out.print(new HelloWorld().sayHello());
  }
}

关于该 Java 代码有两点需要注意。首先,大部分情况下我们应该把项目主代码放到 src/main/java/ 目录下(遵循 Maven 的约定),而无须额外的配置,Maven 会自动搜寻该目录找到项目主代码。其次,该 Java 类的包名是 com.wx.mvn.helloworld,这与我们之前在 POM 中定义的 groupId 和 artifactId 相吻合。一般来说,项目中 Java 类的包都应该基于项目的 groupId 和 artifactId,这样更加清晰,更加符合逻辑,也方便搜索构件或者 Java 类。代码编写完毕后,我们使用 Maven 进行编译,在项目根目录下运行命令 mvn clean compile 即可。Maven 首先执行了 clean:clean 任务,删除 target/ 目录,默认情况下 Maven 构建的所有输出都在 target/ 目录中;接着执行 resources:resources 任务(未定义项目资源,暂且略过);最后执行 compiler:compile 任务,将项目主代码编译至 target/classes 目录(编译好的类为 com/wx/mvn/helloworld/HelloWorld.Class)。

仓库配置

Maven Repos

下面介绍一些 Maven 仓库工作的原理。典型的一个 Maven 依赖下会有这三个文件:

maven-metadata.xml
maven-metadata.xml.md5
maven-metadata.xml.sha1

maven-metadata.xml 里面记录了最后 deploy 的版本和时间。

<?xml version="1.0" encoding="UTF-8"?>
<metadata modelVersion="1.1.0">
  <groupId>io.github.hengyunabc</groupId>
  <artifactId>mybatis-ehcache-spring</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <versioning>
    <snapshot>
      <timestamp>20150804.095005</timestamp>
      <buildNumber>1</buildNumber>
    </snapshot>
    <lastUpdated>20150804095005</lastUpdated>
  </versioning>
</metadata>

其中 md5, sha1 校验文件是用来保证这个 meta 文件的完整性。Maven 在编绎项目时,会先尝试请求 maven-metadata.xml,如果没有找到,则会直接尝试请求到 jar 文件,在下载 jar 文件时也会尝试下载 jar 的 md5, sha1 文件。Maven 的 repository 并没有优先级的配置,也不能单独为某些依赖配置 repository。所以如果项目配置了多个 repository,在首次编绎时,会依次尝试下载依赖。如果没有找到,尝试下一个,整个流程会很长。所以尽量多个依赖放同一个仓库,不要每个项目都有一个自己的仓库。如果想要使用本地 file 仓库里,在项目的 pom.xml 里配置,如:

<repositories>
  <repository>
    <id>hengyunabc-maven-repo</id>
    <url>file:/home/hengyunabc/code/maven-repo/repository/</url>
  </repository>
</repositories>
上一页
下一页