开发工具篇第三讲:你连maven都不懂面试官怎么敢要你

在Java开发中,常用构建工具ant、maven和gradle, 其中maven相对主流。本文是开发工具篇第三讲:Maven 从入门到实战

文章目录

1、什么是Maven?

Maven是一款服务于Java平台的自动化构建工具。

  • 构建:以”Java源文件“、”框架配置文件“、”JSP“、”HTML“、”图片“等资源为”原材料“,去“生产”一个可以运行的项目的过程。
  • 演化过程:Make-> Ant ->Maven ->Gradle
  • 编译:java源文件->编译->Class字节码文件->交给JVM去执行
  • 部署:一个项目最终运行的并不是动态Web工程本身,而是这个动态Web工程“编译的结果”
  • 搭建:
    在这里插入图片描述

maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件。它包含了一个项目对象模型,一组标准集合,一个项目生命周期,一个依赖管理系统和用来运行定义在生命周期阶段中插件目标的逻辑。当使用Maven的时候,你用一个明确定义的项目对象模型来描述你的项目,然后Maven可以应用横切的逻辑,这些逻辑来自于一组共享的(或自定义的)插件。

1.1、Maven的目录结构

目录的划分是根据需要来的,每个目录有其特定的功能。目录本质上就是一个文件或文件夹路径而已

img

1.2、如何修改默认的目录配置

在maven项目工程对应project的 pom.xml中,在<project>--><build>节点下,你可以指定自己的目录路径信息:

<build>
    <!-- 目录信息维护,用户可以指定自己的目录路径 -->
    <sourceDirectory>E:\intellis\maven-principle\phase-echo\src\main\java</sourceDirectory>
    <scriptSourceDirectory>E:\intellis\maven-principle\phase-echo\src\main\scripts</scriptSourceDirectory>
    <testSourceDirectory>E:\intellis\maven-principle\phase-echo\src\test\java</testSourceDirectory>
    <outputDirectory>E:\intellis\maven-principle\phase-echo\target\classes</outputDirectory>
    <testOutputDirectory>E:\intellis\maven-principle\phase-echo\target\test-classes</testOutputDirectory>
  
    <!-- 注意,对resource而言,可以有很多个resource路径的配置,你只需要指定对应的路径是resource即可 -->
    <resources>
      <resource>
        <directory>E:\intellis\maven-principle\phase-echo\src\main\resources</directory>
      </resource>
    </resources>
  
    <!-- 注意,对resource而言,可以有很多个resource路径的配置,你只需要指定对应的路径是resource即可 -->
    <testResources>
      <testResource>
        <directory>E:\intellis\maven-principle\phase-echo\src\test\resources</directory>
      </testResource>
    </testResources>
  
    <directory>E:\intellis\maven-principle\phase-echo\target</directory>
</build>

2、Maven能为我们解决什么问题?

目前的技术在开发中存在的问题?
在这里插入图片描述

  • 1、一个项目就是一个工程
    • 如果项目非常庞大,就不适合继续使用package来划分模块。最好是一个模块对应一个工程,利于分工协作。
    • 借助Maven可以将一个项目拆分为多个工程。
  • 2、项目中需要的jar包需要手动复制、粘贴到WEB_INF/lib目录下
    • 带来的问题是:同样的jar包文件重复出现在不同的项目工程中,浪费存储空间;
    • 借助maven,可以将jar包仅仅保存在仓库中,有需要使用的工程”引用“这个文件接口,并不需要真的把jar包复制过来
  • 3、jar包需要别人替我们准备好,或到官网下载
    • Maven可以以一种规范的方式下载jar包
  • 4、一个jar包依赖的其他jar包需要自己手动加入到项目中
    • Maven会自动将依赖的jar包导入进来。

3、说说Maven有什么优缺点?

优点

  • 简化了项目依赖管理;
  • 易于上手,对于新手来说了解几个常用命令即可满足日常工作;
  • 便于与持续集成工具(jenkins)整合;
  • 便于项目升级,无论是项目本身还是项目使用的依赖;
  • maven有很多插件,便于功能扩展,比如生产站点,自动发布版本等。

