原文:https://www.yuque.com/uy2gee/yfyp6h/maven
Maven配置
Maven配置生效原则
默认情况:配置生效(从前往后进行覆盖,不同配置合并)
- ~/.m2文件下 settings.xml
- 本机安装的apache maven文件下conf/settings.xml
- 项目中pom.xml
其本质:~/.m2/settings.xml是约定,在IDEA中maven默认指定了这个文件路径,使用时会遵循上述的默认情况,如果我们在IDEA中指定了maven的settings.xml的路径,那么~/.m2/settings.xml就不会生效
Pom中的profile机制
profile 里所配置的东西,在正常情况下是不会生效的,想要生效要指定激活他才行。
配置:
<profiles>
<profile>
<id>dev</id>
<properties>
<!--环境-->
<spring.profiles.active>dev</spring.profiles.active>
</properties>
<activation>
<!--默认是否开启-->
<activeByDefault>true</activeByDefault>
</activation>
</profile>
</profiles>
生效方式:
-P参数指定 : mvn install -Pdev
默认启动参数总开启:activeByDefault
IDEA开发工具中勾选:
Maven的依赖机制
坐标机制
groupId + artifactId + version + packaging + classifier,五个维度的坐标,唯一定位一个依赖包
任何一个项目,都是用这五个维度唯一定位一个发布包
实际上后面两个维度较为少用,99%的场景下,唯一定位一个依赖的就是三个维度,groupId + artifactId + version
groupId:组织ID
artifactId:项目模块ID
version:
版本号
SNAPSHOT:SNAPSHOT后缀的版本是非稳定版本,每次打包的时候都会重新去仓库拉取,deploy可以一直覆盖,其余版本号都是release版本,deploy后不能覆盖,只能在私服操作删除后再次进行提交。
packaging:
目前支持以下三种配置:
<packaging>pom</packaging>
<packaging>jar</packaging>
<packaging>war</packaging>
引用的时候使用的时<type>标签
classifier:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-hikaricp</artifactId>
<version>1.0.0</version>
<type>jar</type>
<classifier>jdk8</classifier>
</dependency>
查找坐标时会将classifier拼接在版本号后面,比如:hibernate-hikaricp-1.0.0-jdk8.jar
引入依赖
依赖查找网站:https://mvnrepository.com/
依赖的坐标示例:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-hikaricp</artifactId>
<version>1.0.0</version>
<type>jar</type>
<scope>test</scope>
<optional>true</optional>
<classifier></classifier>
</dependency>
optional:
<optional>true</optional>
此时依赖传递失效,不会向上传递
如果A依赖于B,B依赖于C,B对C的依赖是optional,那么A就不会依赖于C。反之,如果没有optional,根据传递性依赖机制,A会依赖于C。
scope:
maven在编译源代码的时候有一套classpath;在编译测试代码以及执行测试代码的时候,有一套classpath;运行项目的时候,有一套classpath;依赖范围就是用来控制依赖包与这三种classpath的关系的。
有如下参数可配置:
compile:默认,对编译、测试和运行的classpath都有效。一般都是用这种scope
test:仅仅对于运行测试代码的classpath有效,编译或者运行主代码的时候无效,仅仅测试代码需要用的依赖一般都会设置为这个范围,比如junit。一些测试框架,或者只有在测试代码中才会使用的一些依赖,会设置为test,这个的好处在于说,打包的时候这种test scope的依是不会放到最终的发布包里去的。减少发布包的体积。
provided:编译和测试的时候有效,但是在运行的时候无效,因为可能环境已经提供了,比如servlet-api,一般就是这个范围,在运行的时候,servlet容器会提供依赖。servlet-api是用来开发java web项目的,可能你在开发代码和执行单元测试的时候,需要在pom.xml里面声明这个servlet-api的依赖,因为要写代码和测试代码。但是最终打完包之后,放到tomcat容器里面去跑的时候,是不需要将这个servlet-api的依赖包打入发布包中的,因为tomcat容器本身就会给你提供servlet-api的包。
runtime:测试和运行classpath有效,但是编译代码时无效,比如jdbc的驱动实现类,比如mysql驱动。因为写代码的时候是基于javax.sql包下的标准接口去写代码的。然后在测试的时候需要用这个包,在实际运行的时候才需要用这个包的,但是编译的时候只要javax.sql接口就可以了,不需要mysql驱动类。一般我们声明mysql驱动的时候,不会设置为runtime,因为也许你开发代码的时候会用到mysql驱动特定的api接口,不仅仅只是用javax.sql。
system:
使用上与provided相同,不同之处在于该依赖不从maven仓库中提取,而是从本地文件系统中提取,其会参照systemPath的属性进行提取依赖。
import:
这个是maven2.0.9版本后出的属性,import只能在dependencyManagement的中使用,能解决maven单继承问题,import依赖关系实际上并不参与限制依赖关系的传递性。
依赖传递
比如A->B->C->X(1.0),A->D->X(2.0),A有两个传递性依赖X,不同的版本
此时就会依赖调解,就近原则,离A最近的选用,就是X的2.0版本
如果A->B->X(1.0)和A->D->X(2.0),
路径等长那么会选择第一声明原则,哪个依赖在pom.xml里先声明,就用哪个
排除传递依赖
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-hikaricp</artifactId>
<version>1.0.0</version>
<!-- 排除依赖 -->
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
依赖冲突
原因
因为传递依赖的机制导致高版本的依赖没有生效。
解决方式
1、使用mvn dependency:tree 查看依赖路径,查看冲突的jar在哪里被引用了
2、然后确定其中一个高版本的jar
3、使用上文中的<exclusions>进行排除那个那个低版本的jar的传递依赖
Maven的仓库
几种仓库介绍
本地仓库:
作用:
对远程仓库的一个缓存仓库,使用到的包会从远程仓库拉取到本地仓库后进行使用。
配置:
默认地址是 ~.m2/repository
可以通过setting.xml中的<localRepository>/User/c/maven/repository</localRepository>进行指定
在IDEA中也可以通过maven的设置中指定仓库地址
中央仓库:
一般指maven中默认的<id>central</id><url>https://repo.maven.apache.org/maven2</url> 仓库,配置在(maven-model-builder-3.6.3jar:org.apache.maven.model.pom-4.0.0.xml),中央仓库还有其他的,比如jboss,但是很少有人使用。
私服:
作用:
企业中搭建自己的私服,自己来管理仓库
配置:
配置在settrings.xml 或则 项目中的pom.xml中
有如下两种配置方式
<repositories></repositories>
通过profile配置仓库
<profile>
<id>nexus</id>
<repositories>
</repositories>
</profile>
镜像仓库:
作用:
镜像配置的 repositorie,将仓库设置的url改为镜像配置的url进行操作。
配置:
<mirrors>
<mirror>
<id>aliyun-maven</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
mirrorOf:指定需要镜像的仓库的id,多个仓库用 英文逗号(,)进行分割,central是maven默认的中央仓库地址。被镜像的仓库所配置的url将会失效。
仓库配置生效规则
配置的地方主要两种:settings文件 和 pom文件
主要分为两种配置方式:
直接配置仓库
<repositories></repositories>
通过profile配置仓库
<profile>
<id>nexus</id>
<repositories>
</repositories>
</profile>
原则分为两种:
settings 优于 pom
profile 优于 repositories
情况:
settings:profile -> pom:profile -> setting:repositories -> pom:repositories
上传到仓库配置
maven会根据模块的版本号(pom文件中的<version>版本号</version>)中是否带有-SNAPSHOT来判断这个是快照版本还是正式版本.
pom.xml
<distributionManagement>
<repository>
<!-- 和 service.id 要匹配 -->
<id>nexus-releases</id>
<name>maven-releases</name>
<url>http://192.168.1.15:8081/repository/maven-releases/</url>
<layout>default</layout>
<!--上传时指定版本,默认使用 version的版本-->
<!--<uniqueVersion>1.0.0</uniqueVersion>-->
</repository>
<snapshotRepository>
<id>nexus-snapshots</id>
<name>maven-snapshots</name>
<url>http://192.168.1.15:8081/repository/maven-snapshots/</url>
<layout></layout>
<uniqueVersion></uniqueVersion>
</snapshotRepository>
</distributionManagement>
setting.xml
<servers>
<server>
<id>nexus-release</id>
<username>admin</username>
<password>admin</password>
</server>
<server>
<id>nexus-snapshots</id>
<username>admin</username>
<password>admin</password>
</server>
</servers>
Nexus私服搭建使用
下载安装
自行百度
企业级私服玩法
nexus中的几个核心仓库作用
常见的仓库如下图:
maven-releases:存放公司releases版本的包。
maven-snapshots:存放公司snapshots版本的包。
maven-central:代理中央仓库(国内一般代理aliyun镜像,aliyun镜像了maven中央仓库)
maven-public:对上面的几个仓库做分组,可以通过这个分组仓库拉取到分组内的所有仓库的包。
maven-public配置玩法:
权限体系
nexus默认有2个账号,admin 和 anonymous。
admin: 具有管理权限,可以拉取,上传,删除,管理nexus后台
anonymous:匿名用户,我们不提供账号密码的时候默认使用的就是这个匿名账号,该账号只能拉取。也可以在这设置中关闭匿名用户,让我们的私服的任何操作必须登录
权限管理
设置是否支持匿名账户
设置定时任务
配置仓库的的一些定时任务,比如:删除不完整的上传,删除未使用的快照等
Maven 生命周期
生命周期有三种:clean、default、site
生命周期中phase、plugin、goal的关系
完整的maven生命周期及默认配置:https://www.processon.com/view/link/6113f632e401fd5eeb87e600
生命周期有三种、每个生命周期都对应了固定的phase,有相应的执行顺序,plugin是对应到phase上的,goal是plugin上的一个个功能点,配置的时候会将某个plugin上的goal指定到对应的phase上,phase和plugin和goal都是多对多的关系。
plugin结合生命周期的配置方式
pom.xml
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.1.RELEASE</version>
<!-- 指定goal -->
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<!--参数,插件定义的-->
<configuration>
<skipTests>true</skipTests>
</configuration>
</plugin>
</plugins>
</build>
使用plugin、goal的方式
mvn plugin:goal
示例:
mvn compiler:compile
单独执行plugin的goal 仅仅只会执行这一个goal,和生命周期无关
关于工程骨架 Archetype
自行百度
企业级使用案例
聚合功能实现多模块
自行百度
多模块依赖版本统一
父pom.xml
<properties>
<hutool.version>2.4.1.10</hutool.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<!--插件同理-->
<pluginManagement>
<plugins>
<plugin>
</plugin>
</plugins>
</pluginManagement>
子pom.xml
<dependencies>
<dependency>
<!--默认使用父pom中定义的版本号-->
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
</dependencies>
<plugins>
<plugin>
</plugin>
</plugins>
基于资源过滤+profile功能自动适配各个发布环境
pom.xml
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>application*.properties</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>application.properties</include>
<include>application-${spring.profiles.active}.properties</include>
</includes>
</resource>
</resources>
</build>
<profiles>
<profile>
<id>dev</id>
<properties>
<spring.profiles.active>dev</spring.profiles.active>
</properties>
</profile>
</profiles>