Maven从入门到好难

参考文献
永远最好的官网
超赞maven系列文章

1. 为啥要有maven

想当初,刚毕业刚工作,之前学的C++,java不懂,部门用的Spring,于是开始学习SSM,妈的,jar包好难整,还要一个个下载好放到libs目录中。
后来遇到好几次jar包冲突,还好有maven的idea插件,才让问题快速找到原因。
因此maven可以解决

  1. jar包的下载难
  2. jar包版本之间的依赖问题
  3. jar包版本冲突【maven并没有很好的解决,工作还是经常遇到jar包冲突的问题,这个时候你需要一个排查思路】
  4. 项目的目录结构不同
  5. 项目的生命周期控制方式五花八门

官方解释什么是maven:maven是apache软件基金会组织维护的一款自动化构建工具,专注服务于java平台的项目构建和依赖管理

2. maven的安装

3. maven的配置文件,重点之中【待完善】

这块其实水很深,不同的maven版本和配置都有可能导致最终打出来的包不一样。
曾经我们就遇到配置的不同导致打出来的包不同,最后导致线上问题,真的是。。。。。太难了。。。

4. maven约定的项目配置

Maven从入门到好难_第1张图片

4.1 通过idea查看项目依赖

Maven从入门到好难_第2张图片

4.2 idea maven helper插件

查包依赖,排包的好工具!!!

4.3 pom导入jar包格式

<dependencies>
        
        <dependency>
            <groupId>groupId>
            <artifactId>artifactId>
            <version>version>
            
            <type>type>
            
            <scope>scope>
            
            <optional>optional>
            
            <exclusions>
                <exclusion>exclusion>
                <exclusion>exclusion>
            exclusions>
        dependency>
    dependencies>

4.4 重点的scope

控制jar包是否打包到项目的classpath中。
Maven从入门到好难_第3张图片
还有一个import

有的时候我们会从在项目中加第三方的jar包,因为都是私有的项目,他们只给了一个jar包,maven仓库中没有,那这个时候怎么办呢?

4.5 用mvn deploy到自己的私有仓库中

mvn install:install-file -Dfile=D:\*.*-1.0.jar -DgroupId=*.* -DartifactId=*-* -Dversion=1.0 -Dpackaging=jar

Maven从入门到好难_第4张图片

4.6 使用system

似乎这里和上述文章说的不一致,那我们来搞个测试。

发现打完包之后的确没有这个jar包。需要注意的是:使用第二种方式导入的jar包,因为scope指定的是system类型,因此打包时并不会被打入到最终的jar中;如果需要和项目一起打包则需要使用springboot的打包插件。

<plugin>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-maven-pluginartifactId>
    <configuration>
    	
        <includeSystemScope>trueincludeSystemScope>
    configuration>
plugin>

4.7 maven解析pom中依赖调解的原则

  • 路径最近原则
    上面A->B->C->Y(1.0),A->D->Y(2.0),Y的2.0版本距离A更近一些,所以maven会选择2.0。

但是如果出现了路径是一样的,如:A->B->Y(1.0),A->D->Y(2.0),此时maven又如何选择呢?

  • 最先声明原则
    如果出现了路径一样的,此时会看A的pom.xml中所依赖的B、D在dependencies中的位置,谁的声明在最前面,就以谁的为主,比如A->B在前面,那么最后Y会选择1.0版本。

这两个原则就是解决jar包冲突的理论依据,必须理解!!!!:路径最近原则、最先声明原则

4.8 optional选项作用

官网介绍
排包还有一个思路

A->B中scope:compile
B->C中scope:compile

如果我们不想引入C
那么就可以在B项目中引入Cjar包的时候把optional设置为true。

5. maven仓库

一句话:maven引包只是一个引用,在最终打包后才会在包中。

5.1 仓库的分类

  • 本地仓库
    maven本地仓库默认地址是~/.m2/respository目录,这个默认我们也可以在~/.m2/settings.xml文件中进行修改:
<localRepository>本地仓库地址</localRepository>
  • 私有仓库
    自己公司的maven私有仓库,有可能工作的时候这个仓库就需要你维护或者搭建。
    maven的私有仓库现在也有两个不同的版本了: Nexus 2/3。文件存储的格式好像又比较大的改动。。。。

总体上来说私服有以下好处:

加速maven构件的下载速度
节省宽带
方便部署自己的构件以供他人使用
提高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

访问一下
Maven从入门到好难_第5张图片
中仓仓库查找jar包的网站:https://search.maven.org/

新的中仓仓库查找jar包的网站:https://central.sonatype.com/

  • 其他公共远程仓库
    比如像阿里、网易等等

5.2 重点!!快照版本和正式版本

version以-SNAPSHOT结尾的,表示这是一个不稳定的版本,这个版本我们最好只在公司内部测试的时候使用,最终发布的时候,我们需要将-SNAPSHOT去掉,然后发布一个稳定的版本,表示这个版本是稳定的,可以直接使用,这种稳定的版本我们叫做release版本。

  1. 开发的时候使用快照版本,这个时候每次打包都会去拉去最新的版本,如果你改动的快照包的代码,就需要deploy后让引用的也无妨重新打包部署一下。。。
  2. 正式版本只要有了就不会再去私有仓库中拉取了。注意:有的时候本地搞出来了一个错误的正式包,但是因为是正式包,本地有了就不会去仓库中拉,所以这个时候需要手动删除本地的错误的包

