参考文献
永远最好的官网
超赞maven系列文章
想当初,刚毕业刚工作,之前学的C++,java不懂,部门用的Spring,于是开始学习SSM,妈的,jar包好难整,还要一个个下载好放到libs目录中。
后来遇到好几次jar包冲突,还好有maven的idea插件,才让问题快速找到原因。
因此maven可以解决
官方解释什么是maven:maven是apache软件基金会组织维护的一款自动化构建工具,专注服务于java平台的项目构建和依赖管理。
这块其实水很深,不同的maven版本和配置都有可能导致最终打出来的包不一样。
曾经我们就遇到配置的不同导致打出来的包不同,最后导致线上问题,真的是。。。。。太难了。。。
查包依赖,排包的好工具!!!
<dependencies>
<dependency>
<groupId>groupId>
<artifactId>artifactId>
<version>version>
<type>type>
<scope>scope>
<optional>optional>
<exclusions>
<exclusion>exclusion>
<exclusion>exclusion>
exclusions>
dependency>
dependencies>
控制jar包是否打包到项目的classpath中。
还有一个import
有的时候我们会从在项目中加第三方的jar包,因为都是私有的项目,他们只给了一个jar包,maven仓库中没有,那这个时候怎么办呢?
mvn install:install-file -Dfile=D:\*.*-1.0.jar -DgroupId=*.* -DartifactId=*-* -Dversion=1.0 -Dpackaging=jar
似乎这里和上述文章说的不一致,那我们来搞个测试。
发现打完包之后的确没有这个jar包。需要注意的是:使用第二种方式导入的jar包,因为scope指定的是system类型,因此打包时并不会被打入到最终的jar中;如果需要和项目一起打包则需要使用springboot的打包插件。
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<includeSystemScope>trueincludeSystemScope>
configuration>
plugin>
但是如果出现了路径是一样的,如:A->B->Y(1.0),A->D->Y(2.0),此时maven又如何选择呢?
这两个原则就是解决jar包冲突的理论依据,必须理解!!!!:路径最近原则、最先声明原则。
官网介绍
排包还有一个思路
A->B中scope:compile
B->C中scope:compile
如果我们不想引入C
那么就可以在B项目中引入Cjar包的时候把optional设置为true。
一句话:maven引包只是一个引用,在最终打包后才会在包中。
~/.m2/respository
目录,这个默认我们也可以在~/.m2/settings.xml
文件中进行修改:<localRepository>本地仓库地址</localRepository>
总体上来说私服有以下好处:
加速maven构件的下载速度
节省宽带
方便部署自己的构件以供他人使用
提高maven的稳定性,中央仓库需要本机能够访问外网,而如果采用私服的方式,只需要本机可以访问内网私服就可以了
apache-maven-3.6.1\lib\maven-model-builder-3.6.1.jar\org\apache\maven\model\pom-4.0.0.xml
仓库地址:
https://repo.maven.apache.org/maven2
访问一下
中仓仓库查找jar包的网站:https://search.maven.org/
新的中仓仓库查找jar包的网站:https://central.sonatype.com/
version以-SNAPSHOT结尾的,表示这是一个不稳定的版本,这个版本我们最好只在公司内部测试的时候使用,最终发布的时候,我们需要将-SNAPSHOT去掉,然后发布一个稳定的版本,表示这个版本是稳定的,可以直接使用,这种稳定的版本我们叫做release版本。
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.javacode2018groupId>
<artifactId>maven-chat03artifactId>
<version>1.0-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.62version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>2.2.1.RELEASEversion>
dependency>
dependencies>
<repositories>
<repository>
<id>aliyun-releasesid>
<url>https://maven.aliyun.com/repository/publicurl>
<releases>
<enabled>trueenabled>
releases>
<snapshots>
<enabled>falseenabled>
snapshots>
repository>
repositories>
project>
repository元素说明:
id:远程仓库的一个标识,中央仓库的id是central,所以添加远程仓库的时候,id不要和中央仓库的id重复,会把中央仓库的覆盖掉
url:远程仓库地址
releases:主要用来配置是否需要从这个远程仓库下载稳定版本构建
snapshots:主要用来配置是否需要从这个远程仓库下载快照版本构建
enabled属性,是个boolean值,默认为true,表示是否需要从这个远程仓库中下载稳定版本或者快照版本
太难了,搞不懂。。。。。
最常用的是Nexus
每个生命周期中的后面的阶段会依赖于前面的阶段,当执行某个阶段的时候,会先执行其前面的阶段。
如何执行mvn的命名
mvn 阶段1 [阶段2] [阶段n]
mvn 插件goupId:插件artifactId[:插件version]:help
mvn 插件前缀:help
mvn help:describe -Dplugin=插件goupId:插件artifactId[:插件version]
mvn help:describe -Dplugin=插件前缀
-Dgoal=目标名称 -Ddetail
参数查看目标参数或者用help插件mvn 插件goupId:插件artifactId[:插件version]:help -Dgoal=目标名称 -Ddetail
mvn 插件前缀:help -Dgoal=目标名称 -Ddetail
mvn help:describe -Dplugin=插件goupId:插件artifactId[:插件version] -Dgoal=目标名称 -Ddetail
mvn help:describe -Dplugin=插件前缀 -Dgoal=目标名称 -Ddetail
mvn 插件goupId:插件artifactId[:插件version]:插件目标 [-D目标参数1] [-D目标参数2] [-D目标参数n]
mvn 插件前缀:插件目标 [-D目标参数1] [-D目标参数2] [-D目标参数n]
mvn help:describe -Dplugin=插件goupId:插件artifactId[:插件version]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-source-pluginartifactId>
<version>3.2.0version>
<executions>
<execution>
<id>attach-sourceid>
<goals>
<goal>jar-no-forkgoal>
goals>
<phase>verifyphase>
execution>
executions>
plugin>
plugins>
build>
mvn help:describe -Dplugin=插件goupId:插件artifactId[:插件version] -Dgoal=目标名称 -Ddetail
mvn help:describe -Dplugin=插件前缀 -Dgoal=目标名称 -Ddetail
~/work/ mvn help:describe -Dplugin=source -Dgoal=jar-no-fork -Ddetail
[INFO] Mojo: 'source:jar-no-fork'
source:jar-no-fork
Description: This goal bundles all the sources into a jar archive. This
goal functions the same as the jar goal but does not fork the build and is
suitable for attaching to the build lifecycle.
Implementation: org.apache.maven.plugins.source.SourceJarNoForkMojo
Language: java
Bound to phase: package
Available parameters:
Bound to phase: package
mvn 插件goupId:插件artifactId[:插件version]:插件目标 [-D目标参数1] [-D目标参数2] [-D目标参数n]
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<java.version>1.8java.version>
<maven.test.skip>truemaven.test.skip>
properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-surefire-pluginartifactId>
<version>2.12.4version>
<configuration>
<skip>trueskip>
configuration>
plugin>
plugins>
build>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-surefire-pluginartifactId>
<version>2.12.4version>
<executions>
<execution>
<goals>
<goal>testgoal>
<goal>helpgoal>
goals>
<phase>pre-cleanphase>
<configuration>
<skip>trueskip>
configuration>
execution>
executions>
plugin>
plugins>
build>
<pluginRepositories>
<pluginRepository>
<id>myplugin-repositoryid>
<url>http://repo1.maven.org/maven2/url>
<releases>
<enabled>trueenabled>
releases>
pluginRepository>
pluginRepositories>
这里没啥好说的,实际看过就知道了,但是重点讲一下
<modules>
<module>模块1module>
<module>模块2module>
<module>模块nmodule>
modules>
<package>pompackage>
注意上面的module元素,这部分是被聚合的模块pom.xml所在目录的相对路径。
package的值必须为pom。
<parent>
<groupId>父构件groupIdgroupId>
<artifactId>父构件artifactIdartifactId>
<version>父构件的版本号version>
<relativePath>父构件pom.xml路径relativePath>
parent>
relativePath表示父构件pom.xml相对路径,默认是…/pom.xml,所以一般情况下父子结构的maven构件在目录结构上一般也采用父子关系。单有的时候是评级的,这个时候就需要relativePath正确的配置了。
mvn dependency:tree 这个插件可以根据pom.xml的配置,列出构件的依赖树信息。
也可以用来排包
maven提供的dependencyManagement元素既能让子模块继承到父模块的依赖配置,又能保证子模块依赖使用的灵活性,在dependencyManagement元素下声明的依赖不会引入实际的依赖,他只是声明了这些依赖,不过它可以对dependencies中使用的依赖起到一些约束作用。
父项目写好dependencyManagement做好版本管理,子项目引用的时候不需要写版本。
如上,dependencyManagement可以让子项目配置更简单。
但是实际开发中我们自己的项目就是多模块的,此时又想引入其他项目的dependencyManagement怎么办呢?
可以在我们的项目中使用加入下面配置:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.javacode2018groupId>
<artifactId>javacode2018-parentartifactId>
<version>1.0-SNAPSHOTversion>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>构件2dependency>
<dependency>构件3dependency>
<dependency>构件ndependency>
dependencies>
dependencyManagement>
就可以做到这个效果,相当于把导入的配置像C语言的宏定义一样使用。
和依赖管理(dependencyManagement)管理一样,父项目配置好插件,子项目也可以不配置版本了。
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-source-pluginartifactId>
<version>3.2.0version>
<executions>
<execution>
<id>attach-sourceid>
<phase>verifyphase>
<goals>
<goal>jar-no-forkgoal>
goals>
execution>
executions>
plugin>
plugins>
pluginManagement>
build>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-source-pluginartifactId>
plugin>
plugins>
build>
聚合主要是为了方便多模块快速构建。
而继承主要是为了重用相同的配置。
对于聚合来说,聚合模块是知道被聚合模块的存在的,而被聚合模块是感知不到聚合模块的存在。
对于继承来说,父构件是感知不到子构件的存在,而子构件需要使用parent来引用父构件。
两者的共同点是,聚合模块和继承中的父模块的package属性都必须是pom类型的,同时,聚合模块和父模块中的除了pom.xml,一般都是没有什么内容的。
实际使用是,我们经常将聚合和继承一起使用,能同时使用到两者的优点。
生个版本,嘿,项目启动报错。或者是启动不报错,运行报错。。。。如:
没有这个类 NoSuch
没有这个方法 NoSuch
如何处理呢:
类->包
,注意有的时候可能是类的静态初始化抛异常了