Maven基础概念与使用(一)
前言
为什么需要自动化构建工具
一个Java项目要部署上线,最简单的构建过程都要经过编译、打包,项目比较少并且互相没有依赖时,我们可以手动调用javac命令编译java源文件,调用jar命令将class文件打包,当工程项目非常多, 并且很多有依赖关系,甚至一些复杂的项目还有很多流程需要处理,如Junit测试、资源过滤处理等等,每次手动机械式操作效率非常低。
本地开发时,本地的IDE工具如Idea、Eclipse、Vscode等代替我们做了大量的工作,当项目上线时, 线上服务器并没有IDE工具,因此需要自动化构建工具来完成项目的构建打包。
Java自动化构建工具的三驾马车
Ant
完全开放的程序式构建工具,没有任何约定,所有的构建过程需要开发人员全部编写在 build.xml配置文件中,过程非常繁琐,并且不支持依赖统一管理。
build.xml示例<?xml version="1.0" encoding="UTF-8"?> <!-- name是当前工程的名称,default是默认执行的任务,basedir是工作目录 --> <project name="ExampleApp" default="run" basedir="."> <!-- 源代码目录 --> <property name="src" value="src"/> <!-- 编译后的字节码文件目录--> <property name="dest" value="classes"/> <!-- 最终生成的jar包 --> <property name="finalJarName" value="example-app-1.0.jar"/> <!-- 定义了一个init任务 --> <target name="init"> <!-- 建立classes目录 --> <mkdir dir="${dest}"/> </target> <!-- 定义编译任务,依赖了init任务 --> <target name="compile" depends="init"> <javac srcdir="${src}" destdir="${dest}" classpath="..."/> </target> <!-- 打jar包 --> <target name="build" depends="compile"> <jar destfile="${finalJarName}" basedir="classes"> <!-- 添加MANIFEST --> <manifest> <attribute name="Created-By" value="example"/> <attribute name="Main-Class" value="com.example.train.App"/> <attribute name="Class-Path" value="lib/guava-18.0.jar;xxx.jar"/> </manifest> </jar> </target> <!-- 运行 --> <target name="run" depends="build"> <java classname="com.example.train.App" classpath="${finalJarName}" /> </target> </project>
- Maven
XML声明式构建工具,引入了生命周期概念,支持依赖管理,大部分的构建工作(如编译、打包)都可通过生命周期阶段绑定的默认插件来完成,不允许在XML中编写任何自定义任务,必须通过插件来实现。
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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example.train</groupId> <artifactId>boot-jar-test-demo</artifactId> <packaging>jar</packaging> <version>1.0</version> <dependencies> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>18.0</version> </dependency> </dependencies> <!-- 自定义构建过程 --> <build> <plugins> <plugin> ... </plugin> </plugins> </build> </project>
- Maven
Gradle
综合了Ant与Maven两者的特点,配置文件语法简洁,可以自由定义task,同时又支持插件来完成大部分构建工作,相比Maven,它还支持Groovy、Kotlin、Scala、C++、Android等项目的构建,它在性能、用户体验上更好,但是它很多优秀理念与约定都来自于Maven。
build.gradle示例buildscript { ext { springBootVersion = '2.0.3.RELEASE' } dependencies { classpath("org.springframework.boot:spring-boot-gradleplugin:${springBootVersion}") } } // 定义变量 def env = System.getProperty("profile") ?: "local" dependencies { compile project(":container-api") compile (group: 'org.apache.httpcomponents', name: 'httpclient',version: '4.5.10') { force = true } } tasks.withType(JavaCompile) { options.encoding = "UTF-8" } bootJar{ baseName = 'example-app' } // 注册一个task tasks.register('removeInput', Delete) { delete 'inputs/3.txt' }
Maven到底是什么
Maven是目前最流行的Java项目自动化构建工具,它通过定义
POM
(Project Object Model)和一系列插件来标准化整个项目的构建,同时它又是一个项目管理工具,通过Maven可以整合与拆分项目模块(Module),解决项目之间的依赖关系。安装
访问Maven官方网站 https://maven.apache.org/ , 进入 Download 页面, 选择maven3的稳定版本进行下载,当前项目中使用比较多的应该是
3.5.0
版本,可进入 https://archive.apache.org/dist/maven/maven-3/3.5.0/binaries/ 选择对应的系统版本进行下载。安装Maven之前,请先安装JDK,同时配置JAVA_HOME环境变量。Linux
首先通过命令工具
wget
下载 apache-maven-3.5.0-bin.tar.gz,或者本地下载后直接上传到服务器。- 解压
tar -zxvf apache-maven-3.5.0-bin.tar.1 gz -C /usr/local
配置环境变量,通过命令
vim /etc/profile
打开文件,在末尾增加如下配置MAVEN_HOME=/usr/local/apache-maven-3.5.0 PATH=$PATH:$MAVEN_HOME/bin MAVEN_OPTS="-Xms256m -Xmx512m" export MAVEN_HOME export PATH export MAVEN_OPTS
- 刷新 /etc/profile
source /etc/profile
验证安装
mvn -v
Windows
下载 apache-maven-3.5.0-bin.zip ,将解压后的内容提取到指定的目录
配置环境变量
进入 桌面->电脑->右键属性->高级系统设置->高级->环境变量, 在系统环境变量中增加一条 MAVEN_HOME=D:\tools\apache-maven-3.5.0
,同时在path环境变量中 新增Maven路径%MAVEN_HOME%/bin
。验证
打开一个新的CMD终端,输入如下命令验证是否成功安装
mvn -v Apache Maven 3.5.0 (ff8f5e7444045639af65f6095c62210b5713f426; 2017-04- 04T03:39:06+08:00) Maven home: D:\tools\apache-maven-3.5.0\bin\.. Java version: 1.8.0_191, vendor: Oracle Corporation Java home: C:\Program Files\Java\jdk1.8.0_191\jre Default locale: zh_CN, platform encoding: GBK OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"
基础配置与概念
POM
Project Object Model(POM)
,项目对象模型,POM将一个项目抽象为具体的模型,然后Maven通过POM来对项目进行管理。POM的详细配置来主要自于Maven项目根目录下的pom.xml文件,但项目构建时最终生效的POM内容可能来自于三个模块的合成。
对于相同配置项,项目pom.xml的优先级最高,在项目根目录(pom.xml文件所在同级目录)下执行命令即可查看最终生效的POM。
mvn help:effective-pom
每个POM默认都隐式继承了Maven定义的超级POM,可通过如下方式查看超级POM内容
- 当前安装的Maven版本是3.5.0,在%MAVEN_HOME%/lib目录下有一个maven-model-builder-3.5.0.jar,将该jar包解压后,在org\apache\maven\model下有一个pom-4.0.0.xml文件,即默认超级POM。
- 在Maven官方网站查看超级POM定义,访问 https://maven.apache.org/ref/3.5.0/maven-modelbuilder/super-pom.html 。
默认约定
Maven项目的基本目录结构
D:\campus\workspace\use-plugin-demo>tree
├─src
│ ├─main
│ │ ├─java
│ │ └─resources
│ └─test
│ ├─java
│ └─resources
└─target
├─classes
Maven的目标是尽可能将项目的构建过程自动化,因此默认约定以下目录结构,默认约定都是在超级POM中定义的。
注意: 不要在项目pom.xml中覆盖超级POM定义的默认目录结构,因为Maven的核心理念是约定大于配置,配置大于编码。
Artifact
artifact在Maven中可以是任何文件,大部分情况下可能是POM文件或者JAR文件,只要通过坐标能够将其定位就可以称为artifact,跟Docker Harbor镜像仓库中的artifact类似。artifact有三个非常重要的坐标,简称GAV, 通过GAV可以在同一个仓库中确定唯一的artifact。
- groupId 公司或组织域名倒序,如 com.example.train
- artifactId 具体的项目,如 course-demo
- version 版本,如 1.0
<dependency>
<groupId>com.example.train</groupId>
<artifactId>course-demo</artifactId>
<version>1.0</version>
</dependency
通过这个GAV坐标定位到的文件就是com/example/train目录下的course-demo-1.0.jar,jar文件所在目录通常还会有一个对应的pom文件,也称为元数据文件。
其它几个可选的坐标属性
classifier
<dependency>
<groupId>com.example.train</groupId>
<artifactId>course-demo</artifactId>
<version>1.0</version>
<classifier>jdk7</classifier>
</dependency>
配置了classifier属性后,定位到的文件是com/example/train/course-demo-1.0-jdk7.jar。
extension
在pom.xml中一般通过配置type属性,对应的ArtifactHandler会进行处理,下面是常用的部分type类型。
当在pom.xml中进行如下配置时,也能定位到文件com/example/train/course-demo-1.0-jdk7.jar。
<dependency>
<groupId>com.example.train</groupId>
<artifactId>course-demo</artifactId>
<version>1.0</version>
<type>test-jar</type>
</dependency>
此时ArtifactHandler是test-jar,classifier是tests,extension是jar,通过type属性可以辅助定位到artifact以及是否加入classpath等,不填写type默认jar。
仓库
Maven使用仓库来存储artifacts(jar),项目中的依赖包都是从仓库中下载,在项目中构建好的artifact也可以安装上传到仓库中。
本地仓库(Local Repository)
- 位于本机文件系统目录,主要用来缓存从远程仓库下载的依赖包,通过mvn install命令也可将构建好的jar存放于本地仓库。
- Maven安装后,本地仓库默认位置是${user.home}/.m2/repository,由于用户目录一般位于系统盘,在项目开发过程中,本地仓库缓存的依赖包会非常庞大,强烈建议修改默认位置。
中央仓库(Central Repository)
- Maven官方仓库,位于国外,下载速度非常慢
- 在超级POM中定义,所有项目默认都从中央仓库下载依赖,地址:https://repo.maven.apache.org/maven2
远程仓库(Remote Repository)
远程仓库是相对于本地仓库而言,需要通过网络访问的仓库都称为远程仓库,中央仓库也是一种远程仓库。
- 私有仓库(局域网):公司内网搭建的Nexus私服
- 开放仓库(公网):代理了中央仓库,用户就近访问,提高下载速度,如阿里云仓库、红帽子仓库等。
如图所述,世界各地任何项目构建时,任何依赖都需要请求中央仓库,这会给中央仓库带来巨大的访问压力,因此Maven又推出了Mirror(镜像)配置策略,给某个仓库A配置了Mirror,那Maven构建项目时不会去请求A,而是请求A仓库配置的Mirror仓库。
在国内,中央仓库网络几乎访问不通,因此通常给中央仓库配置一个Mirror,加快访问速度,这个Mirror仓库可以是国内的公网远程仓库,也可以是内网的私服仓库。
<mirrors>
<mirror>
<id>innerNexus</id>
<!-- 给中央仓库配置Mirror, 这个id代表的就是中央仓库,在超级POM中定义的id -->
<mirrorOf>central</mirrorOf>
<name>inner nexus server</name>
<url>http://120.99.18.186:8880/repository/maven-public/</url>
</mirror>
</mirrors>
通过GAV坐标在同一个仓库可以确定唯一artifact,如果混用多个远程仓库可能jar包不兼容。
Settings
Maven配置settings通常有两种级别
全局settings
Maven安装时自动生成的,${MAVEN_HOME}/conf/settings.xml。用户settings
通常位于${user.home}/.m2/settings.xml
两个settings文件同时存在,它们的内容将进行合并,对于相同配置项用户settings配置优先。
<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 https://maven.apache.org/xsd/settings-1.0.0.xsd">
<!-- 本地仓库地址 -->
<localRepository/>
<!-- 当maven需要输入值的时候, 是否交由用户输入, 默认为true -->
<interactiveMode>true</interactiveMode>
<!-- 基于安全性或者网络问题,可设置为离线模式, 默认false -->
<offline/>
<!-- 插件的groupId,当maven执行未指定groupId的插件命令时在此列表搜索, mvn test:test-->
<!-- 不配置pluginGroup,则要指定完整插件坐标执行 mvn com.example:test-mavenplugin:v1.0:test -->
<pluginGroups/>
<!-- 远程仓库服务器的访问凭证信息 -->
<servers/>
<!-- 镜像加速 -->
<mirrors/>
<!-- 网络代理 -->
<proxies/>
<!-- Profile属性列表 -->
<profiles/>
<!-- 激活的Profile配置 -->
<activeProfiles/>
</settings>
在settings文件中可以编写插值表达式,表达式内容通常来自于系统属性(System.getProperties)或者环境变量。
<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 https://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository>${user.home}/.m2/repository</localRepository>
<offline>false</offline>
......
</settings>
在开发maven项目过程中,需要在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
https://maven.apache.org/xsd/settings-1.0.0.xsd">
...
<localRepository>E:/m2/repo</localRepository>
...
</settings>
不配置,默认 ${user.home}/.m2/repository
。
- Servers
远程仓库的依赖下载与上传通常在项目的pom.xml中定义,但是远程库所在的服务器信息,如访问用户名、密码等,往往因为不适合与POM一起发布,所以一般配置在settings文件中。
<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
https://maven.apache.org/xsd/settings-1.0.0.xsd">
...
<servers>
<server>
<id>example_snapshot</id>
<username>user</username>
<password>6dc85a12</password>
</server>
<server>
<id>example</id>
<username>user</username>
<password>6dc85a12</password>
</server>
</servers>
server中的id自定义不重复就行,该id与pom文件中distributionManagement中repository元素的id相匹配,同时与当前settings中的mirror中的id相匹配,除了username,password属性,还可以定义文件目录权限、密钥key路径。
- Mirrors
<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
https://maven.apache.org/xsd/settings-1.0.0.xsd">
...
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<name>Nexus aliyun</name>
<url>https://maven.aliyun.com/repository/central</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
...
</settings>
mirror相当于一个拦截器,它会拦截maven对remote repository的相关请求,把请求里的remote repository地址,重定向到mirror里配置的地址。id用于区分mirror,这个id与Servers中的id相匹配,当需要使用相关凭据连接远程库时,根据id在servers配置中查找。
Mirror配置规则
- 匹配所有仓库请求,即将所有的仓库请求都转到该镜像上
<mirrorOf>*</mirrorOf>
- 仓库repo1和repo2的请求转到该镜像上,使用逗号分隔多个远程仓库
<mirrorOf>repo1,repo2</mirrorOf>
- 匹配所有仓库请求,repo1除外,使用感叹号将仓库从匹配中排除
<mirrorOf>*,!repo1</miiroOf>
通常配置central镜像即可,我们也可以配置一个所有仓库的镜像,以保证该镜像是Maven唯一使用的仓库。
pom与settings中定义的仓库与镜像优先级关系
mirror(settings.xml)> repository(pom.xml)> repository(settings.xml)
- Profiles
Profile可以定义一系列的配置信息,然后指定其激活条件。通过定义多个profile,根据不同的激活条件从而达到不同环境使用不同的构建配置信息。
- settings.xml 中的 profile 元素是 pom.xml 中 profile 元素的裁剪版本。
- settings.xml 负责的是整体的构建过程, pom.xml 负责单独的项目对象构建过程。
- settings.xml 只包含了id, activation, repositories, pluginRepositories 和 properties 元素,不可自定义标签元素。
- settings.xml与pom.xml定义了相同id的profile,内容进行合并叠加,settings中配置优先级更高。
查看当前激活的profile
mvn help:active-profiles
命令行结构
Maven的核心是POM,除了少数几个帮助性命令(help, version)可以在任何地方执行,其它的命令都必须在项目根目录下执行,即编写了pom.xml的目录。
mvn [options] [<goal(s)>] [<phase(s)>]