5.3 Maven中远程仓库的配置

5.3.1. 使用项目的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/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,表示是否需要从这个远程仓库中下载稳定版本或者快照版本

5.3.2. settings.xml配置

太难了,搞不懂。。。。。

私有仓库搭建

最常用的是Nexus

6. maven插件

6.1 介绍

6.2 生命周期和阶段

每个生命周期中的后面的阶段会依赖于前面的阶段,当执行某个阶段的时候,会先执行其前面的阶段。
Maven从入门到好难_第6张图片


Maven从入门到好难_第7张图片
Maven从入门到好难_第8张图片

6.3 mvn命令

如何执行mvn的命名

mvn 阶段1 [阶段2] [阶段n]

6.4 插件的目标和参数查看

  1. 列出插件所有目标 ,使用插件的help目标查看或者用help插件
mvn 插件goupId:插件artifactId[:插件version]:help
mvn 插件前缀:help

mvn help:describe -Dplugin=插件goupId:插件artifactId[:插件version]
mvn help:describe -Dplugin=插件前缀
  1. 查看插件目标参数列表,使用-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
  1. 命令行运行插件
mvn 插件goupId:插件artifactId[:插件version]:插件目标 [-D目标参数1] [-D目标参数2] [-D目标参数n]
mvn 插件前缀:插件目标  [-D目标参数1] [-D目标参数2] [-D目标参数n]
  1. 查看插件的前缀
mvn help:describe -Dplugin=插件goupId:插件artifactId[:插件version]

Maven从入门到好难_第9张图片

6.5 插件的目标和生命周期阶段绑定

<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

6.6 插件传参的方式

6.6.1. mvn命令-D属性名称的方式传递

mvn 插件goupId:插件artifactId[:插件version]:插件目标 [-D目标参数1] [-D目标参数2] [-D目标参数n]

6.6.2. pom.xml中properties中定义的方式指定。

<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>

6.6.3. pom的plugin里配置插件的参数

6.6.3.1 插件目标共享参数配置
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.pluginsgroupId>
            <artifactId>maven-surefire-pluginartifactId>
            <version>2.12.4version>
            
            <configuration>
                <skip>trueskip>
            configuration>
        plugin>
    plugins>
build>
6.6.3.2 插件目标参数配置
<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>

6.7.插件仓库配置

<pluginRepositories>
    <pluginRepository>
        <id>myplugin-repositoryid>
        <url>http://repo1.maven.org/maven2/url>
        <releases>
            <enabled>trueenabled>
        releases>
    pluginRepository>
pluginRepositories>

7 maven的聚合、继承、单继承问题

7.1 聚合也就是多模块

这里没啥好说的,实际看过就知道了,但是重点讲一下

<modules>
    <module>模块1module>
    <module>模块2module>
    <module>模块nmodule>
modules>
<package>pompackage>

注意上面的module元素,这部分是被聚合的模块pom.xml所在目录的相对路径。

package的值必须为pom。

7.2 多模块中子构件的pom.xml引入父构件的配置:

<parent>
   <groupId>父构件groupIdgroupId>
   <artifactId>父构件artifactIdartifactId>
   <version>父构件的版本号version>
   <relativePath>父构件pom.xml路径relativePath>
parent>

relativePath表示父构件pom.xml相对路径,默认是…/pom.xml,所以一般情况下父子结构的maven构件在目录结构上一般也采用父子关系。单有的时候是评级的,这个时候就需要relativePath正确的配置了。

mvn dependency:tree 这个插件可以根据pom.xml的配置,列出构件的依赖树信息。
也可以用来排包

7.3 依赖管理(dependencyManagement)

maven提供的dependencyManagement元素既能让子模块继承到父模块的依赖配置,又能保证子模块依赖使用的灵活性,在dependencyManagement元素下声明的依赖不会引入实际的依赖,他只是声明了这些依赖,不过它可以对dependencies中使用的依赖起到一些约束作用。

父项目写好dependencyManagement做好版本管理,子项目引用的时候不需要写版本。

7.4 单继承的问题和解决

如上,dependencyManagement可以让子项目配置更简单。
但是实际开发中我们自己的项目就是多模块的,此时又想引入其他项目的dependencyManagement怎么办呢?

7.4.1 回到scope中没有说的import

可以在我们的项目中使用加入下面配置:

<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>

import就可以做到这个效果,相当于把导入的配置像C语言的宏定义一样使用。

7.5 插件管理(pluginManagement)

和依赖管理(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,一般都是没有什么内容的。
实际使用是,我们经常将聚合和继承一起使用,能同时使用到两者的优点。

8. 大神写的太好一定要看-mvn命令1

9. 大神写的太好一定要看-maven命令2

10. 排包

生个版本,嘿,项目启动报错。或者是启动不报错,运行报错。。。。如:

没有这个类 NoSuch
没有这个方法 NoSuch

如何处理呢:

  1. 通过报错信息查找到类->包,注意有的时候可能是类的静态初始化抛异常了
  2. 通过maven helper插件找到冲突的包
  3. 排包:A: 使用exclusions;B: 使用maven的依赖解析原则,直接在项目的pom文件中配置好版本,这样让maven首先就找到正确的版本。

你可能感兴趣的:(杂记,maven,java)