缺点

  • Maven是一个庞大的构建系统,学习难度大。(很多都可以这样说,入门容易[优点]但是精通难[缺点]);
  • Maven采用约定约定优于配置的策略,虽然上手容易但是一旦出现问题,难于调试;
  • 网络环境较差,很多repository无法访问。

4、什么是Maven的坐标?

4.1、定义 GAV 遵从以下规则
  • 1) GroupId 格式: com.{公司/BU}.业务线.[子业务线], 最多 4 级。
    • 说明: {公司/BU}例如: alibaba / taobao / tmall / kaikeba 等 BU 一级; 子业务线可选。
    • 正例: com.taobao.jstormcom.alibaba.dubbo.register
  • 2) ArtifactId 格式:产品线名-模块名。语义不重复不遗漏, 先到中央仓库去查证一下。
    • 正例: dubbo-client / fastjson-api / jstorm-tool
  • 3) Version: 详细规定参考下方。
4.2、二方库版本号命名方式:主版本号.次版本号.修订号
  • 1)主版本号:产品方向改变,或者大规模 API 不兼容,或者架构不兼容升级。
  • 2)次版本号:保持相对兼容性,增加主要功能特性,影响范围极小的 API 不兼容修改。
  • 3)修订号:保持完全兼容性,修复 BUG、新增次要功能特性等。

说明:注意起始版本号必须为:1.0.0,而不是 0.0.1。

反例:仓库内某二方库版本号从 1.0.0.0 开始,一直默默“升级” 成 1.0.0.64,完全失去版本的语义信息。

Maven其中一个核心的作用就是管理项目的依赖,引入我们所需的各种jar包等。为了能自动化的解析任何一个Java构件,Maven必须将这些Jar包或者其他资源进行唯一标识,这是管理项目的依赖的基础,也就是我们要说的坐标。包括我们自己开发的项目,也是要通过坐标进行唯一标识的,这样才能才其它项目中进行依赖引用。

maven的坐标通过groupId,artifactId,version唯一标志一个构件。groupId通常为公司或组织名字,artifactId通常为项目名称,versionId为版本号。

4.3、线上应用不要依赖 SNAPSHOT 版本(安全包除外) ;正式发布的类库必须先去中央仓库进行查证,使 RELEASE 版本号有延续性,且版本号不允许覆盖升级。

说明:不依赖 SNAPSHOT 版本是保证应用发布的幂等性。另外,也可以加快编译时的打包构建

5、讲一下Maven的生命周期?

maven从项目的三个不同的角度,定义了三套生命周期,三套生命周期是相互独立的,它们之间不会相互影响。

  • 默认构建生命周期 (Default Lifeclyle):该生命周期表示这项目的构建过程,定义了一个项目的构建要经过的不同的阶段。
  • 清理生命周期 (Clean Lifecycle):该生命周期负责清理项目中的多余信息,保持项目资源和代码的整洁性。一般拿来清空directory(即一般的target) 目录下的文件。
  • 站点管理生命周期 (Site Lifecycle):向我们创建一个项目时,我们有时候需要提供一个站点,来介绍这个项目的信息,如项目介绍,项目进度状态、项目组成成员,版本控制信息,项目javadoc索引信息等等。站点管理生命周期定义了站点管理过程的各个阶段。

img

5.1、Maven的默认构建生命周期:从我们的项目构建,一直到项目发布的这个过程

在这里插入图片描述
在这里插入图片描述

5.2、maven对项目默认生命周期的抽象

Maven将其架构和结构的组织放置到了components.xml 配置文件中,该配置文件的路径是: apache-maven-version\lib\maven−core−{version}\lib\maven-core-version\lib\maven−core−{version}.jar\META-INFO\plexus\conponents.xml文件中。其中,我们可以看到关于default生命周期XML节点配置信息:

