1、仓库,私服,repository,servers,mirror 标签
2、dependencyManagement,父子 pom
3、依赖传递规则:1、最短路径,2、路径长度相同时,使用写在上面的
Maven 是项目构建和依赖管理工具,提供仓库(公共和私服),提供插件(扩展功能)
项目构建简单点理解就是把源码,编译,生成 jar 包或者 war 包的过程。
依赖管理就是项目中依赖的各种 jar 包,Maven 能用简单的方式对这个依赖 jar 包进行管理
maven 的安装非常简单,参考官网文档:https://maven.apache.org/install.html
1、安装好 jdk,设置好 JAVA_HOME
环境变量,指向 jdk的安装目录。或者让 java
命令在任何目录都能执行
2、解压Maven安装包
unzip apache-maven-3.9.1-bin.zip
或者
tar xzvf apache-maven-3.9.1-bin.tar.gz
3、在环境变量中设置 Maven
mac 或者 Linux 环境:执行命令 vim ~/.bash_profile
编辑文件
export MAVEN_HOME=/Users/awesome/tools/apache-maven-3.8.2
export PATH=$MAVEN_HOME/bin:$GRADLE_HOME/bin:$PATH
保存后,执行 source ~/.bash_profile
,然后执行 mvn -v
,看能否成功打印 Maven 信息
Maven 的安装目录下的 /conf/settings.xml
groupId(必须定义):不关键,比如com.dianping.zebra,或者 com.sankuai.meituan
artifactId必须定义:项目中的一个模块,推荐用模块名,比如xy-trade-microloan-thrift-api,或者 zebra-client
version(必须定义):版本,比如 2.9.2-SNAPSHOT
packaging(可选定义):定义了maven的打包方式,不定义packaging时默认jar包,当然也可以定义war包
scope(可选定义):作用范围,默认为compile。如果test,表示只能在测试代码中import该依赖,主代码依赖会报错
classifier(不能直接定义):定义一些附属组件,比如【javadoc文档】和【sources源代码】
依赖:用于描述一个依赖的 jar 包,在 pom.xml 文件中定义
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.4version>
dependency>
<dependency>
<groupId>org.powermockgroupId>
<artifactId>powermock-api-mockito2artifactId>
<version>2.0.2version>
<scope>testscope>
dependency>
<dependency>
<groupId>it.lianyangguoronggroupId>
<artifactId>codecartifactId>
<version>1.0version>
<scope>systemscope>
<systemPath>${basedir}/lib/lianyangguorong/commons-codec-sdk-1.0-SNAPSHOT.jarsystemPath>
dependency>
:依赖范围,compile,test,provided,runtime,system,import
概述:用来控制依赖与这三种classpath(编译,测试,运行)的关系,有以下几种选择
compile(默认):在【编译,测试,运行】时都使用该依赖。比如spring-core(都需要用到)
test:只对【test文件夹下】有效,比如JUnit,mockito(只有在单元测试才用到这些依赖)
provided:已提供该依赖。对于【编译和测试】有效。在运行时无效,比如 servlet-api,编译和测试的时候需要,运行的时候由于容器已经提供,就不需要了。
runtime:对【测试和运行】有效,编译主代码时无效。典型的例子是JDBC驱动实现
system:类似provided,但是要通过systemPath 指定文件路径
import:导入依赖范围,后面解释dependencyManagement时再介绍
何为依赖传递:【我的项目A】依赖【spring-core】,【spring-core】pom.xml中依赖【commons-logging】。则 【我的项目A】依赖【commons-logging】
依赖传递的范围:【我的项目A】依赖scope=test【spring-core】,【spring-core】依赖scope=compile【commons-logging】。则【我的项目A】依赖scope=test【commons-logging】
依赖的规则:第一原则优先,相同则采用第二原则
第一原则:依赖路径越短越优先。比如:A->B->C->X(1.0);A->D->X(2.0)。由于X(2.0)的路径短,X(2.0)会被解析使用
第二原则:看pom.xml中的依赖顺序,谁写在上面谁先依赖。比如A->B->Y(1.0);A->C->Y(2.0)。如果pom.xml文件中B写在C的上面,则Y(1.0)会被解析使用
配置 true ,则该依赖为【可选依赖】
【可选依赖】有什么用:不具有传递性
比如:A->B,B->mysql.jar(可选),B->oracle.jar(可选)
则依赖不会传递,即 A不会依赖mysql.jar和oracle.jar。换句话说:项目里没有mysql.jar和oracle.jar不会对A产生任何影响
为什么要【可选依赖】
假如项目B实现了两个特性,其中的特性一依赖于X,特性二依赖于Y,而且这两个特性是互斥的,用户不可能同时使用这两个特性
比如B是一个持久层隔离工具包,特性一用于mysql,特性二用于oracle,这两者是互斥的,究竟用哪个,让用户自己来手动选(手动引入)
例子:B的pom.xml,用户如果要用mysql的jar包,需要在A中自己手动引
<dependencies>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.10version>
<optional>trueoptional>
dependency>
<dependency>
<groupId>postgresqlgroupId>
<artifactId>postgresqlartifactId>
<version>8.4-701.jdbc3version>
<optional>trueoptional>
dependency>
dependencies>
A 的 pom.xml
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.10version>
<optional>trueoptional>
dependency>
假如项目里有个第三方依赖,该依赖还依赖了另一个1.0.0-SNAPSHOT版本的库,那么该1.0.0-SNAPSHOT就会成为当前项目的传递性依赖。此时我想排除该依赖,则要使用标签
需要注意的是:声明exclusion时候只需要groupId和artifactId,不需要version(显然,根据前两者就可以在pom.xml中唯一确定一个Maven坐标了)
假如项目里有很多Spring Framework的依赖(如下),你希望保持它们版本号一致,并且统一管理它们的版本
org.springframework:spring-core:2.5.6
org.springframework:spring-beans:2.5.6
org.springframework:spring-context:2.5.6
org.springframework:spring-context-support:2.5.6
使用标签
可以通过命令查看项目中的所有依赖和依赖关系
显示所有已解析依赖:mvn dependency:list
查看解析后的依赖树:mvn dependency:tree
分析当前的项目依赖:mvn dependency:analyze
一般在 idea 中安装 Maven Helper ,方便可视化查看依赖关系
mvn clean:清理 target/目录
mvn compile:编译项目主代码,生成 class 文件到 target/classes 目录
mvn test:执行单元测试
mvn package:打包,如果POM中没有指定,默认打jar包,位于target/目录中
mvn install:将jar包安装到本地仓库
mvn deploy: 将 jar包部署到远程仓库
何为仓库:Maven将所有构建完成的jar包安装部署到Maven本地仓库(本地电脑上的一个文件夹),所有项目可以共用
只分为两类:【本地仓库】和【远程仓库】,一个用户只有一个【本地仓库】,但是可以配置多个【远程仓库】,远程仓库中,一般公司会提供私服仓库
jar查找规则
(1)先从【本地仓库】找
(2)找不到再去【远程仓库】下载到【本地仓库】
(3)如果都没有则报错
默认配置下,【本地仓库】的路径为:用户目录/.m2/repository/…
比如Windows:C:\Users\jyy.m2\repository\
如何更改【本地仓库】地址?
修改 $MAVEN_HOME/conf/settings.xml ,增加一行 标签配置。
<localRepository>/Users/xxxx/tools/maven_repositorylocalRepository>
如何安装【本地Maven项目】到【本地仓库】?
命令:mvn install
中央仓库:
Maven自带的远程仓库,包含了绝大部分开源的构件:https://mvnrepository.com/
Maven的安装文件自带【中央仓库】的配置,可以通过 $MAVEN_HOME/lib/maven-model-builder-3.0.jar中的 org/apache/maven/model/pom-4.0.0.xml看到,该pom文件是一个超级POM,所有Maven项目都会继承
私服:架设在局域网内,代理外部广域网上的远程仓库
jar包查询规则:先找【本地仓库】,再找【私服】,找不到再找【远程仓库】
为什么需要私服:
有些jar包是公司内部用的,不开源,可以放在私服
如果Internet不稳定,私服提高了稳定性
比较著名的有:Nexus
在pom.xml中添加 标签
:必须是唯一的,Maven自带的中央仓库使用的id为central,如果其他仓库id声明也使用central,则会覆盖中央仓库的配置
:名称,随便去取
:仓库地址,一般是http协议格式,可以在浏览器中打开
和标签
snapshots的为false,表示不允许从 JBoss仓库下载【快照版本】的jar包
releases 的 为true,表示可以从 JBoss仓库下载【发布版本】的jar包
:从Maven远程仓库检查更新的频率,3种选择
never(从不检查更新)
always(每次都检查)
X(每隔X分钟检查一次)
:检查策略,3种选择
warn(出错则输出warn警告)
fail(出错则构建失败)
ignore(完全忽略检验失败)
:default表示仓库的布局是Maven2和Maven3的默认布局
<profiles>
<profile>
<id>company_profileid>
<repositories>
<repository>
<id>my_maven_repositoryid>
<name>Nexusname>
<url>http://nexus.xxxxx.com/repository/maven/url>
<releases>
<enabled>trueenabled>
releases>
<snapshots>
<enabled>trueenabled>
snapshots>
repository>
repositories>
<pluginRepositories>
<pluginRepository>
<id>my_maven_repositoryid>
<name>Nexusname>
<url>http://nexus.xxxxx.com/repository/maven/url>
<releases>
<enabled>trueenabled>
releases>
<snapshots>
<enabled>trueenabled>
snapshots>
pluginRepository>
pluginRepositories>
profile>
profiles>
<activeProfiles>
<activeProfile>company_profileactiveProfile>
activeProfiles>
settings.xml中配置 标签。需要注意的是,必须与前面pom.xml中的id相同
<servers>
<server>
<username>xxxxxxusername>
<password>passwordpassword>
<id>my_maven_repositoryid>
server>
servers>
在项目的 pom.xml 文件中,增加以下配置
<distributionManagement>
<repository>
<id>myCompany-nexus-releasesid>
<name>myCompany Nexus Repositoryname>
<url>http://xxx.xxxxxxx.com/repository/releasesurl>
repository>
<snapshotRepository>
<id>myCompany-nexus-snapshotsid>
<name>myCompany Nexus Repositoryname>
<url>http://xxx.xxxxxxx.com/repository/snapshotsurl>
snapshotRepository>
distributionManagement>
表示:releases版本的仓库地址
表示:snapshots版本的仓库地址
标签必须要与 settings.xml中的id一致
需要注意的是,如果repository需要用户名密码的话,需要在 settings.xml 中配合标签使用
settings.xml文件内容:
<servers>
<server>
<username>xxxxxusername>
<password>passwordpassword>
<id>myCompany-nexus-releasesid>
server>
<server>
<username>xxxxxusername>
<password>passwordpassword>
<id>myCompany-nexus-snapshotsid>
server>
servers>
配置好之后:mvn clean deploy
命令会自动部署到远程仓库
比如中央仓库在外网,国内访问比较慢,可以配置中央仓库的国内镜像,相当于是覆盖了中央仓库的地址
何为镜像:就比如,阿里云提供了Maven仓库的国内镜像,国内用户下载起来会更快(https://maven.aliyun.com/repository/public)
在settings.xml中配置标签,代替某些的url
例1:下图的为central,表示用该url替代了【Maven中央仓库】,所有去中央仓库的请求都会转到该url
<mirror>
<id>aliyunmavenid>
<mirrorOf>centralmirrorOf>
<name>阿里云公共仓库name>
<url>https://maven.aliyun.com/repository/publicurl>
mirror>
例2:下图的为*,表示用该url替代了所有的配置,所有配置的都会转到该url镜像
<mirrors>
<mirror>
<id>aliyunmavenid>
<mirrorOf>*mirrorOf>
<name>阿里云公共仓库name>
<url>https://maven.aliyun.com/repository/publicurl>
mirror>
<mirror>
<id>aliyunmavenid>
<mirrorOf>*mirrorOf>
<name>阿里云谷歌仓库name>
<url>https://maven.aliyun.com/repository/googleurl>
mirror>
<mirror>
<id>aliyunmavenid>
<mirrorOf>*mirrorOf>
<name>阿里云spring仓库name>
<url>https://maven.aliyun.com/repository/springurl>
mirror>
<mirror>
<id>aliyunmavenid>
<mirrorOf>*mirrorOf>
<name>阿里云gradle-pluginname>
<url>https://maven.aliyun.com/repository/gradle-pluginurl>
mirror>
mirrors>
如果该镜像需要认证,则去settings.xml中配置即可
的用法
* :匹配所有远程仓库
external:* :匹配所有远程仓库,但是 locolhost 和 file://协议的除外,即匹配所有不在本机上的远程仓库
repo1, repo2 :匹配 repo1 和 repo2
*, !repo1 :匹配所有远程仓库, repo1除外(感叹号表示排除)
为何需要snapshot版本?快照版本的依赖,上传到仓库后,都会带着时间戳属性。当别人拉取依赖时,如果发现有更新时间戳的,Maven 就会重新拉取。默认更新频率是 1 天一次,可以修改仓库配置的 undatePolicy 调整。也可以使用命令 mvn clean install-U
maven的生命周期,可以理解为 Maven 为构建项目规定的动作,具体的动作由插件完成。
maven拥有3套相互独立的生命周期:分别是 clean(清理项目),default(构建项目),site(建立项目站点)
clean生命周期:主要用于清理项目
pre-clean:执行清理前需要完成的工作
clean:清理上一次构建生成的文件
post-clean:执行清理后需要完成的工作
default声明周期:三套生命周期中最核心的部分
site声明周期:主要目的是建立和发布项目站点
pre-site
site
post-site
site-deploy:将生成的项目站点发布到服务器上
Maven的核心仅仅是定义了生命周期,具体的任务由插件完成。
什么是插件目标
compiler:compile(maven-compiler-plugin的compile目标)
surefire:test(maven-surefire-plugin的test目标)
插件绑定
为了让用户不需要配置就能构建Maven项目,Maven在其主要生命周期绑定了很多插件的目标,比如常见的 clean,compile,package
插件配置参数
(1)命令行配置(常用)
常见形式:使用-D参数,伴随 key=value 形式
mvn install -Dmaven.test.skip=true
(2)pom.xml中全局配置
比如,配置compile时生成java1.8的字节码文件
<properties>
<java.version>1.8java.version>
<maven.compiler.source>${java.version}maven.compiler.source>
<maven.compiler.target>${java.version}maven.compiler.target>
properties>
org.springframework.boot
spring-boot-maven-plugin
org.apache.maven.plugins
maven-compiler-plugin
2.3.2
1.8
1.8
jib-maven-plugin
<plugin>
<groupId>com.google.cloud.toolsgroupId>
<artifactId>jib-maven-pluginartifactId>
<version>2.8.0version>
<configuration>
<allowInsecureRegistries>trueallowInsecureRegistries>
<from>
<image>openjdk:8-jdk-alpineimage>
from>
<to>
<image>${docker.registry.url}/${docker.registry.name}/${project.artifactId}:${project.version}
image>
<tags>
<tag>${project.version}tag>
tags>
<auth>
<username>${docker.registry.username}username>
<password>${docker.registry.password}password>
auth>
to>
<container>
<jvmFlags>
<jvmFlag>-Djava.security.edg=file:/dev/./urandomjvmFlag>
jvmFlags>
<volumes>
<volume>/tmpvolume>
<volume>/logsvolume>
volumes>
<ports>
<port>8080port>
ports>
<mainClass>com.heima.learn.storage.StorageApplicationmainClass>
<format>OCIformat>
<creationTime>USE_CURRENT_TIMESTAMPcreationTime>
container>
configuration>
<executions>
<execution>
<id>jib-maven-pluginid>
<phase>packagephase>
<goals>
<goal>buildgoal>
goals>
execution>
executions>
plugin>
docker-maven-plugin
<plugin>
<groupId>io.fabric8groupId>
<artifactId>docker-maven-pluginartifactId>
<version>0.33.0version>
<executions>
<execution>
<id>build-imageid>
<phase>packagephase>
<goals>
<goal>buildgoal>
goals>
execution>
executions>
plugin>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-war-pluginartifactId>
<version>2.6version>
<configuration>
<warName>project_namewarName>
configuration>
plugin>
本地不想安装 Tomcat 的可以使用这个插件
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<version>2.2version>
<configuration>
<port>8088port>
<path>/path>
<server>tomcat-development-serverserver>
<useTestClasspath>trueuseTestClasspath>
configuration>
plugin>
比如:存在两个同级的子模块,可以用一个【主pom.xml】管理多个【子pom.xml】
例如来自zebra项目的主pom文件
<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.0modelVersion>
<groupId>com.dianping.zebragroupId>
<artifactId>zebra-allartifactId>
<packaging>pompackaging>
<version>2.9.1version>
<name>zebra-allname>
<organization>
<name>Meituan Dianpingname>
<url>http://www.dianping.com/url>
organization>
<modules>
<module>zebra-daomodule>
<module>zebra-samplemodule>
<module>zebra-admin-webmodule>
<module>zebra-cat-clientmodule>
<module>zebra-clientmodule>
modules>
<description>zebradescription>
需要用到的标签
:主pom文件必须声明为pom,否则无法构建(但子pom文件可以不声明packaging,因为默认为jar)
:内容为【子pom文件】中的 ,即子项目名称
父模块与子模块的结构
父子结构:最常用的目录结构
平行结构:不太常用,父pom中中的路径需要变化,子 pom中的 parent 中需要通过指定父 pom.xml 的位置
为什么要聚合与继承:在所有子模块的【子pom】中,往往会写重复的依赖配置,比如spring-core, spring-beans等等
【子pom】如何继承【父pom】:标签
需要注意的是:一般采用【父子目录结构】无需声明,默认值是 …/pom.xml
默认情况下,父 pom 中定义的依赖,会被子 module 中完全继承。这样会存在问题,如果子 module 中不想完全继承父依赖,怎么处理?由此引入
能让子模块有选择的引用父模块的依赖
父模块的pom.xml:
<properties>
<commons-beanutils.version>1.8.3commons-beanutils.version>
<fastjson.version>1.2.83fastjson.version>
<commons.codec.version>1.8commons.codec.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>commons-beanutilsgroupId>
<artifactId>commons-beanutils-coreartifactId>
<version>${commons-beanutils.version}version>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>${fastjson.version}version>
dependency>
<dependency>
<groupId>commons-codecgroupId>
<artifactId>commons-codecartifactId>
<version>${commons.codec.version}version>
dependency>
dependencies>
dependencyManagement>
子模块的pom.xml:
<dependencies>
<dependency>
<groupId>commons-beanutilsgroupId>
<artifactId>commons-beanutils-coreartifactId>
dependency>
dependencies>
对于子模块
如果需要依赖:只需要配置groupId和artifactId。而version不需要写,只需要委托给父类管理就行了
如果不需要依赖:在子pom.xml中不写就行了,不写就不会引入
dependencyManagement中的依赖版本还会覆盖传递依赖版本
举个例子:项目中依赖的A,A依赖了B的1.0版本。如果在dependencyManagement中显示声明依赖B的2.0版本,那么A也会去依赖B的2.0版本
最佳实践:一般使用 dependencyManagement 统一管理项目依赖的版本
超级pom的坐标:对于Maven3,超级pom的目录为:maven/lib/maven-model-builder-x.x.x.jar中
超级pom中定义了什么?
(1)定义了【默认中央仓库】和【插件仓库】
(2)定义了【主代码/测试 输出目录】,【主代码输出目录】,【最终构件的名称格式】等等
(3)定义了【Maven内置插件】的默认版本
Maven提倡约定优于配置(Convention Over Configuration):在maven中只需要简单的配置pom文件,就可以实现 清除构建目录、创建目录、编译代码、复制依赖至目标目录,最后打包
maven约定如下
源码目录为 src/main/java
编译输出目录为 target/classes
打包方式为jar
包输出目录为 target
参考链接:https://blog.csdn.net/qq_41157876/article/details/119117070
1、安装后,指定本次仓库位置,方便调整
2、某个依赖 jar 包,从远程仓库拉取过程中可能失败,可以进入到本地仓库文件夹,删除对应的jar 包目录
3、多模块项目,使用dependencyManagement
4、settings.xml 文件中,指定镜像,如果公司有私服,指定私服地址
5、注意依赖传递原则,防止引入不兼容的版本的 jar 包
6、给 IDE 安装 Maven Helper 插件
博主水平有限,欢迎留言,指正错误,交流技术