Maven

dev-env-resource

# 一、Maven基础

# Maven简介

Maven是 Apache 开源组织奉献的一个开源项目。 Maven 的本质是一个项目管理工具,将项目开发和管理过程抽象成一个项目对象模型(POM)。开发人员只需做一些简单的配置,就可以批量完成项目的构建、报告和文档的生成工作。

Maven 是跨平台的,这意味着无论是在 Windows 上,还是在 Linux 或者 Mac 上,都可以使用同样的命令。

MAVEN三板斧用来定位坐标:groupId、artifactId、version

<dependency>
	<groupId>com.superc.kim</groupId>
	<artifactId>common</artifactId>
	<version>1.0.0-SNAPSHOT</version>
</dependency>
1
2
3
4
5

Maven 为全世界的 Java 开发者提供了一个免费的中央仓库(maven中央仓库repository (opens new window))。

在其中可以找到绝大部分的流行开源类库。通过一些 Maven 的衍生工具(如 Nexus),我们还能对其进行快速地搜索。只要定位了坐标,Maven 就能够帮我们自动下载,省去了手工导入。

# Maven特点

  • Maven 统一集中管理所有的依赖包,不需要程序员再去寻找。
  • 对应第三方组件用到的共同 jar,Maven 自动解决重复和冲突问题
  • Maven 作为一个开放的架构,提供了公共接口,方便同第三方插件集成。程序员可以将自己需要的插件,动态地集成到 Maven,从而扩展新的管理功能。
  • MAVEN能帮助我们标准化构建过程。Maven 可以统一每个项目的构建过程,实现不同项目的兼容性管理。

# 二、Maven生命周期

生命周期:lifecycle

阶段:phase

在项目构建时通常会包含清理(clean)编译(complie)测试(test)打包(package)验证(verify)部署(install)发布(deploy)文档生成(site) 等步骤。

# 三大生命周期

maven 统一对其进行了整理抽像成三个生命周期 (lifecycle)及各自对应的多个阶段(phase)。

maven 总共包含三大生命周期:

  1. clean Lifecycle清理生命周期,用于清理项目;
  2. default Lifecycle默认生命周期,用于编译、打包、测试、部署等;
  3. site Lifecycle站点文档生成,用于构建站点文档;

三大生命周期其相互独立执行,也可以合在一起执行。

但lifecycle 中的phase 是有严格执行的顺序的,比如必须是先执行完compile 才能执行pakcage 动作。

此外phase 还有包含逻辑存在,即当你执行一个phase 时 其前面的phase 会自动执行。例如执行编译mvn package前会先自动执行mvn validatemvn package所有phase。

生命周期(lifecycle) 阶段(phase) 描述(describe)
clean Lifecycle pre-clean 预清理
clean 清理
post-clean 清理之后
default Lifecycle validate 验证
initialize 初始化
generate-sources
process-sources
generate-resources
process-resources
compile 编译
process-classes
generate-test-sources
process-test-sources
generate-test-resources
process-test-resources
test-compile 编译测试类
process-test-classes
test 执行测试
prepare-package 构建前准备
package 打包构建
pre-integration-test
integration-test
post-integration-test
verify 验证
install 上传到本地仓库
deploy 上传到远程仓库
site Lifecycle pre-site 准备构建站点
site 构建站点文档
post-site 构建站点之后
site-deploy 站点部署

# 三、Maven依赖

# 依赖传播特性

  • 直接依赖

  • 间接依赖

# Maven依赖优先原则

基于依赖传播特性,导致整个依赖网络会很复杂,难免会出现相同组件不同版本的情况。Maven此时会基于依赖优先原则选择其中一个版本。

  • 依赖在前原则
  • 路径最短原则

# 可选依赖

可选依赖表示这个依赖不是必须的。通过在 <dependency> 添加 <optional>true</optional>

默认是不可选的。

可选依赖不会被传递

