Maven学习笔记

Maven概述

Maven是Apache软件基金会组织维护的一款专门为Java项目提供构建依赖管理支持的工具。

Maven的作用: 【管理jar包之间的依赖关系】

  1. 随着框架封装程度提高,项目使用的jar包规模越来越大
  2. 项目中的jar包从来源各异,不便获取;使用Maven之后,jar包会从规范的远程仓库下载到本地
  3. 项目中的jar包存在错综复杂的依赖关系,甚至可能会产生冲突;Maven通过依赖的传递性自动完成依赖jar包的导入,可以对依赖的配置进行调整,让某些jar包不会被导入从而处理冲突问题

【软件构建的管理工具】

  1. 脱离IDE环境的生产环境中执行构建操作,需要专门的工具支持;Maven针对构建过程的主要环节提供支持

Snipaste_2022-05-17_18-48-54.png

软件项目构建的主要环节:

  1. 清理:删除上一次构建的结果,为下一次构建做好准备
  2. 编译:将Java 源程序编译成 *.class 字节码文件
  3. 测试/报告:运行提前准备好的测试程序jUnit
  4. 打包:对Java工程封装为jar包、Web工程封装为war包
  5. 安装:将打包生成的jar包和war包存放在Maven仓库
  6. 部署:对于jar包部署至Nexus私服服务器、war包借助cargo等插件部署至Tomcat服务器等

Maven的工作机制如下图所示。
Snipaste_2022-05-17_19-13-28.png

Maven核心概念

坐标__:Maven使用三个『向量』『Maven的仓库』唯一定位到一个『jar』包,坐标和仓库中jar包的存储路径之间有对应关系

  • groupId:公司或组织的 id(域名的倒序,通常也会加上项目名称)
  • artifactId:一个项目或者是项目中的一个模块的 id(模块的名称)
  • version:版本号(后缀SNAPSHOT表示快照版本/RELEASE 表示正式版本)

POM_:_Project Object Model,项目对象模型。和POM类似的是DOM(Document Object Model),即文档对象模型,它们都是模型化思想的具体体现 Maven工程根目录下的pom.xml配置文件是Maven工程的核心配置文件

  1. <!-- 当前Maven工程的坐标 -->
  2. <groupId>com.eliyson.maven</groupId>
  3. <artifactId>pro01-maven-java</artifactId>
  4. <version>1.0-SNAPSHOT</version>
  5. <!-- 当前Maven工程的打包方式,可选值有下面三种: -->
  6. <!-- jar:表示这个工程是一个Java工程 -->
  7. <!-- war:表示这个工程是一个Web工程 -->
  8. <!-- pom:表示这个工程是“管理其他工程”的工程 -->
  9. <packaging>jar</packaging>
  10. <name>pro01-maven-java</name>
  11. <url>http://maven.apache.org</url>
  12. <!-- 可以在properties标签中自定义属性,用于后面标签中使用 -->
  13. <!-- 后面标签中使用自定义属性方式:${自定义属性名} -->
  14. <properties>
  15. <!-- 工程构建过程中读取源码时使用的字符集 -->
  16. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  17. </properties>
  18. <!-- 当前工程所依赖的jar包,可包含多个dependency -->
  19. <dependencies>
  20. <!-- 使用dependency配置一个具体的依赖,仅包含一个gav坐标 -->
  21. <dependency>
  22. <!-- 在dependency标签内使用具体的坐标指定我们需要依赖的一个jar包 -->
  23. <groupId>junit</groupId>
  24. <artifactId>junit</artifactId>
  25. <version>4.12</version>
  26. <!-- scope标签配置依赖的范围 -->
  27. <scope>test</scope>
  28. </dependency>
  29. </dependencies>

约定目录结构__:为了让构建过程能自动化完成,必须约定目录结构。例如:Maven执行编译操作,必须先去Java源程序目录读取Java源代码,然后执行编译,最后把编译结果存放在target目录 随着框架封装程度越来越高,逐渐呈现从编码到配置,再到约定的技术发展趋势

Snipaste_2022-05-17_21-00-48.png

