本文是开发工具篇第三讲:maven 从入门到实战

文章目录

    • 1、什么是maven?
    • 2、Maven能为我们解决什么问题?
    • 3、说说maven有什么优缺点?
    • 4、什么是Maven的坐标?
    • 5、讲一下maven的生命周期
    • 6、说说你熟悉哪些maven命令?
    • 7、如何解决依赖传递引起的版本冲突?
    • 8、说说maven的依赖原则
    • 9、说说依赖的解析机制?
    • 11、说说插件的解析机制
    • 12、修改maven版本号的常见方法
  • Action1:定义 GAV 遵从以下规则:
  • Action2:二方库版本号命名方式:主版本号.次版本号.修订号
  • Action3:线上应用不要依赖 SNAPSHOT 版本(安全包除外) ;正式发布的类库必须先去中央仓库进行查证, 使 RELEASE 版本号有延续性, 且版本号不允许覆盖升级。
  • Action4:二方库的新增或升级,保持除功能点之外的其它 jar 包仲裁结果不变。如果有改变,必须明确评估和验证。
  • Action5:二方库里可以定义枚举类型, 参数可以使用枚举类型, 但是接口返回值不允许使用枚举类型或者包含枚举类型的 POJO 对象。
  • Action6:二方库定制包的命名方式,在规定的版本号之后加“-英文说明[序号]” ,英文说明可以是部门简称、 业务名称,序号直接紧跟在英文说明之后,表示此定制包的顺序号。
  • Action7:依赖于一个二方库群时,必须定义一个统一的版本变量,避免版本号不一致。
  • Action8:禁止在子项目的 pom 依赖中出现相同的 GroupId,相同的 ArtifactId,但是不同的 Version。
  • Action9:底层基础技术框架、核心数据管理平台、或近硬件端系统谨慎引入第三方实现。
  • Action10:所有 pom 文件中的依赖声明放在`<dependencies>`语句块中,所有版本仲裁放在`<dependencyManagement>` 语句块中。
  • Action11:二方库不要有配置项, 最低限度不要再增加配置项。
  • Action12:不要使用不稳定的工具包或者 Utils 类。
  • Action13:为避免应用二方库的依赖冲突问题,二方库发布者应当遵循以下原则:

1、什么是maven?

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

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

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


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的坐标?

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


5、讲一下maven的生命周期

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



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、如何解决依赖传递引起的版本冲突?

  • 问题:

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

  • 解决方案:重新升级item-standard项目jar包,然后im项目和ip项目依赖is最新的jar包,即可。

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

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

8、说说maven的依赖原则

最短路径原则

  • 依赖传递的路径越短越优先

pom文件申明顺序优先

  • 路径长度一样,则先申明的优先

覆写原则

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

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

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

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

11、说说插件的解析机制

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

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-apideployParam="-pl $deployModules -am"# deployParam=if [[ -n "$deployParam" ]]thenecho "********** 将会deploy的module及其依赖module(含parent):"arr=(${deployModules//,/ })for var in ${arr[@]}doecho "${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): " selectVersionif [[ $selectVersion == "n" ]]thenif [[ $currentMvnVersion == *"-RELEASE" ]]thenecho "********** 格式错误!当前为版本格式为-RELEASE,请输入以-SNAPSHOT结尾的版本号"elseread -p "********** 是否需要把SNAPSHOT包【"$currentMvnVersion"】上传到dev环境?【y/n】" selectDevif [ $selectDev = "y" ]thenecho "********** 开始打包并deploy到dev"mvn -Pdev clean deploy $deployParam -DskipTests=true -Uelseecho "********** 你没有deploy到dev"firead -p "********** 是否需要把SNAPSHOT包【"$selectVersion"】上传到【真线】环境?【y/n】" selectProdif [ $selectProd = "y" ]thenecho "********** 开始打包并deploy到prod"mvn -P \!dev -Pprod clean deploy -pl $deployModules -am -DskipTests=true -Uelseecho "********** 你没有deploy到prod"fifielse if [[ $selectVersion == *"-SNAPSHOT" ]]thenecho "********** 开始更新pom文件 ********** \n"mvn versions:set -DnewVersion=$selectVersionecho "********** 更新pom完成 ********** "read -p "********** 是否需要把SNAPSHOT包【"$selectVersion"】上传到dev环境?【y/n】" selectDevif [ $selectDev = "y" ]thenecho "********** 开始打包并deploy到dev"mvn -Pdev clean deploy $deployParam -DskipTests=true -Uelseecho "********** 你没有deploy到dev"firead -p "********** 是否需要把SNAPSHOT包【"$selectVersion"】上传到【真线】环境?【y/n】" selectProdif [ $selectProd = "y" ]thenecho "********** 开始打包并deploy到prod"mvn -P \!dev -Pprod clean deploy -pl $deployModules -am -DskipTests=true -Uelseecho "********** 你没有deploy到prod"firead -p "********** 是否保存更新后的version【"$selectVersion"】在代码里?【y/n】建议选y  " selectRevertif [ $selectRevert = "y" ]thenecho "********** 保存更新后的version【"$selectVersion"】在代码里了"elsemvn versions:set -DnewVersion=$currentMvnVersionfi
elseecho "********** 格式错误!请输入以-SNAPSHOT结尾的版本号"fi
fiecho "********** SNAPSHOT打包上传操作结束 **********"

Action1:定义 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: 详细规定参考下方。