# 排除依赖

即排除指定的间接依赖。通过配置 <exclusions> 配置排除指定组件。

# 依赖范围

过Mave 的依赖范围配置<scope>来明确依赖范围。

  • compile(默认):编译范围,编译和打包都会依赖。

  • provided:提供范围,编译时依赖,但不会打包进去。如:servlet-api.jar

  • runtime:运行时范围,打包时依赖,编译不会。如:mysql-connector-java.jar

  • test:测试范围,编译运行测试用例依赖,不会打包进去。如:junit.jar

  • system:表示由系统中CLASSPATH指定。编译时依赖,不会打包进去。配合<systemPath> 一起使用。

    示例:java.home下的tool.jar

    <!-- system 的通常使用方式-->
    <dependency>
    	<groupId>com.sun</groupId>
    	<artifactId>tools</artifactId>
    	<version>${java.version}</version>
    	<scope>system</scope>
    	<optional>true</optional>
    	<systemPath>${java.home}/../lib/tools.jar</systemPath>
    </dependency>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9

    system 除了可以用于引入系统classpath 中包,也可以用于引入系统非maven 收录的第三方JAR。

    做法是将第三方JAR放置在 项目的 lib 目录下,然后配置 相对路径,但因system 不会打包进去所以需要配合 maven-dependency-plugin 插件配合使用。

    当然推荐大家还是通过 将第三方JAR手动install 到仓库。

    <!-- system 另外使用方式 ,将工程内的jar直接引入 -->
    <dependency>
        <groupId>jsr</groupId>
        <artifactId>jsr</artifactId>
        <version>3.5</version>
        <scope>system</scope>
        <optional>true</optional>
        <systemPath>${basedir}/lib/jsr305.jar</systemPath>
    </dependency>
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
  • import:只在dependencyManagement标签中使用,解决Maven单依赖。

# 四、Maven聚合与继承

# 聚合

聚合是指将多个模块整合在一起,统一构建,避免一个一个的构建。聚合需要个父工程,然后使用 <modules>进行配置其中对应的是子工程的相对路径

<modules>
    <module>kim-client</module>
    <module>kim-server</module>
</modules>
1
2
3
4

# 继承

继承是指子工程直接继承父工程 当中的属性、依赖、插件等配置,避免重复配置。

  1. 属性继承:
  2. 依赖继承:
  3. 插件继承:

上面的三个配置子工程都可以进行重写,重写之后以子工程的为准。

# 依赖管理

通过继承的特性,子工程是可以间接依赖父工程的依赖,但多个子工程依赖有时并不一至,这时就可以在父工程中加入 <dependencyManagement> 声明该功程需要的JAR包,然后在子工程中引入。

<!-- 父工程中声明 junit 4.12 -->
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
</dependencyManagement>
    
<!-- 子工程中引入 -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 五、Maven属性

# 自定义属性

通过 <properties> 配置 属性参数,可以简化配置。

<!-- 配置proName属性 -->
<properties>
    <proName>kim-test</proName>
</properties>

<!-- 引用方式 -->
${proName} 
1
2
3
4
5
6
7

# Maven默认的属性

Maven默认属性 描述
${basedir} 项目根目录
${version} 表示项目版本;
${project.basedir} 同${basedir};
${project.version} 表示项目版本,与${version}相同;
${project.build.directory} 构建目录,缺省为target
${project.build.sourceEncoding} 表示主源码的编码格式;
${project.build.sourceDirectory} 表示主源码路径;
${project.build.finalName} 表示输出文件名称;
${project.build.outputDirectory} 构建过程输出目录,缺省为target/classes

# 六、Maven插件

# 插件Plugin

插件与普通jar 包一样,也是由三板斧进行坐标定位groupId、artifactId、version

当使用该插件时也是从本地仓库中搜索,如果没有再从远程仓库下载。

# 插件执行 execution

