《Maven实战》笔记

2022-06-28 20:58:43 浏览数 (1)

本文最后更新于 659 天前,其中的信息可能已经有所发展或是发生改变。

第一章 Maven简介

1.1何为Maven

maven翻译为“知识的积累”,“内行”,“专家”

作为Apache组织中颇为成功的一个开源项目,Maven主要服务于基于Java平台的项目构建,依赖管理和项目信息管理

1.1.1何为构建

编译,运行单元测试,生成文档,打包和部署

1.1.2Maven是优秀的构建工具
  • Maven是跨平台的
  • 最大化地消除了构建的重复
  • 抽象了构建生命周期
  • 提供已实现的插件
  • 标准化构建过程
1.1.3Maven不仅仅是构建工具
  • 依赖管理工具
    • 随着依赖的增多,版本不一致、版本冲突、以来臃肿等问题都会接踵而来。
    • Maven提供了一个优秀的解决方案(坐标系统)来定位每一个构件
  • 项目信息管理工具
    • 项目描述、开发者列表、版本控制系统地址、许可证、缺陷管理系统地址等
  • 通过Maven插件,我们能轻松获得项目文档、测试报告、静态分析代码、源码版本、日志报告等有价值的项目信息
  • 约定优于配置
    • Maven对项目目录结构、测试用例命名方式等内容都有既定的规则

1.2同类工具

  • Make
    • 强大之处在于它可以利用所有系统的本地命令,达到快速、高效
    • 缺点
    • 将自己和系统绑定在一起了,无法跨平台
    • 语法不友好
  • Ant 不是蚂蚁,而是意指“另一个整洁的工具”(Another Neat Tool),最早用来构建Tomcat
    • 支持跨平台
    • 使用Xml定义构建脚本,更加友好
    • 缺点
    • 针对构建的过程,每个项目都要重新编写
    • 没有依赖管理

1.3Maven与极限编程

极限编程(XP)是敏捷开发方法,强调拥抱变化。

  • Maven如何帮助XP团队实现一些核心价值
    • 简单
    • Maven暴露了一组一致、简洁的操作接口,简化构建系统的复杂度
    • 交流与反馈
    • 与版本控制系统结合,所有人都能执行最新的构建并快速得到反馈
    • 自动生成项目报告,帮助成员了解项目的状态,促进团队的交流
  • Maven无缝支持或融入到XP的实践中
    • 测试驱动开发(TDD)
    • TDD强调测试先行,所有产品都应由测试用例覆盖。
    • 测试是Maven生命周期中最重要的组成部分之一,提供现成的插件,如JUnitTestNG
    • 持续集成(CI)
    • CI强调的是项目以最短的周期(如15分钟)集成最新的代码。
    • CI的前提是源码管理系统和构建系统
    • 目前业界流行的CI服务器HudsonCruiseControl都能很好的和Maven集成,使用Maven后,持续集成会更加方便
    • 富有信息的工作区
    • 强调开发者能够快速方便地了解到项目的最新状态。

“只有两类计算机语言,一类语言天天被人骂,还有一类没人用。” ------C 之父


第二章 Maven的安装和配置

  • 安装目录介绍
    • boot:类加载器框架
    • lib:可在这里找到maven内置的超级POM
    • NOTICE.txt记录了maven包含的第三方软件

第三章 Maven使用入门

  • POM:project object model,项目对象模型
  • modelVersion:当前POM模型的版本
  • SNAPSHOT:快照,说明项目处于开发中,是不稳定版本
  • 没有任何Java代码,我们就能定义一个Maven项目的POM,体现了项目对象模型最大程度的和实际代码独立——解耦
  • 代码的包名:GroupId ArtifactId
  • finalName:自定义打包后的文件名
  • jar:jar:jar插件的jar目标
  • Archetype:快速生成项目骨架,感觉和SpringBootStarter很像,都是一堆jar包的集合

第四章 背景案例