<component>  
    <role>org.apache.maven.lifecycle.Lifecycle</role>  
    <implementation>org.apache.maven.lifecycle.Lifecycle</implementation>  
    <role-hint>default</role-hint>  
    <configuration>  
        <id>default</id>  
        <phases>  
            <phase>validate</phase>  
            <phase>initialize</phase>  
            <phase>generate-sources</phase>  
            <phase>process-sources</phase>  
            <phase>generate-resources</phase>  
            <phase>process-resources</phase>  
            <phase>compile</phase>  
            <phase>process-classes</phase>  
            <phase>generate-test-sources</phase>  
            <phase>process-test-sources</phase>  
            <phase>generate-test-resources</phase>  
            <phase>process-test-resources</phase>  
            <phase>test-compile</phase>  
            <phase>process-test-classes</phase>  
            <phase>test</phase>  
            <phase>prepare-package</phase>  
            <phase>package</phase>  
            <phase>pre-integration-test</phase>  
            <phase>integration-test</phase>  
            <phase>post-integration-test</phase>  
            <phase>verify</phase>  
            <phase>install</phase>  
            <phase>deploy</phase>  
        </phases>  
    </configuration>  
</component> 

Maven根据一个项目的生命周期的每个阶段,将一个项目的生命周期抽象成了如上图所示的23个阶段。而每一个阶段应该干什么事情由用户决定。换句话说,maven为每一个阶段设计了接口,你可以为每一阶段自己定义一个接口,进而实现对应阶段应该有的行为

img

在经历这些生命周期的阶段中,每个阶段会理论上会有相应的处理操作。但是,在实际的项目开发过程中, 并不是所有的生命周期阶段都是必须的。 基于类似的约定,maven默认地为一些不同类型的maven项目生命周期的阶段实现了默认的行为。

Maven 在设计上将生命周期阶段的抽象和对应阶段应该执行的行为实现分离开,maven这些实现放到了插件中,这些插件本质上是实现了maven留在各个生命周期阶段的接口。如下图所示,maven针对不同打包类型的maven项目的生命周期阶段绑定了对应的默认行为:

img

5.3、Maven各生命阶段行为绑定

maven会根据Mojo功能的划分,将具有相似功能的Mojo放到一个插件中。并且某一个特定的Mojo能实现的功能称为 goal,即目标,表明该Mojo能实现什么目标。

img

例如,我们项目生命周期有两个阶段: compile 和 test-compile,这两阶段都是需要将Java源代码编译成class文件中,相对应地,compile和test-compiler分别被绑定到了org.apache.maven.plugin.compiler.CompilerMojo 和org.apache.maven.plugin.compiler.TestCompilerMojo上:

img

5.4、如何查看Maven各个生命周期阶段和插件的绑定情况

maven默认实现上,会为各个常用的生命周期根据约定绑定特定的插件目标。maven将这些配置放置到了: apache-maven-version\lib\maven−core−{version}\lib\maven-core-version\lib\maven−core−{version}.jar\META-INFO\plexus\default-binds.xml文件中,针对不同打包类型的项目,其默认绑定情况也会不一样,我们先看一下常用的jar包类型和war包类型的项目默认绑定情况:

    <!-- jar包格式的项目生命周期各个阶段默认绑定情况 -->  
    <component>  
        <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>  
        <role-hint>jar</role-hint>  
        <implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>  
        <configuration>  
            <lifecycles>  
                <lifecycle>  
                    <id>default</id>  
                    <!-- START SNIPPET: jar-lifecycle -->  
                    <phases>  
                        <!-- 插件绑定的格式:   <plugin-groupid>:<plugin-artifactid>:<version>:goal  -->   
                        <process-resources>  
                    org.apache.maven.plugins:maven-resources-plugin:2.6:resources  
                        </process-resources>  
                        <compile>  
                    org.apache.maven.plugins:maven-compiler-plugin:3.1:compile  
                        </compile>  
                        <process-test-resources>  
                    org.apache.maven.plugins:maven-resources-plugin:2.6:testResources  
                        </process-test-resources>  
                        <test-compile>  
                    org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile  
                        </test-compile>  
                        <test>  
                    org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test  
                        </test>  
                        <package>  
                    org.apache.maven.plugins:maven-jar-plugin:2.4:jar  
                        </package>  
                        <install>  
                    org.apache.maven.plugins:maven-install-plugin:2.4:install  
                        </install>  
                        <deploy>  
                    org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy  
                        </deploy>  
                    </phases>  
                    <!-- END SNIPPET: jar-lifecycle -->  
                </lifecycle>  
            </lifecycles>  
        </configuration>  
    </component>  
      
    <!-- war包格式的项目生命周期各个阶段默认绑定情况 -->  
    <component>  
        <role>org.apache.maven.lifecycle.mapping.LifecycleMapping</role>  
        <role-hint>war</role-hint>  
        <implementation>org.apache.maven.lifecycle.mapping.DefaultLifecycleMapping</implementation>  
        <configuration>  
            <lifecycles>  
                <lifecycle>  
                    <id>default</id>  
                    <!-- START SNIPPET: war-lifecycle -->  
                    <phases>  
                        <process-resources>  
                    org.apache.maven.plugins:maven-resources-plugin:2.6:resources  
                        </process-resources>  
                        <compile>  
                    org.apache.maven.plugins:maven-compiler-plugin:3.1:compile  
                        </compile>  
                        <process-test-resources>  
                    org.apache.maven.plugins:maven-resources-plugin:2.6:testResources  
                        </process-test-resources>  
                        <test-compile>  
                    org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile  
                        </test-compile>  
                        <test>  
                    org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test  
                        </test>  
                        <package>  
                    org.apache.maven.plugins:maven-war-plugin:2.2:war  
                        </package>  
                        <install>  
                    org.apache.maven.plugins:maven-install-plugin:2.4:install  
                        </install>  
                        <deploy>  
                    org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy  
                        </deploy>  
                    </phases>  
                    <!-- END SNIPPET: war-lifecycle -->  
                </lifecycle>  
            </lifecycles>  
        </configuration>  
    </component>  