execution 配置包含一组指示插件如何执行的属性:

  • id : 执行器命名
  • phase:在什么阶段执行?
  • goals:执行一组什么目标或功能?
  • configuration:执行目标所需的配置文件?

插件的配置

示例:自定义插件执行,实现功能为将插件依赖拷贝到指定目录。

<!-- maven-dependency-plugin:处理与依赖相关的插件 -->
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>3.1.1</version>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/myLibs</outputDirectory>
                <overWriteReleases>false</overWriteReleases>
                <overWriteSnapshots>true</overWriteSnapshots>
                <excludeTransitive>true</excludeTransitive>
            </configuration>
        </execution>
    </executions>
</plugin>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 默认插件

# 生命周期与插件的关系

生命周期的phase组成了项目构建的完整过程,但这些过程具体由谁来实现呢?

这就是插件,maven 的核心部分代码量其实很少,其大部分实现都是由插件来完成的。

比如:test 阶段就是由 maven-surefire-plugin 实现。

在pom.xml 中我们可以设置指定插件目标(gogal)phase 绑定,当项目构建到达指定phase时,就会触发些插件gogal 的执行。 (埋点)

一个插件有时会实现多个phase。比如:maven-compiler-plugin插件分别实现了compile 和testCompile。

总结:

  • 生命周期的 阶段phase 可以绑定具体的插件及目标;
  • 不同配置下同一个阶段phase 可以对应多个插件和目标;
  • phase==>plugin==>goal(功能);

# 生命周期与插件的默认绑定

全部的生命周期与插件的默认绑定 (opens new window)

展示部分常用的生命周期与插件的默认绑定

<phases>
  <process-resources>
    org.apache.maven.plugins:maven-resources-plugin:2.6:resources
  </process-resources>
  <compile>
    org.apache.maven.plugins:maven-compiler-plugin:3.1:compile
  </compile>
  <process-test-resources>
    org.apache.maven.plugins:maven-resources-plugin:2.6:testResources
  </process-test-resources>
  <test-compile>
    org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile
  </test-compile>
  <test>
    org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test
  </test>
  <package>
    org.apache.maven.plugins:maven-jar-plugin:2.4:jar
  </package>
  <install>
    org.apache.maven.plugins:maven-install-plugin:2.4:install
  </install>
  <deploy>
    org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy
  </deploy>
</phases>
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

# 常用插件的使用

在我们的项目当中并没有配置 maven-compiler-plugin 插件,但当我们执行compile 阶段时一样能够执行编译操作。原因是maven 默认为指定阶段绑定了插件实现。

例如以下两个操作在一定程度上是等价的。

# 最简版命令,当一个插件有且只有一个phase时,直接简化为phase命令
mvn compile
# 完整版执行命令
mvn org.apache.maven.plugins:maven-compiler-plugin:3.1:compile
1
2
3
4
  • 简化版的命令

maven官方提供的插件,在执行时默认可以省略groupId,以及maven--pluginsversion信息。

maven会自动去下载最新版本的插件执行。

# 简化版命令
mvn compiler:compile
1
2

以上三条命令等价执行,均表示执行maven编译。

# 自定义插件

# 实现步骤

  • 创建maven 插件项目

  • 设定packaging 为maven-plugin

  • 添加插件依赖

  • 编写插件实现逻辑

  • 打包构建插件

<packaging>maven-plugin</packaging>

<dependencies>
    <dependency>
        <groupId>org.apache.maven</groupId>
        <artifactId>maven-plugin-api</artifactId>
        <version>3.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.maven.plugin-tools</groupId>
        <artifactId>maven-plugin-annotations</artifactId>
        <version>3.4</version>
    </dependency>
</dependencies>

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

# 七、Maven使用

# Maven下载

maven官方下载链接 (opens new window)

  • Binary是可执行版本,已经编译好可以直接使用。
  • Source是源代码版本,需要自己编译成可执行软件才可使用。