依赖范围__:即引入的jar包的有效作用范围,可以在pom.xml中scope标签中配置依赖的范围,可选值有compile/test/provided/system/runtime/import,常用依赖范围选值有compile(编译运行有效)、test(测试有效,junit)、provided(运行环境已提供的)。限制的作用范围如下表 对于服务器运行环境中已有的jar包,项目不将相同的jar包放入war包并部署至运行环境,以避免和服务器上已有的同类 jar 包产生冲突,所以将这类引用的jar包依赖范围设置为provided 实际使用需引入第三方jar包时可以从网站(http://mvnrepository.com)上查找jar包信息,复制gav坐标及依赖范围至当前模块的pom.xml文件中dependencies标签中

依赖范围 main目录 test目录 开发过程 部署至服务器
compile 有效 有效 有效 有效
test 无效 有效 有效 无效
provided 有效 有效 有效 无效

依赖传递性【在 A 依赖 B,B 依赖 C 的前提下,A 引入 B 的 jar 包是否同时带入 C 的 jar 包】

  • B 依赖 C 时使用 compile 范围:可以传递
  • B 依赖 C 时使用 test 或 provided 范围:不能传递,必须单独配置依赖

版本仲裁**:**工程依赖的不同jar包直接或间接地依赖同一功能jar包的不同版本,则Maven按最短路径优先路径相同时先声明者优先的原则组织jar包的依赖

Snipaste_2022-05-18_00-26-44.png
Snipaste_2022-05-18_00-28-33.png

排除依赖__:显式指明排除的依赖,避免jar包之间的冲突

  1. <dependency>
  2. <groupId>com.eliyson.maven</groupId>
  3. <artifactId>pro01-maven-java</artifactId>
  4. <version>1.0-SNAPSHOT</version>
  5. <scope>compile</scope>
  6. <!-- 使用excludes标签配置依赖的排除 -->
  7. <exclusions>
  8. <!-- 在exclude标签中配置一个具体的排除 -->
  9. <exclusion>
  10. <!-- 指定要排除的依赖的坐标(不需要写version) -->
  11. <groupId>commons-logging</groupId>
  12. <artifactId>commons-logging</artifactId>
  13. </exclusion>
  14. </exclusions>
  15. </dependency>

继承__:Maven工程之间,A 工程继承 B 工程,则称 B 工程是父工程,A 工程是子工程。本质上是 A 工程的pom.xml 中的配置继承了 B 工程中 pom.xml 的配置。通过在父工程中为整个项目维护依赖信息的组合既保证了整个项目使用规范、准确的 jar 包;又能够将以往的经验沉淀下来,节约时间和精力 【提出继承的需求背景】

  1. 实际项目中需对程序进行模块划分,每一个模块都需要各自维护自己的依赖信息,不易统一管理jar包版本
  2. 使用框架时所需要的jar包依赖信息组合需要经过长期摸索和反复调试,最终确定一个可用稳定的组合,这个耗费很大精力总结出来的方案不应该在新的项目中重新摸索

Maven工程继承关系的配置:

  1. 创建父工程:将父工程pom.xml中的打包方式修改为pom方式,<packaging>pom</packaging>
  2. 创建模块工程:在父工程的根目录下创建模块工程。
  3. 父工程中配置依赖的统一管理:子工程创建后会在父工程的pom.xml中自动生成聚合标签,父工程通过该聚合标签管理子工程。

    1. <modules>
    2. <module>pro04-maven-module</module>
    3. <module>pro05-maven-module</module>
    4. <module>pro06-maven-module</module>
    5. </modules>
  4. 子工程中指明父工程坐标:在子工程的pom.xml中使用parent标签指定当前工程的父工程。

    1. <parent>
    2. <!-- 父工程的坐标 -->
    3. <groupId>com.eliyson.maven</groupId>
    4. <artifactId>pro03-maven-parent</artifactId>
    5. <version>1.0-SNAPSHOT</version>
    6. </parent>
  5. 父工程统一管理依赖:使用dependencyManagement标签配置对依赖的管理。

    1. <properties>
    2. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    3. <!-- 自定义标签,维护Spring版本数据 -->
    4. <spring.version>4.3.6.RELEASE</spring.version>
    5. </properties>
    6. <dependencyManagement>
    7. <dependencies>
    8. <dependency>
    9. <groupId>org.springframework</groupId>
    10. <artifactId>spring-core</artifactId>
    11. <version>${spring.version}</version>
    12. </dependency>
    13. </dependencies>
    14. </dependencyManagement>
  6. 子工程引用被父工程管理的依赖:父工程管理的依赖并没有自动引入子工程,需在子工程中单独配置,配置时可以把版本号省略,表示子工程中这个依赖的版本由父工程决定。

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.springframework</groupId>
    4. <artifactId>spring-core</artifactId>
    5. </dependency>
    6. </dependencies>

    聚合__:使用一个“总工程”将各个“模块工程”汇集起来,作为一个整体对应完整的项目。聚合后的构建命令可以在“总工程”中一键执行,自动依据依赖关系选择正确的顺序执行;总工程的modules标签中列出完整的模块工程 【聚合和继承】两者是同一的,从继承角度上看是父工程和子工程的关系;从聚合关系上看是总工程和模块工程的关系

生命周期__:Maven设定了相互独立的三个生命周期,生命周期中每个环节对应构建过程中的每个操作

  1. Clean Lifecycle:在进行真正的构建之前进行一些清理工作
  2. Default Lifecycle:构建的核心部分,编译,测试,打包,安装,部署等等
  3. Site Lifecycle:生成项目报告,发布站点

在任何一个生命周期内部,执行任何一个具体环节的操作,都是从本周期最初的位置开始执行,直到指定的地方,构建过程的自动化程度大大提高

插件__:Maven的核心程序仅仅负责宏观调度(定义了抽象的生命周期),不做具体工作。具体工作由Maven插件完成,一个插件可以对应多个目标,而每个目标都和生命周期中的某个环节对应。例如maven-compiler-plugin-3.1.jar插件中有compile和test-compile两个目标,对应Default生命周期中的compile和test-compile两个环节

仓库__:仓库有本地仓库和远程仓库之分 Maven私服:在局域网内可以使用Nexus技术搭建Maven私服,为当前局域网范围内的所有Maven工程服务 中央仓库:Internet上为全世界所有Maven工程提供服务 中央仓库镜像:为中央仓库分担流量,减轻中央仓库的压力

1.jpg

Maven基础配置

核心程序解压后即可使用,需修改系统环境变量及配置文件conf/settings.xml。

【与Maven相关的环境变量配置】

  1. Maven是Java程序,必须基于JDK运行,需要通过JAVA_HOME找到JDK的安装位置
  2. 配置Maven的bin目录上一层目录为MAVEN_HOME变量,并将bin目录加入PATH

【配置文件settings.xml的配置】 指定本地仓库/配置中央仓库的镜像仓库/配置默认JDK版本

  1. <!-- 指定本地仓库路径 -->
  2. <localRepository>C:\MvnRepository</localRepository>
  3. <!-- 在mirrors标签中设置中央仓库镜像,提高访问速度 -->
  4. <mirrors>
  5. <mirror>
  6. <id>nexus-aliyun</id>
  7. <mirrorOf>central</mirrorOf>
  8. <name>Nexus aliyun</name>
  9. <url>http://maven.aliyun.com/nexus/content/groups/public</url>
  10. </mirror>
  11. </mirrors>
  12. <!-- 指定Java工程默认JDK版本 -->
  13. <profile>
  14. <id>jdk-1.8</id>
  15. <activation>
  16. <activeByDefault>true</activeByDefault>
  17. <jdk>1.8</jdk>
  18. </activation>
  19. <properties>
  20. <maven.compiler.source>1.8</maven.compiler.source>
  21. <maven.compiler.target>1.8</maven.compiler.target>
  22. <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
  23. </properties>
  24. </profile>

Maven命令行环境

Maven的jar包管理命令由主命令和子命令构成,子命令包含插件和操作目标两个部分。使用Maven与jar包管理相关的命令应在对应Maven工程目录下,要求存在pom.xml文件。
Snipaste_2022-05-17_23-29-21.png
生成Maven管理的Java工程:mvn archetype:generate(archetype即为雏形/原型的意思)
清理:mvn clean(删除编译生成的target目录)
编译:mvn compile(主程序编译,主程序编译结果约定存放目录:target/classes);mvn test-compile(测试程序编译,测试程序编译结果约定存放目录:target/test-classes)
测试/报告:mvn test(测试报告目录:target/surefire-reports)
打包:mvn package(jar包存放目录:target)
安装:mvn install(jar 包存入 Maven 本地仓库,pom.xml 文件转换为jar包中的pom文件)
查看依赖:mvn dependency:list(列表展示)或mvn dependency:tree(树形结构展示)

Maven的IDEA环境

新建 Microsoft PowerPoint 演示文稿.jpg

POM的配置一二

Q:构建时需要将依赖的jar包一并打入到jar包中,在POM中如何配置?
A:可利用Maven的打包插件maven-assembly-plugin指定目标,将所有依赖的jar包打包为一个统一的jar包。

  1. <!-- 在pom.xml文件中可加入构建过程使用的插件并指明目标/对应生命周期的环节 -->
  2. <build>
  3. <plugins>
  4. <plugin>
  5. <artifactId>maven-assembly-plugin</artifactId>
  6. <configuration>
  7. <descriptorRefs>
  8. <descriptorRef>jar-with-dependencies</descriptorRef>
  9. </descriptorRefs>
  10. </configuration>
  11. <executions>
  12. <execution>
  13. <id>make-assembly</id>
  14. <phase>package</phase>
  15. <goals>
  16. <goal>single</goal>
  17. </goals>
  18. </execution>
  19. </executions>
  20. </plugin>
  21. </plugins>
  22. </build>