6、说说你熟悉哪些Maven命令?

mvn archetype:generate 创建Maven项目
mvn compile 编译源代码
mvn deploy 发布项目
mvn test-compile 编译测试源代码
mvn test 运行应用程序中的单元测试
mvn site 生成项目相关信息的网站
mvn clean 清除项目目录中的生成结果
mvn package 根据项目生成的jar
mvn install 在本地Repository中安装jar
mvn eclipse:eclipse 生成eclipse项目文件
mvnjetty:run 启动jetty服务
mvntomcat:run 启动tomcat服务
mvn clean package -Dmaven.test.skip=true:清除以前的包后重新打包,跳过测试类

7、使用二方库的注意事项?

1、二方库的新增或升级,保持除功能点之外的其它 jar 包仲裁结果不变。如果有改变,必须明确评估和验证。

  • 说明:在升级时,进行 dependency:resolve 前后信息比对,如果仲裁结果完全不一致,那么通过 dependency:tree 命令,找出差异点,进行<exclude> 排除 jar 包。

2、二方库里可以定义枚举类型, 参数可以使用枚举类型, 但是接口返回值不允许使用枚举类型或者包含枚举类型的 POJO 对象。

3、二方库定制包的命名方式,在规定的版本号之后加“-英文说明[序号]” ,英文说明可以是部门简称、 业务名称,序号直接紧跟在英文说明之后,表示此定制包的顺序号。

  • 说明:fastjson 给 SCM 定制的版本号: 1.0.0-SCM1。注:请尽可能在应用端来解决类冲突和加载问题,避免随意发布此类定制包。

4、依赖于一个二方库群时,必须定义一个统一的版本变量,避免版本号不一致。

  • 说明:依赖 springframework-core, -context, -beans,它们都是同一个版本,可以定义一个变量来保存版本:${spring.version},定义依赖的时候,引用该版本。

5、二方库不要有配置项, 最低限度不要再增加配置项。

6、不要使用不稳定的工具包或者 Utils 类。

  • 说明: 不稳定指的是提供方无法做到向下兼容,在编译阶段正常,但在运行时产生异常,因此,尽量使用业界稳定的二方工具包

7、为避免应用二方库的依赖冲突问题,二方库发布者应当遵循以下原则:

  • 1)精简可控原则移除一切不必要的 API 和依赖,只包含 Service API、必要的领域模型对象、Utils 类、常量、枚举
    。如果依赖其它二方库,尽量是 provided 引入,让二方库使用者去依赖具体版本号;无 log 具体实现,只依赖日志框架。

  • 2)稳定可追溯原则:每个版本的变化应该被记录,二方库由谁维护,源码在哪里,都需要能方便查到。除非用户主动升级版本,否则公共二方库的行为不应该发生变化。

8、说说Maven的依赖原则?

