Maven 文件结构

目录 说明
bin Maven运行的脚本
boot 包含plexus-classworlds-2.5.2.jar Maven的类加载框架
conf 该目录包含一个非常重要的配置文件setting.xml。修改该文件就能全局的定制Maven的行为, 用户也可以在~/.m2/目录来建立用户范围级别的Maven行为配置
lib Maven运行时所需要的Java类库
LICENSE 开源协议说明
NOTICE Maven 依赖第三方核心库的说明
README.txt Maven 介绍说明

Maven编译

约定(主代码)

默认情况下,Maven假设项目主代码位于 src/main/java目录,一般该目录会被打包到最终的构件中(如jar)

命令

命令 说明
clean 清理输出目录 target/
resources 处理资源文件
compile 编译项目主代码
package 项目打包
install 将项目输出的jar安装到本地仓库中

Pom 结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

<!-- XML头,指定该xml文档的版本和编码方式 -->
<?xml version="1.0" encoding="UTF-8"?>
<!-- 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">
<!-- 当前POM模型版本 -->
<modelVersion>4.0.0</modelVersion>
<!--定义项目属于哪个组,一般这个组定义所在的组织或者公司关联 -->
<!-- 例如在googlecode组织上建立myapp项目,
那么groupId应该是com.googlecode.myapp -->
<groupId>com.cotide</groupId>
<!-- 当前Maven项目在组中唯一的ID -->
<artifactId>MyProject</artifactId>
<!-- 项目名称 (可选) -->
<name>Default Project</name>
<!-- 项目当前的版本 -->
<!-- SNAPSHOT说明项目处于开发阶段是不稳定的版本 -->
<version>1.0-SNAPSHOT</version>
<!-- 打包文件格式jar or war (可选) -->
<packaging>jar</packaging>
<!-- 相同版本下针对不同的环境或者jdk使用的jar -->
<classifier></classifier>
</project>
节点 说明
name 名称 - 设计目的方便阅读 (可选)
groupId 坐标 (定义唯一的项目或者组织)
artifactId 基于坐标的项目名称
version 项目版本
packaging 打包文件格式 pom, jar, maven-plugin, ejb, war, ear, rar, par

格式:groupId:artifactId:version

节点 说明
classifier 扩展名

格式: groupId:artifactId:packaging:classifier:version

POM依赖范围

类型 说明
compile 编译依赖范围(默认)
test 测试依赖范围
provided 已提供依赖范围
runtime 运行时依赖范围
system 系统依赖范围
import 导入依赖范围

POM依赖关系

  • 传递性依赖

在POM配置中没有指定依赖范围默认为compile,当遇到A->B-C库的时候这种行为叫传递性依赖

  • 依赖调解

例子:A -> B -> C-> X(1.0) 和 A -> D- >X(2.0)

1.路径最近者优先

例子:A -> B -> Y(1.0) 和 A -> C-> Y(2.0)

2.第一声明者优先

  • 可选依赖

    可以自行配置依赖选择方式,通过进行配置,标记该配置的的项目不会被传递依赖。

1
2
3
4

# 依赖关系
A -> B -> mysql-connector-java (可选)
A -> B -> postgresql (可选)

mysql-connector-java 和 postgresql 只会对项目B产生影响,当A依赖B的时候,这两个依赖不会被传递,如果项目A想依赖需要显示的去声明mysql-connector-java 和 postgresql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

<!-- 可选依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.10</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>8.4-701.jdbc3</version>
<optional>true</optional>
</dependency>

<!-- 显示声明 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.10</version>
</dependency>
  • 排除依赖

    可以显示的去排除项目引用的依赖关系

例如:项目依赖一个有版权问题的project-b的 jar,如果需要使用该项目,可以显示的去替换这个依赖关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

<dependencies>
<dependency>
<groupId>com.juvenxu.mvnbook</groupId>
<artifactId>project-b</artifactId>
<version>1.0.0</version>
<exclusions>
<!-- 排查依赖配置 -->
<exclusion>
<groupId>com.juvenxu.mvnbook</groupId>
<artifactId>project-c</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.juvenxu.mvnbook</groupId>
<artifactId>project-c</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
  • 归类依赖

    项目中如果依赖多个版本的JAR(构件),为了更方便的去升级该项目,可以使用该配置