Action2:二方库版本号命名方式:主版本号.次版本号.修订号

  • 1)主版本号:产品方向改变,或者大规模 API 不兼容,或者架构不兼容升级。
  • 2)次版本号:保持相对兼容性,增加主要功能特性,影响范围极小的 API 不兼容修改。
  • 3)修订号:保持完全兼容性,修复 BUG、新增次要功能特性等。

说明:注意起始版本号必须为:1.0.0,而不是 0.0.1。
反例:仓库内某二方库版本号从 1.0.0.0 开始,一直默默“升级” 成 1.0.0.64,完全失去版本的语义信息。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Action12:不要使用不稳定的工具包或者 Utils 类。

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

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

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

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

开发工具篇第三讲:Maven从入门到实战相关推荐

  1. 开发工具篇第九讲:菜鸟入坑指南

    摘要:本文是开发工具篇第九讲:菜鸟入坑指南.针对新人上手慢的问题,写了这篇入坑指南,方便自己回顾,总结.本文分为四个部分,分别为jenkins使用技巧:常用软件操作命令:开发手册:调试手册.主要材料来 ...

  2. Cesium开发工具篇 | 07回顾总结

    到目前为止,Cesium开发课程的篇幅已经学完四分之三了,大家如果有什么问题可以私信我或者扫描以下二维码进群沟通,若群二维码失效,可扫描最下方的公众号二维码,加我为好友并备注加群.有时会比较忙来不及回 ...

  3. 【后端教程】深入浅出动态化 SSR 服务(一):开发工具篇

    简述 在前端还未系统化之时的刀耕火种时代,已经有非常多的生成页面的工具,其可视化的方式极大的赋能了非技术人员,加快了业务的迭代速度.如今,随着前端技术的发展和复杂化,我们看到越来越多以组件为基础的页面 ...

  4. 嵌入式 Linux 开发工具篇问题整理//C语言测试(杨辉三角、递归调用实现阶乘、计算器、统计字符串出现次数)//2018.07.12.//

    嵌入式 Linux 开发工具篇问题整理 1. 嵌入式开发与传统开发的区别?(同类问题:单片机开发与嵌入式开发的区别)             是否有无操作系统:     2. 移植操作系统的好处有哪些 ...

  5. 安装Ubuntu后必须要做的几件事(二)--开发工具篇

    链接 链接 安装Ubuntu后必须要做的几件事(一)–基础应用篇 安装Ubuntu后必须要做的几件事(二)–开发工具篇 终端的乐趣–Linux下有趣的终端命令或者工具 Ubuntu使用apt-file ...

  6. iOS开发工具篇-AppStore统计工具

    http://blog.devtang.com/blog/2013/06/16/ios-dev-tool-app-store-tool/ iOS开发工具篇-AppStore统计工具 JUN 16TH, ...

  7. 开发工具篇第八讲:阿里云OSS对象存储服务

    本文是开发工具篇第八讲:阿里云对象存储服务(Object Storage Service,简称 OSS),具有与平台无关的RESTful API接口,您可以在任何应用.任何时间.任何地点存储和访问任意 ...

  8. 【个人博客设计】开发工具篇

    概述 系列: [个人博客设计] [个人博客设计]框架与插件篇 [个人博客设计]开发工具篇 开发工具:IDEA+Navicat+tomcat+Hbuilder+微信开发者工具 1.1.IntelliJ ...

  9. 【Groovy】Gradle 构建工具 ( 自动下载并配置构建环境 | 提供 API 扩展与开发工具集成 | 内置 Maven 和 Ivy 依赖管理 | 使用 Groovy 编写构建脚本 )

    文章目录 一.Gradle 自动下载并配置构建环境 二.Gradle 提供 API 扩展与开发工具集成 三.Gradle 内置 Maven 和 Ivy 依赖管理 四.Gradle 使用 Groovy ...

最新文章

  1. NOIp 图论算法专题总结 (1):最短路、最小生成树、最近公共祖先
  2. LINUx设置ip导致内核挂死,Linux之TCPIP内核参数优化
  3. JAVA调用c/c++代码
  4. 微众WeCross 跨链平台(10)使用场景
  5. VTK:PolyData之RibbonFilter
  6. [小才能]防备误删文件
  7. android里的oneshot模式,android – 使用ONE_SHOT标志等待意图
  8. 再聊机器人设计:如何加速开发流程?
  9. Selenium 显式等待条件及其含义
  10. commons-io实现流的拷贝
  11. [转]Effective C#原则4:用条件属性而不是#if
  12. GitHub 标星 10,000+,Apache 顶级项目 ShardingSphere 的开源之路
  13. 高斯消元解模同余方程组
  14. ECSHOP用户评论
  15. android 信号检测,卫星、手机信号都能测!安卓神器你值得拥有
  16. matlab syms类型,matlab中syms类型的转换
  17. Linux下U盘自动识别和挂载
  18. 人工智能安全(二)—攻击
  19. 信息学奥赛一本通C++语言-----1087:级数求和
  20. 'cnpm' 不是内部或外部命令,真正有效解决方法

热门文章

  1. 2016-7-20 奶奶走了
  2. C语言/C++初学 问题
  3. JavaScrip 防止别人复制,剪切,查看源代码,页面另存为的操作
  4. 常用逻辑用语@命题@猜想@量词@否命题和命题的否定
  5. 计算机设置表格内框线,word表格和边框在哪里 exl表格内框线怎么设置
  6. 电脑服务器型号在哪,电脑服务器型号内存
  7. 技术人生:真的要注意身体了,坚持锻炼
  8. wamp mysql创建数据库_在wamp中创建数据库
  9. mcreator安装教程
  10. 为什么android手机内存不够,安卓手机内存不足怎么办?安卓手机内存越来越小解决方法汇总...