# 配置settings.xml

  • 指定本地仓库路径
  • 配置镜像
  • 配置JDK
  • 配置私服

完整的settings.xml如下:


<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
    
  <!-- 配置本地仓库 -->
  <localRepository>D:\Install_java\maven_Repository\repository-spring</localRepository>

  <servers>
    <!-- 配置nexus私服的认证信息 -->
    <server>
        <id>nexus-public</id>
        <username>admin</username>
        <password>admin</password>
    </server>
    <server>
      <id>nexus-releases</id>
      <username>admin</username>
      <password>admin</password>
    </server>
    <server>
      <id>nexus-snapshots</id>
      <username>admin</username>
      <password>admin</password>
    </server>
  </servers> 
   
  <mirrors>
    <!-- 配置我的私服nexus -->
    <mirror>
        <id>nexus-public</id>
        <mirrorOf>*</mirrorOf>
        <name>Nexus Public</name>
        <url>http://nexus.kim.com/repository/maven-public/</url>
    </mirror>
	 
    <!-- 配置阿里云镜像 -->
	<mirror>
		<id>alimaven</id>
		<name>aliyun maven</name>
		<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
		<mirrorOf>central</mirrorOf>
	</mirror> 
  </mirrors>
	
  <profiles>
	<!-- 配置jdk版本 -->
	<profile>
	  <id>JDK-1.8</id>
      <activation>
		<activeByDefault>true</activeByDefault>
		<jdk>1.8</jdk>
      </activation>
	  <properties>
		<maven.compiler.source>1.8</maven.compiler.source>
		<maven.compiler.target>1.8</maven.compiler.target>
		<maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
	  </properties>
    </profile>
  </profiles>

</settings>
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

# 配置环境变量

在系统环境变量配置MAVEN_HOME

MAVEN_HOME
你所安装的maven路径
1
2

在Path添加

%MAVEN_HOME%\bin
1

查看maven版本

mvn -v
1

# 八、Maven私服

# 私服使用场景

1、公司不能连接公网,可以用一个私服务来统一连接。

2、公司内部jar 组件的共享。

# Maven下载依赖过程

Maven先从本地下载依赖包,若本地没有则去私服进行下载,若私服也没有再去远程仓库。

在远处仓库下载依赖包到本地仓库后,也会在私服中进行存储。

# 私服下载依赖配置

pom.xml 中配置远程仓库,作用范围为当前项目。

<repositories>
    <repository>
        <id>nexus-public</id>
        <name>my nexus repository</name>
		<url>http://192.168.0.200:8081/nexus/content/groups/public/</url>
    </repository>
</repositories>
1
2
3
4
5
6
7

或者在settings.xml 文件中配置远程仓库镜像,作用范围为本机maven环境。

<mirror>        
    <id>nexus-aliyun</id>
    <mirrorOf>*</mirrorOf>
    <name>Nexus aliyun</name>
    <url>http://192.168.0.200:8081/nexus/content/groups/public/</url>
</mirror> 
1
2
3
4
5
6

# 发布项目至私服配置

pom.xml 中配置远程仓库

<distributionManagement>
    <repository>
        <id>nexus-release</id>
        <name>nexus release</name>
        <url>http://192.168.0.200:8081/nexus/content/repositories/releases/</url>
    </repository>
    <snapshotRepository>
        <id>nexus-snapshot</id>
        <name>nexus snapshot</name>
        <url>http://192.168.0.200:8081/nexus/content/repositories/snapshots/</url>
    </snapshotRepository>
</distributionManagement>
1
2
3
4
5
6
7
8
9
10
11
12

settings.xml 文件中设置server

<server>
    <id>nexus-snapshot</id>
    <username>deployment</username>
    <password>deployment123</password>
</server>
<server>
    <id>nexus-release</id>
    <username>deployment</username>
    <password>deployment123</password>