8.1、依赖路径最短优先原则
  • 依赖传递的路径越短越优先

  • A -> B -> C -> X(1.0)
    A -> D -> X(2.0)
    
  • 由于 X(2.0) 路径最短,所以使用 X(2.0)。

8.2、pom文件声明顺序优先原则
  • 路径长度一样,则先声明的优先

  • A -> B -> X(1.0)
    A -> C -> X(2.0)
    
  • 在 POM 中最先声明的优先,上面的两个依赖如果先声明 B,那么最后使用 X(1.0)。

8.3、覆写优先原则
  • 子 POM 内声明的依赖优先于父 POM 中声明的依赖。

  • 即当前pom文件里声明的直接覆盖父工程传过来的

问题1:如何解决依赖传递引起的版本冲突?

  • 问题:A项目因为item-standard-api jar包deploy的姿势不正确,只deploy成功了一部分,导致B项目在部署时,由于item-standard-api依赖item-microservice-api,又传递依赖item-microservice-common,导致了此报错

  • 报错:如下图所示
    在这里插入图片描述

  • 解决方案:找到 Maven 加载的 Jar 包版本,使用 mvn dependency:tree 查看依赖树,根据依赖原则来调整依赖在 POM 文件的声明顺序。首先重新升级item-standard项目jar包,然后im项目和ip项目依赖is最新的jar包,即可。

  • 第二种解决方案:可通过dependency的exclusion元素排除掉依赖

    • 不推荐,可能已经存在对这个被剔除jar包的依赖

9、说说Maven依赖的解析机制?

当依赖的范围是 system 的时候,Maven 直接从本地文件系统中解析构件。

  • 根据依赖坐标计算仓库路径,尝试直接从本地仓库寻找构件,如果发现对应的构件,就解析成功。如果在本地仓库不存在相应的构件,就遍历所有的远程仓库,发现后,下载并解析使用。如果依赖的版本是 RELEASE 或 LATEST,就基于更新策略读取所有远程仓库的元数据文件(groupId/artifactId/maven-metadata.xml),将其与本地仓库的对应元合并后,计算出RELEASE 或者 LATEST 真实的值,然后基于该值检查本地仓库,或者从远程仓库下载如果依赖的版本是 SNAPSHOT,就基于更新策略读取所有远程仓库的元数据文件,将它与本地仓库对应的元数据合并,得到最新快照版本的值,然后根据该值检查本地仓库,或从远程仓库下载
  • 如果最后解析得到的构件版本包含有时间戳,先将该文件下载下来,再将文件名中时间戳信息删除,剩下 SNAPSHOT 并使用(以非时间戳的形式使用)。

10、如何部署第三方JAR包?

背景:在项目中我们经常需要使用第三方的Jar,比如某些SDK,这些SDK没有直接发布到公开的maven仓库中,这种情况下如何使用这些三方JAR呢?

解决方法:如果有Maven私服,将第三方Jar包安装到我们的Maven仓库

先配置Maven私服, server & profile信息

<!-- server -->
<server>
  	<id>maven-public</id>
  	<username>xxx</username>
  	<password>xxx</password>
    </server>
<!-- profile -->
<profile>
    <id>nexus</id>
    <repositories>
        <repository>
						<id>maven-public</id>
            <url>xxx.xxx.xxx.xxx</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
    </repositories>
</profile>

然后使用如下命令,部署到Maven仓库

# -X:详细信息输出用于调试
# -Dfile:本地jar路径
# gav: group, artifactId, verson
# -Durl:仓库地址
# -DrepositoryId:settings文件中的ID 
mvn -X deploy:deploy-file -DgroupId="com.huxun" -DartifactId="yop-java-sdk-biz" -Dversion="1.0.0" -Dpackaging="jar" -Dfile="/Users/xxx/Downloads/yop-java-sdk-biz/4.1.13/yop-java-sdk-biz-4.1.13.jar" -DrepositoryId="maven-public" -Durl="http://nexus.xxx.com/repository/maven-releases/" --settings  /Users/xxx/.m2/settings.xml

如果没有Maven私服,放在项目代码中,比如项目中libs文件夹中

使用systemPath属性,<scope>system</scope>, 其它gav三元组是可以随意填写的。

<dependency>
    <groupId>com.aliyun</groupId>
    <artifactId>taobao-sdk-java</artifactId>
    <version>1.0.0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/libs/taobao-sdk-java-auto_1479188381469-20180831.jar</systemPath>
