ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Maven基础

2022-07-18 17:34:28  阅读:160  来源: 互联网

标签:优先 依赖 -- basedir 基础 Maven 仓库


核心思想:约定大于配置

其实约定大于配置这一思想在开发中经常出现
当程序中的某一个或者某一些参数没有配置的时候,程序会自动设定一个默认值。
这个默认值的设定,就称之为约定。

意义在于:减少不必要的配置。

仓库

Maven的仓库分为三种:

  1. 本地仓库:maven优先从本地库中获取依赖
  2. 中央仓库:当本地库没有所需依赖包时,中央仓库 → 本地仓库
  3. 远程私服仓库:中央仓库有非常多常用的lib,但并非所有,为了下载中央仓库下载不到的lib,自己构建私人的远程仓库以供下载构建依赖

标准目录

目录 作用
${basedir} 项目根目录,存放pom.xml和所有子目录
${basedir}/src/main/java 存放 java 源代码
${basedir}/src/main/resources 存放资源文件,如 propert 文件
${basedir}/src/test/java 存放测试代码
${basedir}/src/test/resources 存放测试的资源文件
${basedir}/src/main/webapp/WEB-INF web 应用文件目录,如 web.xml,本地图片,jsp
${basedir}/target 打包输出目录
${basedir}/target/classes 编译输出目录
${basedir}/target/test-classes 测试编译输出目录

构件

  • groupId:当前Maven构件隶属组织名(必须)
  • artifactId:项目的唯一标识符,项目的名称(必须)
  • version:当前版本(必须)
  • scope:依赖范围指定
  • packaging:打包方式
  • classifier:通常用于区分以上项目都相同的构件的不同版本

依赖范围

依赖范围是三种可见性的组合
有三种可见性,编译,测试,运行

  • compile:默认的依赖范围,对于编译,测试,运行三种都生效

  • test:仅对于测试生效,典型的就是 Junit

  • provided:对于编译,测试生效。比如 servlet-api.jar 在 Tomcat 中已经提供了,只需要编译与测试阶段提供即可。

  • runtime:对于测试,运行生效。如JDBC驱动实现。
    注:由于现在的开发多使用mybatis,所以JDBC的部分不需要在编译阶段处理。

  • system:与上述均不相同。使用 system 后必须通过 systemPath 元素指定依赖文件的路径,不依赖 Maven 仓库的解析,所以存在依赖关系不可移植的风险。

依赖冲突

直接依赖冲突

众所周知,对于 Maven 而言,同一个groupId,artifactId下,只能使用一个 version

<dependencies>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.3.0</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.0</version>
    </dependency>
</dependencies>

对于上述配置,将使用3.5.0的mybatis,可以理解为后配置覆盖前配置(覆盖策略)

※思考问题

现在,我们可以思考下,比如工程中需要引入A、B,而 A 依赖 1.0 版本的 C,B 依赖 2.0 版本的 C,那么问题来了,C 使用的版本将由引入A、B的顺序而定? 这显然不靠谱!如果 A 的依赖写在 B 的依赖后面,将意味着最后引入的是 1.0 版本的 C,很可能在运行阶段出现类(ClassNotFoundException)、方法(NoSuchMethodError)找不到的错误(因为B使用的是高版本的C)!

传递依赖冲突

Maven 引入的传递性依赖机制,能大大简化依赖管理。大部分情况只需要关心项目的直接依赖,而不用关心依赖的依赖。但是当多个直接依赖的依赖出现冲突时,问题就令人抓狂了起来。

依赖传递有两种情况:

  1. 存在模块间的继承关系,在继承父模块后同时引入父模块中的依赖,可通过可选依赖机制放弃依赖传递到子模块
  2. 引入lib时附带引入该lib的依赖lib。这是依赖冲突的主要原因。如下所示。
    x → y → z(1.0)
    x → g → z(2.0)
    由于z 1.0和2.0两个都解析会导致依赖重复,所以必须选择其中一个。

依赖优化

Maven有一定的智能,可以对部分依赖进行调整来保证构件的唯一性。

因为只针对部分依赖,所以还是有误判的情况。因此,通过手动配置来优化依赖还是有必要的。
我们可以使用 maven-dependency-plugin 提供的三个目标来实现依赖分析

$ mvn dependency:list
$ mvn dependency:tree
$ mvn dependency:analyze

若需要更精细的分析,可以在命令后添加如下参数

-Dverbose
-Dincludes=<groupId>:<artifactId>

依赖冲突调解规则

软件开发依赖冲突问题,有四种原则:

  • 路径最短优先原则
  • 声明顺序优先原则
  • 排除原则
  • 版本锁定原则

依赖调解详解

Maven依赖调解遵循以下两大原则:路径最短优先声明顺序优先

第一原则:路径最短优先

若依赖链的长度不同是,优先使用短的

a --> b --> x(1.1)		// dist(a->x) = 2
a --> c --> d --> x(1.2)	// dist(a->x) = 3

上述情况,优先使用版本x(1.1)的依赖

第二原则:声明顺序优先

若依赖链的长度相同时,使用优先声明的

a --> b --> x(1.1)	// dist(a->x) = 2
a --> c --> x(1.2)	// dist(a->x) = 2

当 a 的 pom.xml 中优先声明 b,使用 x(1.1) 的依赖

解决依赖冲突

简单暴力,在对应pom.xml中加入一下内容即可

<dependency>
  <groupId>org.glassfish.jersey.containers</groupId>
  <artifactId>jersey-container-grizzly2-http</artifactId>
  <!-- 剔除依赖 -->
  <exclusions>
    <exclusion>
      <groupId>org.glassfish.hk2.external</groupId>
      <artifactId>jakarta.inject</artifactId>
    </exclusion>
    ...
  </exclusions>
</dependency>

标签:优先,依赖,--,basedir,基础,Maven,仓库
来源: https://www.cnblogs.com/buzuweiqi/p/16491270.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有