</server>
1
2
3
4
5
6
7
8
9
10

# 九、Maven相关问题

# 清除lastUpdated文件

# windows系统

cd %userprofile%\.m2\repository

for /r %i in (*.lastUpdated) do del %i
1
2
3

# linux系统

find /app/maven/localRepository -name "*.lastUpdated" -exec grep -q "Could not transfer" {} \; -print -exec rm {} \;
1

# 十、Nexus相关问题

# deploy RELEASE 报错maven return code is:400

报错描述:

maven在部署(deploy) RELEASE版本时候,重复执行deploy时抛的异常,报错如下:

maven return code is:400,ReasonPhrase:Repository does not allow updating assets
1

分析

因为本身设置为RELEASE版本,即表示该版本为发布版本,不可更改。

Nexus存储库的更新策略,默认就是不允许更新项目(Disable redeploy)。

解决方案

  • 方案一(该方案可行但不建议):

Nexus具体设置步骤:

  1. 访问私有库管理界面http://xxx.xxx.xxx.xxx:8081
  2. 登录管理员账号(默认:admin/admin123)
  3. 进入设置界面->repository->repositories->maven-releases(目标库)->setting->Deployment pollcy(Allow redeploy)允许更新
  • 方案二:

登录私有库管理界面,删除对应报错的项目,重新进行deploy。

# 十一、Maven命令

构建.bat文件,手动执行maven相关命令。

# 清除本地仓库

清理 Maven 本地仓库中下载失败的包,即以lastUpdated为后缀。

cleanlocal.bat

@echo off
echo.
echo [信息] 清理 Maven 本地仓库中下载失败的包。
echo.

set REPOSITORY_PATH=D:\install_java\maven\mavenRepository\com\myname\project

rem 正在搜索...
for /f "delims=" %%i in ('dir /b /s "%REPOSITORY_PATH%\*lastUpdated*"') do (
    del /s /q %%i
)
rem 搜索完毕

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

# 清除项目

mvn clean执行,在target文件夹中的一切都将被删除。

clean.bat

@echo off
echo.
echo [信息] 清理target目录。
echo.

cd %~dp0
cd../../project

for /D %%s in (canteen*) do (
    call mvn clean -f %%s
)

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

# 打包至本地仓库

执行mvn install,部署项目至本地Maven仓库

install.bat

@echo off
echo.
echo [信息] 部署项目至本地Maven仓库。
echo [注意] 如果发生异常,运行多几次即可。
echo.

set SETTING=D:\install_java\maven\apache-maven-3.8.1\conf\settings.xml
set REPOSITORY_PATH=D:\install_java\maven\mavenRepository\com\myname\project
echo [信息] 清除本地Maven仓库的指定库。
rd /s /q %REPOSITORY_PATH%

cd %~dp0
cd../../project

echo ==============================
echo ========部署 父项目
echo ==============================
call mvn clean install -f project-dependencies -s %SETTING%
call mvn clean install -f project-parent -s %SETTING%

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

# 部署至远程仓库

执行mvn deploy,部署项目至本地Maven仓库和远程Maven仓库

deploy.bat

@echo off
echo.
echo [信息] 部署项目至本地Maven仓库和远程Maven仓库。
echo [注意] 如果发生异常,运行多几次即可。
echo.

set SETTING=D:\deploy_java\maven\apache-maven-3.8.1\conf\settings.xml
set REPOSITORY_PATH=D:\deploy_java\maven\mavenRepository\com\myname\project
rd /s /q %REPOSITORY_PATH%

cd %~dp0
cd../../project


echo ==============================
echo ========部署 父项目
echo ==============================
call mvn clean deploy -f project-dependencies -s %SETTING%
call mvn clean deploy -f project-parent -s %SETTING%

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

# 十二、Maven相关资料

Maven官网 (opens new window)

Maven中央仓库repository (opens new window)

Maven官方下载链接 (opens new window)