1
2
3
4
5

业务场景:统一springframework的版本
思路:
1. 定义属性<属性名>
2. 使用占位符${属性名} 动态注入到<version> 配置项中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

<properties>
<springframework.version>2.5.6</springframework.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-suport</artifactId>
<version>${springframework.version}</version>
</dependency>
</dependencies>
  • 依赖关系检查

通过Intellij IDE 的Terminal工具可以很方便的去了解当前的依赖关系

1
2
3
4
5
6
7
8
9

# 显示依赖关系
$ mvn dependency:list

# 显示层级关系依赖
$ mvn dependency:tree

# 依赖关系分析
$ mvn dependency:analyze

Maven 仓库

任何一个依赖,插件或者项目构建的输出,都称为构件。任何一个构件都有一组坐标唯一标识。任何Maven项目使用任何一个构件的方式都是完全相同的。在此基础上,Maven可以在某一个位置统一存储所有Maven项目共享的构件,这个统一的位置就是仓库

Maven仓库

Maven仓库 (AliYun镜像)

仓库分类

Maven仓库分类

  • 本地仓库
  • 远程仓库

当Maven根据坐标需找构件的时候,首先会检查本地仓库是否存在构件,如果存在直接使用,如果不存在则去远程仓库查找并下载到本地仓库

自定义配置

配置级别

Windows
  • 全局级别配置 Maven3.5\conf\settings.xml
  • 用户级别配置 C:\Users\用户\settings.xml
Linux
  • 全局级别配置 Maven3.5\conf\settings.xml
  • 用户级别配置 ~/.m2/settings.xml

本地仓库配置

修改settings.xml 设置localRepository元素值为仓库本地地址

1
2
3
4

<setting>
<localRepository>F:\lib</localRepository>
</setting>

远程仓库配置

修改settings.xml 设置mirror元素值为仓库远程地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

<setting>
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>*</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
</mirrors>
</setting>

```

#### 远程仓库认证配置

> 修改settings.xml 设置server元素认证信息

``` xml

<setting>
<servers>
<server>
<id>my-proj</id>
<username>repo-user</username>
<password>repo-pwd</password>
</server>
</servers>
</setting>

仓库快照配置

快照是一个特殊的版本,它表示当前开发的一个副本。与常规版本不同,Maven 为每一次构建从远程仓库中检出一份新的快照版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 
<distributionManagement>
<!-- 发布版本构件的仓库 -->
<repository>
<id>proj-releases</id>
<name>Proj Release Repository</name>
<url>远程仓位置</url>
</repository>
<!-- 快照版本的仓库 -->
<snapshotRepository>
<id>proj-snapshots</id>
<name>Proj Snapshot Repository</name>
<url>远程仓位置</url>
</snapshotRepository>
</distributionManagement>
1
2
# 设置Maven 每次自动获取最新的快照
$ mvn clean package -U

生命周期和插件

Maven两个核心概念是生命周期和插件,Maven的生命周期是抽象的,其实际行为都由插件来完成,所以需要两者协同工作

生命周期

  • clean 生命周期的目的是清理项目
  • default 生命周期的母的是构建所需执行的所有步骤
  • site 生命周期的目的是建立和发布项目信息

插件

获取 Apache Maven 官方插件

插件管理

Maven提供了pluginManagement元素帮助管理依赖,通过配置该元素来注入到Maven的生命周期中

聚合

目地为了方便快速构建项目

事例:项目需要同时编译输出两套构件,可以建立新的项目依赖两套构件,修改POM配置如下:

1
2
3
4
5
6

<packaging>pom</packaging>
<modules>
<module>构件A</module>
<module>构件B</module>
</modules>
1
2
# 执行命令
$ mvn clean install

继承

目地为了简化构件中重复POM配置

事例:

Parent项目 -> 构件A

Parent项目 -> 构件B

Parent项目的POM