第五章 坐标和依赖

  • Maven坐标元素
    • groupId:【必须】当前项目隶属的实际项目(公司域名 项目名,例如org.sonatype.nexus
    • artifactId:【必须】实际项目中的一个Maven项目(模块),推荐实际项目作为artifactId的前缀,例如nexus.indexer
    • version:【必须】版本,包括快照(SNAPSHOT
    • packaging:【可选】打包方式,通常与所产生构件的文件扩展名对应,当不定义时,默认为jar
    • classifier:【不能直接定义】帮助定义构建输出的一些附属构件,附属构件与主构件对应,例如通过插件生成如nexus-indexer-2.0.0-javadoc.jar注意,不能直接定义项目的classifiler,因为附属构件不是有项目直接产生的,而是由附加的插件帮助生成
  • 可在方法上使用@Before注解,该方法将在@Test方法之前执行,就行aop一样,同理还有@After
  • 依赖的配置
    • groupId、artifactId、version:依赖的基本坐标
    • type:依赖的类型,对应项目坐标定义的packaging,大部分情况不必声明,默认为jar
    • scope:依赖的范围
    • option:依赖是否可选
    • exclusions:用来排除传递性依赖
  • 三套不同的classpath
    • 编译classpath:编译项目主代码
    • 测试classpath:编译和执行测试代码
    • 运行classpath:实际运行项目
  • 依赖范围:控制依赖与classpath的关系
    • compile:编译依赖范围,如果没指定,默认使用该依赖范围,使用此依赖范围的依赖,对于编译、测试、运行三种classpath都有效,例如spring-core
    • test:测试依赖范围,使用此依赖范围的依赖,只对于测试classpath有效,在编译主代码或者运行项目时将无法使用此类依赖,比如在主代码里import测试依赖范围的依赖里的class,将会报错。例如Junit,只有在编译测试代码和运行测试代码时才需要
    • provided:已提供依赖范围,使用此依赖范围的依赖,对于编译和测试classpath有效,运行时无效。例如springboot项目打war包时,需要将web-starter里的tomcat依赖排除掉,然后单独添加一个tomcat的依赖,并设置依赖范围为provided,这样打包后,lib目录下将没有tomcat的jar包,这样便可放到tomcat里运行了
    • runtime:运行时依赖范围,使用此依赖范围的依赖,对于测试和运行的classpath有效,编译时无效。例如JDBC驱动实现,项目主代码编译时只需要JDK提供的JDBC接口,只是在执行测试或者运行项目的时候才需要实现上诉接口的具体JDBC驱动
    • system:系统依赖范围,与classpath的关系与provided一样,使用此依赖范围必须通过systemPath元素显示地指定依赖文件的路径,systemPath可使用环境变量,例如${java.home}/lib/rt.jar。实际项目示例
  • import:导入依赖范围。该依赖范围不会对三种classpath产生实际的影响
  • 传递性依赖和依赖范围

第一直接/第二直接

compile

test

provided

runtime

compile

compile

runtime

test

test

test

provided

provided

provided

provided

runtime

runtime

runtime

  • 依赖调解
    • 第一原则:路径最近者优先
    • 第二原则:第一声明者优先
  • 可选依赖
    • <optional>true</optional>
    • 不会被传递
  • 排除依赖
    • <exclusion></exclusion>
    • 只需要groupIdatfactId,不需要version
  • 归类依赖
    • 使用<properties></properties>来控制某类依赖的版本,例如spring
  • 优化依赖
    • Maven会自动解析所有项目的直接依赖和和传递性依赖,并且根据规则判断每个依赖的范围,对于一些依赖冲突,也能进行调节,以确保任何一个构件只有一个版本的依赖存在。
    • 最后得到的依赖称为已解析依赖。可通过命令查看mvn dependency:list,还可以通过树的形式查看mvn dependency:tree
    • 最方便的还是Idea的maven help插件
    • mvn dependency:analyze分析依赖,可以得到未声明但被使用的依赖,和声明但未被使用的依赖
  • 关于解决依赖冲突、优化依赖,可以看看这篇文章,比较实用

第六章 仓库

  • Maven项目不再各自存储其依赖文件,只需声明坐标,在需要的时候(例如,编译项目的时候需要将其加入到classpath中),Maven会自动根据坐标,找到仓库中的构件,并使用他们
  • 依赖的查找
    • 本地仓库—>私服—>其他公共库(阿里、网易)—>中央仓库
  • 远程仓库的配置
    • setting.xml
    • pom.xml里的<repository></repository>
    • <layout></layout>指仓库布局
    • <snapshots></snapshots>配置是否下载快照版
    • 注意:以ID区分,相同会覆盖
  • 私服的优点
    • 节省外网宽带
    • 加速Maven构建(Maven构建时会检查快照版本是否为最新)
    • 部署第三方构建(二方包也可以)
    • 降低中央仓库的负荷
    • 提高稳定性,增强控制
  • mvn clean deploy部署到远程仓库

第七章 生命周期和插件

  • Maven的生命周期是抽象的,其实际行为都由插件来完成(设计模式:模板方法)
  • 生命周期抽象了构建的各个步骤,定义了他们的次序,但没有提供具体的实现
  • 三套相互独立的生命周期:clean、default、site

生命周期

目的

包含的阶段

clean

清理项目

三个:pre-clean、clean、post-clean

default

构建项目

validate、initialize、generate-sources、process-sources、generate-resources、process-resources、compile、process-classes、generate-test-sources、process-test-sources、generate-test-resources、process-test-resources、test-compile、process-test-classes、test、prepare-package、package、pre-integration-test、integration-test、post-integration-test、verify、install、deploy

site

建立项目站点

4个:pre-site、site、post-site、site-deploy

  • 插件目标
    • 一个插件包含多个功能,每个功能对应一个插件目标
    • maven-dependency-plugin有十多个目标
    • 分析依赖冲突:mvn dependency:tree -Dverbose
    • 查看声明但未被使用的依赖:mvn dependency:analyze-only
    • 查看重复声明的依赖:mvn dependency:analyze-duplicate
  • 绑定生命周期与插件
    • 为了让用户不用任何配置就能构建Maven项目,maven内置绑定了一些核心的生命周期与插件目标
    • 支持自定义绑定
  • Maven 生命周期的阶段与插件的目标之间的绑定关系
    • clean 生命周期

    clean 生命周期的阶段 插件的目标 pre-clean clean maven-clean-plugin:clean post-clean

    • default 生命周期的内置插件绑定关系及具体任务(打包类型:jar)

    生命周期阶段 插件目标 执行任务 process-resources maven-resources-plugin:resources 复制主资源文件至主输出目录 compile maven-compiler-plugin:compile 编译主代码至主输出目录 process-test-resources maven-resources-plugin:testResources 复制测试资源文件至测试输出目录 test-compile maven-compiler-plugin:testCompile 编译测试代码至测试输出目录 test maven-surefire-plugin:test 执行测试用例 package maven-jar-plugin:jar 创建项目 jar 包 install maven-install-plugin:install 将项目输出构件安装到本地仓库 deploy maven-deploy-plugin:deploy 将项目输出构件部署到远程仓库 注意:上表只列出了拥有插件绑定关系的阶段,default 生命周期还有很多其他阶段,默认它们没有绑定任何插件,因此也没有任何实际行为。

    • site 生命周期

    site 生命周期的阶段 插件的目标 pre-site site maven-site-plugin:site post-site site-deploy maven-site-plugin:deploy

第八章 聚合与继承

  • 约定 一般来说,一个项目的子模块都应该使用相同的groupId,如果他们一起开发和发布,还应该使用同样的version
  • 聚合项目的packaging必须为pom,否则无法构建
  • 通过module元素来实现聚合
  • 聚合项目并非一定是父子关系,例如平行关系
  • 使用平行目录结构时,需要注意module元素为相对路径,例如<module>../xxxx</module>
  • 对聚合的pom执行maven命令时,maven会先解析pom,分析要构建的模块,并计算出一个反应堆构建顺序,然后根据这个顺序构建模块
  • 反应堆
    • 对于单模块项目,反应堆就是其本身
    • 对于多模块项目,反应堆指所有模块组成的一个构建结构,包含各模块之间继承与依赖的关系,从而能够自动计算出合理的模块构建顺序
    • 先分析pom,如果该模块没有依赖与其他模块,则先构建,如果依赖了,则先构建依赖的模块
  • 继承
    • 父容器的packaging必须为pom
    • 子项目包含parent元素
    • 子项目构建时会根据relative元素检查父pom,如果找不到,再从本地仓库查找,relative默认值为../pom.xml
  • 父项目设置dependencymanagement,约束子项目dependencies下的依赖,可以打破解决依赖冲突时,maven的两大仲裁原则(路径最短优先,先声明优先)
  • 通过scope为import,type为pom,引入其他pom的dependencymanagement
  • 插件管理:pluginmanagement
  • 约定大于配置
    • Maven核心设计理论
    • 大量减少配置,开箱即用
    • 例如目录结构(当然也可以自定义,不过得付出代价,个性往往意味着失去通用性,增加复杂性)

Post Views: 350

0 人点赞