</dependency>
  • SpringBoot JAR打包

springboot在打包的时候,调用spring-boot-maven-plugin,执行repackage把tomcat和resource,lib等合成一个新的jar。想要将系统jar打进去,必须配置includeSystemScope。最终会将lib放入BOOT-INF\lib

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <includeSystemScope>true</includeSystemScope>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>build-info</goal>
                        <goal>repackage</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
  • SpringBoot War打包

使用mvn clean package命令打包时需要在pom文件加入以下webResources配置,并设置jar包在WEB-INF/lib目录下

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.4</version>
    <configuration>
        <webResources>
            <resource>
                <directory>src/main/resources/libs/</directory>
                <targetPath>WEB-INF/lib/</targetPath>
                <includes>
                    <include>**/*.jar</include>
                </includes>
            </resource>
        </webResources>
    </configuration>
</plugin>

11、说说Maven插件的解析机制

与依赖的构件(artifactId)一样,插件(plugin)也是基于坐标保存在Maven仓库中。在用到插件的时候会先从本地仓库查找插件,如果本地仓库没有则从远程仓库查找插件并下载到本地仓库。与普通的依赖构件不同的是,Maven会区别对待普通依赖的远程仓库与插件的远程仓库。前面提到的配置远程仓库只会对普通的依赖有效果。当Maven需要的插件在本地仓库不存在时是不会去我们以前配置的远程仓库查找插件的,而是需要有专门的插件远程仓库

11.1、如何自定义maven插件?

todo

参考这篇文章:MAVEN专题之十、设计你自己的maven插件

11.2、项目中Run Package命令

加入Jacoo测试统计的插件, 分为pre-test 和 post-test两个阶段:

<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
      <!--检查代码覆盖率的插件配置-->
			<plugin>
				<groupId>org.jacoco</groupId>
				<artifactId>jacoco-maven-plugin</artifactId>
				<version>${jacoco.version}</version>
        <configuration>
          <!--指定生成.exec文件的存放位置-->
          <destFile>target/coverage-reports/jacoco-unit.exec</destFile>
          <!--Jacoco是根据.exec文件生成最终的报告,所以需指定.exec的存放路径-->
          <dataFile>target/coverage-reports/jacoco-unit.exec</dataFile>
          <excludes>
            <exclude>**/config/*</exclude>
          </excludes>
          <!-- rules里面指定覆盖规则 -->
          <rules>
            <rule implementation="org.jacoco.maven.RuleConfiguration">
              <element>BUNDLE</element>
              <limits>  
                <!-- 指定方法覆盖到50% -->
                <limit implementation="org.jacoco.report.check.Limit">
                  <counter>METHOD</counter>
                  <value>COVEREDRATIO</value>
                  <minimum>0.50</minimum>
                </limit>
                <!-- 指定分支覆盖到50% -->
                <limit implementation="org.jacoco.report.check.Limit">
                  <counter>BRANCH</counter>
                  <value>COVEREDRATIO</value>
                  <minimum>0.50</minimum>
                </limit>
                <!-- 指定类覆盖到100%,不能遗失任何类 -->
                <limit implementation="org.jacoco.report.check.Limit">
                  <counter>CLASS</counter>
                  <value>MISSEDCOUNT</value>
                  <maximum>0</maximum>
                </limit>
              </limits>
            </rule>
          </rules>
        </configuration>
				<executions>
					<execution>
						<id>pre-test</id>
						<goals>
							<goal>prepare-agent</goal>
						</goals>
					</execution>
					<execution>
						<id>post-test</id>
						<phase>test</phase>
						<goals>
							<goal>report</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
		<defaultGoal>compile</defaultGoal>
	</build>
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building cdc-common-config 1.0.1-RELEASE
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- jacoco-maven-plugin:0.7.7.201606060606:prepare-agent (pre-test) @ cdc-common-config ---
[INFO] argLine set to -javaagent:C:\\Users\\xxx\\.m2\\repository\\org\\jacoco\\org.jacoco.agent\\0.7.7.201606060606\\org.jacoco.agent-0.7.7.201606060606-runtime.jar=destfile=D:\\git_cdc2\\cdc-backend-services\\cdc-common-config\\target\\jacoco.exec
[INFO] 
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ cdc-common-config ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 1 resource
[INFO] Copying 5 resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.5.1:compile (default-compile) @ cdc-common-config ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ cdc-common-config ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] skip non existing resourceDirectory D:\git_cdc2\cdc-backend-services\cdc-common-config\src\test\resources
[INFO] 
[INFO] --- maven-compiler-plugin:3.5.1:testCompile (default-testCompile) @ cdc-common-config ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-surefire-plugin:2.19.1:test (default-test) @ cdc-common-config ---
...
Results :

Tests run: 1, Failures: 0, Errors: 0, Skipped: 0

[INFO] 
[INFO] --- jacoco-maven-plugin:0.7.7.201606060606:report (post-test) @ cdc-common-config ---
[INFO] Loading execution data file D:\git_cdc2\cdc-backend-services\cdc-common-config\target\jacoco.exec
[INFO] Analyzed bundle 'cdc-common-config' with 1 classes
[INFO] 
[INFO] --- maven-jar-plugin:2.6:jar (default-jar) @ cdc-common-config ---
[INFO] Building jar: D:\git_cdc2\cdc-backend-services\cdc-common-config\target\cdc-common-config-1.0.1-RELEASE.jar
[INFO] 
[INFO] --- spring-boot-maven-plugin:1.4.1.RELEASE:repackage (default) @ cdc-common-config ---
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 10.372 s
[INFO] Finished at: 2017-03-02T15:43:05+08:00
[INFO] Final Memory: 34M/497M
[INFO] ------------------------------------------------------------------------

12、修改maven版本号的常见方法(非常实用,推荐使用)

常见的做法:

商品中心的做法:
上传到测试环境:

  • mvn -Pdev clean deploy $deployParam -DskipTests=true -U
    上传到真线环境:
  • mvn -P !dev -Pprod clean deploy $deployParam -DskipTests=true -U

使用的shell脚本,如下所示:

#! bin/sh
echo "********** SNAPSHOT打包上传操作开始 **********"

# deploy的module列表,多个用逗号隔开,将会deploy以下module及其依赖module(含parent)
deployModules=batch-job-api,drds-transaction,item-microservice-agreement-api,item-microservice-api\
,item-microservice-common,item-microservice-external-api

deployParam="-pl $deployModules -am"

# deployParam=

if [[ -n "$deployParam" ]]
    then
        echo "********** 将会deploy的module及其依赖module(含parent):"

        arr=(${deployModules//,/ })
        for var in ${arr[@]}
        do
            echo "${var}"
        done
fi



# 获取当前住pom里面的maven version
currentMvnVersion=`awk '/<version>[^<]+<\/version>/{gsub(/<version>|<\/version>/,"",$1);print $1;exit;}' pom.xml`
echo "********** 当前version为:【" $currentMvnVersion "】"

read -p "********** 是否需要变更当前version?不需要请输入n,需要请输入指定version(格式*.*.*-SNAPSHOT): " selectVersion


if [[ $selectVersion == "n" ]]
    then
    if [[ $currentMvnVersion == *"-RELEASE" ]]
        then
            echo "********** 格式错误!当前为版本格式为-RELEASE,请输入以-SNAPSHOT结尾的版本号"
        else
            read -p "********** 是否需要把SNAPSHOT包【"$currentMvnVersion"】上传到dev环境?【y/n】" selectDev
            if [ $selectDev = "y" ]
            then
              echo "********** 开始打包并deploy到dev"
              mvn -Pdev clean deploy $deployParam -DskipTests=true -U
            else
              echo "********** 你没有deploy到dev"
            fi

                read -p "********** 是否需要把SNAPSHOT包【"$selectVersion"】上传到【真线】环境?【y/n】" selectProd
                    if [ $selectProd = "y" ]
                        then
                          echo "********** 开始打包并deploy到prod"
                          mvn -P \!dev -Pprod clean deploy -pl $deployModules -am -DskipTests=true -U
                        else
                          echo "********** 你没有deploy到prod"
                    fi
        fi

else if [[ $selectVersion == *"-SNAPSHOT" ]]
    then
    echo "********** 开始更新pom文件 ********** \n"
    mvn versions:set -DnewVersion=$selectVersion
    echo "********** 更新pom完成 ********** "

    read -p "********** 是否需要把SNAPSHOT包【"$selectVersion"】上传到dev环境?【y/n】" selectDev
    if [ $selectDev = "y" ]
        then
          echo "********** 开始打包并deploy到dev"
          mvn -Pdev clean deploy $deployParam -DskipTests=true -U
        else
          echo "********** 你没有deploy到dev"
        fi

    read -p "********** 是否需要把SNAPSHOT包【"$selectVersion"】上传到【真线】环境?【y/n】" selectProd
        if [ $selectProd = "y" ]
            then
              echo "********** 开始打包并deploy到prod"
              mvn -P \!dev -Pprod clean deploy -pl $deployModules -am -DskipTests=true -U
            else
              echo "********** 你没有deploy到prod"
            fi

    read -p "********** 是否保存更新后的version【"$selectVersion"】在代码里?【y/n】建议选y  " selectRevert
    if [ $selectRevert = "y" ]
        then
           echo "********** 保存更新后的version【"$selectVersion"】在代码里了"
        else
           mvn versions:set -DnewVersion=$currentMvnVersion
        fi
else
    echo "********** 格式错误!请输入以-SNAPSHOT结尾的版本号"
    fi
fi


echo "********** SNAPSHOT打包上传操作结束 **********"

13、工具详解 - Maven私有仓库Nexus

Maven私有仓库Nexus介绍和使用,对工具的使用查查资料就可以

13.1、Nexus是什么

1、有些公司都不提供外网给项目组人员,因此就不能使用maven访问远程的仓库地址,所以很有必要在局域网里找一台有外网权限的机器,搭建nexus私服,然后开发人员连到这台私服上,这样的话就可以通过这台搭建了nexus私服的电脑访问maven的远程仓库。而且自己maven私服更容易维护,由于在内网,公司的开发人员从maven私服迁出jar到本地仓库更快

2、当需要上传第三方或者自己的jar到maven仓库时,就需要私服了。

13.2、Nexus安装

搭建Maven私服

13.3、Nexus功能介绍

Nexus3功能介绍

13.4、Nexus配置和使用

Maven+Nexus代理中央仓库

13.5、Nexus上传第三方jar包

上传含Maven依赖的jar包和源码包到Nexus并下载引入到其他项目中

参考文章:

1、《Maven进阶》1.maven 项目生命周期与构建原理

2、POM Reference

问题1:禁止在子项目的 pom 依赖中出现相同的 GroupId,相同的 ArtifactId,但是不同的 Version。

说明:在本地调试时会使用各子项目指定的版本号,但是合并成一个 war,只能有一个版本号出现在最后的 lib 目录中。曾经出现过线下调试是正确的,发布到线上却出故障的先例。

问题2:底层基础技术框架、核心数据管理平台、或近硬件端系统谨慎引入第三方实现。

问题3:所有 pom 文件中的依赖声明放在<dependencies>语句块中,所有版本仲裁放在<dependencyManagement> 语句块中。

说明: <dependencyManagement> 里只是声明版本,并不实现引入,因此子项目需要显式的声明依赖,version 和 scope 都读取自父 pom。而<dependencies> 所有声明在主 pom 的 <dependencies> 里的依赖都会自动引入, 并默认被所有的子项目继承。

  • 基于此改造我们的项目

问题4:maven报错,父级 ‘Unknown:Unknown:Unknown’ 有问题

原因maven包下载错误,下载错误的原因是settings文件配置的有问题,导致下载的pom文件有问题

解决:到仓库中将原有的包删除,重新下载

参考:https://blog.csdn.net/weixin_52627566/article/details/125822086

问题5:maven下载资源时,选择的是错误的域名,导致下载超时

原因:maven目录下的libexec/conf/settings.xml文件不是最新的,但为啥用户设置文件的settings文件没有覆盖libexec/conf/settings.xml文件,暂不知道是为什么

解决方法:将maven目录下的libexec/conf/settings.xml文件,替换为最新的数据

问题6:maven报The POM for com. is invalid, transitive dependencies (if any) will not be available问题解决

https://blog.csdn.net/m0_73761022/article/details/128673121

 mvn -X -U clean package