1
2
3
4
5
6
<project>
<groupId>com.cotide</groupId>
<artifactId>Parent项目</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
</project>

构件A的POM

1
2
3
4
5
6
7

<parent>
<groupId>com.cotide</groupId>
<artifactId>Parent项目</artifactId>
<version>1.0.0</version>
<relativePath>Parent项目目录/pom.xml</relativePath>
</parent>

构件B的POM

1
2
3
4
5
6
7

<parent>
<groupId>com.cotide</groupId>
<artifactId>Parent项目</artifactId>
<version>1.0.0</version>
<relativePath>Parent项目目录/pom.xml</relativePath>
</parent>

依赖管理

基于继承依赖,进行依赖管理

事例:

Parent项目 -> 构件A (引用构件C)

Parent项目 -> 构件B (引用构件C)

Parent项目的POM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<project>
<groupId>com.cotide</groupId>
<artifactId>Parent项目</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>构件C groupId</groupId>
<artifactId>构件C</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>

构件A的POM

1
2
3
4
5
6
7
8
9
10
11
12
13
14

<parent>
<groupId>com.cotide</groupId>
<artifactId>Parent项目</artifactId>
<version>1.0.0</version>
<relativePath>Parent项目目录/pom.xml</relativePath>
</parent>
<dependencies>
<!-- 指向Parent的构件配置 -->
<dependency>
<groupId>构件C groupId</groupId>
<artifactId>构件C</artifactId>
</dependency>
</dependencies>

构件B的POM

1
2
3
4
5
6
7
8
9
10
11
12
13
14

<parent>
<groupId>com.cotide</groupId>
<artifactId>Parent项目</artifactId>
<version>1.0.0</version>
<relativePath>Parent项目目录/pom.xml</relativePath>
</parent>
<dependencies>
<!-- 指向Parent的构件配置 -->
<dependency>
<groupId>构件C groupId</groupId>
<artifactId>构件C</artifactId>
</dependency>
</dependencies>

IntelliJ IDEA 实战 - 添加junit项目

创建项目 (Maven结构)

项目结构

编辑POM

项目pom.xml 文件结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?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/xsd/maven-4.0.0.xsd">
<!-- 定义名为framework项目 -->
<modelVersion>4.0.0</modelVersion>
<groupId>com.cotide.core</groupId>
<artifactId>framework</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 添加依赖关系 -->
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<!-- 依赖范围,test表示该依赖只对测试有效 -->
<scope>test</scope>
</dependency>
</dependencies>
</project>

关于 接点的依赖关系可以通过查询Maven官方中央仓http://search.maven.org 找到对应的pom配置,由于国内线路访问国外线路慢的问题可以查询阿里Maven镜像http://maven.aliyun.com/nexus

Intellij IDEA Maven配置

Intellij IDEA 默认自带Maven,如果需要修改自己的配置需要在File -> Settings -> Maven 上进行Maven 配置

运行Maven

Intellij IDEA Maven 编译 配置

选择Run -> Edit Configurations 添加Maven 编译配置 -> 点击Run 执行

Maven 执行后的效果

执行完后,在项目下已经添加了junit的依赖,并生成target目录下的文件

Maven 输出乱码问题

pom.xml 配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<build>
<plugins>
<!-- 解决maven test命令时console出现中文乱码乱码 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20</version>
<configuration>
<forkMode>once</forkMode>
<argLine>-Dfile.encoding=UTF-8</argLine>
</configuration>
</plugin>
</plugins>
</build>

Maven 打包控制台项目

pom.xml 配置如下:


<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <!-- 主程序包路径 -->
                <mainClass>com.cotide.main</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

扩展

Nexus

Maven仓库管理软件, Nexus分为开源版和专业版,其开源版本基于CPLv3 许可证

Nexus 搭建

http://books.sonatype.com/nexus-book/3.0/reference/install.html

持续集成

自动化部署

Maven Archetype

Archtype是项目的骨架,通过Maven中的maven-archetype-plugin插件用户可以快速的去生成所需的项目骨架.

# 构建generate项目骨架
$ mvn archetype:generate

参考资料