# 一、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>
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 总共包含三大生命周期:
clean Lifecycle
:清理生命周期,用于清理项目;default Lifecycle
:默认生命周期,用于编译、打包、测试、部署等;site Lifecycle
: 站点文档生成,用于构建站点文档;
三大生命周期其相互独立执行,也可以合在一起执行。
但lifecycle 中的phase 是有严格执行的顺序的,比如必须是先执行完compile 才能执行pakcage 动作。
此外phase 还有包含逻辑存在,即当你执行一个phase 时 其前面的phase 会自动执行。例如执行编译mvn package
前会先自动执行mvn validate
到mvn 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
9system 除了可以用于引入系统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
9import:只在
dependencyManagement
标签中使用,解决Maven单依赖。
# 四、Maven聚合与继承
# 聚合
聚合是指将多个模块整合在一起,统一构建,避免一个一个的构建。聚合需要个父工程,然后使用 <modules>
进行配置其中对应的是子工程的相对路径
<modules>
<module>kim-client</module>
<module>kim-server</module>
</modules>
2
3
4
# 继承
继承是指子工程直接继承父工程 当中的属性、依赖、插件等配置,避免重复配置。
- 属性继承:
- 依赖继承:
- 插件继承:
上面的三个配置子工程都可以进行重写,重写之后以子工程的为准。
# 依赖管理
通过继承的特性,子工程是可以间接依赖父工程的依赖,但多个子工程依赖有时并不一至,这时就可以在父工程中加入 <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>
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}
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>
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>
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
2
3
4
- 简化版的命令
maven官方提供的插件,在执行时默认可以省略groupId
,以及maven-
和-plugins
,version
信息。
maven会自动去下载最新版本的插件执行。
# 简化版命令
mvn compiler:compile
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>
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>
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路径
2
在Path添加
%MAVEN_HOME%\bin
查看maven版本
mvn -v
# 八、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>
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>
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>
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>
2
3
4
5
6
7
8
9
10
# 九、Maven相关问题
# 清除lastUpdated文件
# windows系统
cd %userprofile%\.m2\repository
for /r %i in (*.lastUpdated) do del %i
2
3
# linux系统
find /app/maven/localRepository -name "*.lastUpdated" -exec grep -q "Could not transfer" {} \; -print -exec rm {} \;
# 十、Nexus相关问题
# deploy RELEASE 报错maven return code is:400
报错描述:
maven在部署(deploy) RELEASE版本时候,重复执行deploy时抛的异常,报错如下:
maven return code is:400,ReasonPhrase:Repository does not allow updating assets
分析:
因为本身设置为RELEASE版本,即表示该版本为发布版本,不可更改。
Nexus存储库的更新策略,默认就是不允许更新项目(Disable redeploy)。
解决方案:
- 方案一(该方案可行但不建议):
Nexus具体设置步骤:
- 访问私有库管理界面http://xxx.xxx.xxx.xxx:8081
- 登录管理员账号(默认:admin/admin123)
- 进入设置界面->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
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
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
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21