项目结构

Maven项目结构

就像MakeMakefileAntbuild.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 2Maven 3来说,它只能是4.0.0。这段代码中最重要的是groupIdartifactIdversion三行。这三个元素定义了一个项目基本的坐标,在Maven的世界,任何的jarpom或者war都是以基于这些基本的坐标进行区分的。
  • groupId定义了项目属于哪个组,这个组往往和项目所在的组织或公司存在关联,譬如你在googlecode上建立了一个名为myapp的项目,那么groupId就应该是com.googlecode.myapp,如果你的公司是mycom,有一个项目为myapp,那么groupId就应该是com.mycom.myapp
  • artifactId定义了当前Maven项目在组中唯一的ID,我们为这个Hello World项目定义artifactIdhello-world,本书其他章节代码会被分配其他的artifactId。而在前面的groupIdcom.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中定义的groupIdartifactId相吻合。一般来说,项目中Java类的包都应该基于项目的groupIdartifactId,这样更加清晰,更加符合逻辑,也方便搜索构件或者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文件时也会尝试下载jarmd5, sha1文件。Mavenrepository并没有优先级的配置,也不能单独为某些依赖配置repository。所以如果项目配置了多个repository,在首次编绎时,会依次尝试下载依赖。如果没有找到,尝试下一个,整个流程会很长。所以尽量多个依赖放同一个仓库,不要每个项目都有一个自己的仓库。如果想要使用本地file仓库里,在项目的pom.xml里配置,如:

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