转载

Maven学习2: 依赖管理

1. 创建一个maven项目

  1. 使用Idea创建一个maven项目

    • File>New>Project,
    • 左侧选择Maven,右侧选择Project SDK为1.8,点击Next
    • 输入项目GroupId、ArtifactId,点击Next
    • 点击Finish
  2. 项目目录结构

    Maven学习2: 依赖管理

    |demo
        |src
            |main
                |java # 源码目录
                |resources # 资源目录
            |test
                |java # 测试源码目录
        |pom.xml # 项目配置文件
  3. pom文件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.john.example</groupId>
        <artifactId>demo1</artifactId>
        <version>1.0-SNAPSHOT</version>
    </project>

2. 约定优于配置

  1. 项目目录结构遵循约定

    创建的maven空项目已经包含了一定的目录结构,需要开发者遵循这种目录约定,这是使用maven简洁配置需要付出的代价。

    目录 说明
    {project.basedir} 存放pom文件和项目子模块
    {project.basedir}/src/main/java 源码目录
    {project.basedir}/src/main/resources 资源目录
    {project.basedir}/src/test/java 测试源码目录
    {project.basedir}/src/test/resources 测试资源目录
    ${project.basedir}/target 包输出目录
    ${project.basedir}/target/classes 编译输出目录
    ${project.basedir}/target/test-classes 测试编译输出目录

3. pom文件

  1. 说明
    POM(Project Object Model,项目对象模型)定义了项目的基本信息,用于描述项目如何构建、声明项目依赖。
  2. 简单配置

    <?xml>
    <project>
    <modelVersion>
    <groupId>
    <artifactId>
    <version>
    groupId/artifactId/version
    
  3. 其他配置

    • 项目依赖
    • 插件
    • 执行目标
    • 项目构建profile

4. maven坐标

  1. 说明
    Maven定义了一组规则:世界上任何一个构件都可以使用Maven坐标唯一标识。
    Maven坐标元素包括 groupId , artifactId , version , packaging , classifier
  2. 坐标元素

    • groupId : 定义当前maven项目隶属的实际项目。
    • artifactId : 定义实际项目中的一个maven模块/项目。
    • version : 定义maven项目当前所处的版本。
    • packaging : 定义maven项目的打包方式。打包方式与生成构件的文件扩展名对应,默认为 jar , 常用的打包方式有 jarwarpom
    • classifier : 帮助定义构建输出的附属构件。附属构件与主构件对应。如demo1-1.0-SNAPSHOT- sources .jar这个构件,包含了主构件的源代码。不能直接定义项目的classifier,因为附属构件不是项目直接默认生成的,而是通过附加插件帮助生成的。
  3. 项目构件的文件名

    • 一般规则为: artifactId-version[-classifier].packaging

5. maven依赖

  1. 使用maven怎么引入依赖?

    • 如果要引入第三方jar包,需要知道jar的坐标,然后放入pom.xml中的 dependencies 元素中。

      示例如下:

      <project>
          <dependencies>
              <!-- 添加依赖 -->
              <dependency>
                  <groupId></groupId>
                  <artifactId></artifactId>
                  <version></version>
                  <type></type>
                  <scope></scope>
                  <optional></optional>
                  <exclusions>
                      <exclusion></exclusion>
                      <exclusion></exclusion>
                  </exclusions>
              </dependency>
          </dependencies>
      </project>
    • dependencies 元素包含多个 dependency ,每个 dependency 代表项目依赖的一个构件信息。
    • dependency 元素中的 groupIdartifactIdversion 定义了一个构件的基本坐标。
    • type 被依赖构件的类型,对应于被依赖构件的 packaging 。默认为 jar , 表示被依赖的构件是一个jar包。
    • scope 表示依赖的范围,参考 2.maven依赖范围
    • optional 表示依赖是否可选,参考可选依赖。
    • exclusions 用来排除传递依赖。
  2. maven依赖范围

    依赖范围就是用来控制依赖与三种classpath(编译classpath,运行classpath,测试classpath【编译测试代码、运行测试代码】)的关系。

    • compile : 编译依赖范围。如果未指定,默认使用该依赖范围。 对于编译、测试、运行3种classpath都有效 。比如spring-web。
    • test : 测试依赖范围。只对测试classpath有效, 在编译主代码、运行项目时无法使用此依赖 。比如JUnit。
    • provided : 已提供依赖范围。 对于编译、测试classpath有效,但在运行时无效 。比如servlet-api,在运行项目的时候容器已经提供了。
    • runtime : 运行时依赖范围。 对于测试、运行classpath有效,但在编译主代码时无效 。比如jdbc驱动实现,运行的时候才需要具体的jdbc驱动实现。
    • system : 系统依赖范围。该依赖与三种classpath的关系,和provided依赖范围完全一致。但是,使用system范围的依赖时必须通过systemPath元素显示指定依赖文件的路径。建议谨慎使用。

      <dependency>
          <groupId>com.john</groupId>
          <artifactId>rt</artifactId>
          <version>1.8</version>
          <scope>system</scope>
          <systemPath>${java.home}/lib/rt.jar</systemPath>
      </dependency>
    • import : 导入依赖范围。在maven依赖和dependencyManagement时候用到。
  3. 依赖范围与classpath的关系

    依赖范围

    (scope)

    对于编译classpath有效 对于测试classpath有效 对于运行classpath有效 举例
    compile Y Y Y spring-web
    test -- Y -- JUnit
    provided Y Y -- servlet-api
    runtime -- Y Y JDBC驱动实现
    system Y Y -- 本地的jar包
  4. scope与运行classpath
    scope如果对于运行范围有效,是指依赖的jar包会被打包到项目的运行包中,最后运行的时候会被添加到classpath中运行。
    如果scope对于运行项目无效,那么项目打包的时候,这些依赖不会被打包到运行包中。

6. 传递性依赖

  1. 说明

    • 在项目中引入groupId:junit, artifactId:junit, version:4.12, scope:test的依赖,查看项目依赖,发现项目依赖junit,而junit又依赖org.hamcrest:hamcrest-core:1.3,该依赖也被自动加进来,这个叫做依赖的传递。
    • 假设 A依赖于B,B依赖于C,我们说A对于B是 第一直接依赖 ,B对于C是 第二直接依赖 ,而A对于C是 传递性依赖
    • 第一直接依赖的范围和第二直接依赖的范围决定了传递依赖的范围。
  2. 依赖范围对传递性依赖的影响

    第一直接依赖 / 第二直接依赖 compile test provided runtime
    compile compile -- -- runtime
    test test -- -- test
    provided provided -- provided provided
    runtime runtime -- -- runtime

7. 依赖调解

  1. 第一原则:路径近者优先。

    • A->B->C->Y(1.0),A->D->Y(2.0) ,Y的2.0版本距离A更近一些,所以maven会选择2.0
  2. 第二原则:第一声明者优先。

    • A->B->Y(1.0),A->D->Y(2.0) ,Y的1.0版先声明,所以maven会选择1.0版本。

8. 可选依赖

A->B, scope:compile
    B->X, scope:compile,optional:true
    B->Y, scope:compile,optional:true
  • X、Y是可选依赖,依赖不会由B传至A。X、Y不会对A造成影响。
  • 理想情况下,不应该使用可选依赖。

9. 依赖管理最佳实践

  1. 排除依赖

    • 前提

      A->B, scope:compile
          B->C, scope:compile
    • 目的:A不想引入传递性依赖C
    • 使用 exclusions 元素声明排除依赖, exclusions 元素可以包含多个 exclusion 元素。
    • 声明 exclusion 元素时只需要 groupIdartifactId
  2. 归类依赖

    • 使用 properties 元素定义maven属性

      <properties>
          <springframework.version>5.2.1.RELEASE</springframework.version>
      </properties>
  3. 优化依赖

    • 查看当前项目的已解析依赖(Resolved Dependency)

      john:demo1 john$ mvn dependency:list
      [INFO] Scanning for projects...
      [INFO] 
      [INFO] ---------------------------< com.john:demo1 >---------------------------
      [INFO] Building demo1 1.0-SNAPSHOT
      [INFO] --------------------------------[ jar ]---------------------------------
      [INFO] 
      [INFO] --- maven-dependency-plugin:2.8:list (default-cli) @ demo1 ---
      [INFO] 
      [INFO] The following files have been resolved:
      [INFO]    org.hamcrest:hamcrest-core:jar:1.3:test
      [INFO]    org.springframework:spring-beans:jar:5.2.1.RELEASE:compile
      [INFO]    org.springframework:spring-core:jar:5.2.1.RELEASE:compile
      [INFO]    org.springframework:spring-jcl:jar:5.2.1.RELEASE:compile
      [INFO]    junit:junit:jar:4.12:test
      [INFO]    org.springframework:spring-web:jar:5.2.1.RELEASE:compile
      [INFO] 
      [INFO] ------------------------------------------------------------------------
      [INFO] BUILD SUCCESS
      [INFO] ------------------------------------------------------------------------
      [INFO] Total time: 0.905 s
      [INFO] Finished at: 2019-12-14T18:34:26+08:00
      [INFO] ------------------------------------------------------------------------
    • 查看当前项目的依赖树

      john:demo1 john$ mvn dependency:tree
      [INFO] Scanning for projects...
      [INFO] 
      [INFO] ---------------------------< com.john:demo1 >---------------------------
      [INFO] Building demo1 1.0-SNAPSHOT
      [INFO] --------------------------------[ jar ]---------------------------------
      [INFO] 
      [INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ demo1 ---
      [INFO] com.john:demo1:jar:1.0-SNAPSHOT
      [INFO] +- org.springframework:spring-web:jar:5.2.1.RELEASE:compile
      [INFO] |  +- org.springframework:spring-beans:jar:5.2.1.RELEASE:compile
      [INFO] |  /- org.springframework:spring-core:jar:5.2.1.RELEASE:compile
      [INFO] |     /- org.springframework:spring-jcl:jar:5.2.1.RELEASE:compile
      [INFO] /- junit:junit:jar:4.12:test
      [INFO]    /- org.hamcrest:hamcrest-core:jar:1.3:test
      [INFO] ------------------------------------------------------------------------
      [INFO] BUILD SUCCESS
      [INFO] ------------------------------------------------------------------------
      [INFO] Total time: 0.938 s
      [INFO] Finished at: 2019-12-14T18:35:31+08:00
      [INFO] ------------------------------------------------------------------------
    • 分析当前项目的依赖

      john:demo1 john$ mvn dependency:analyze
      [INFO] Scanning for projects...
      [INFO] 
      [INFO] ---------------------------< com.john:demo1 >---------------------------
      [INFO] Building demo1 1.0-SNAPSHOT
      [INFO] --------------------------------[ jar ]---------------------------------
      [INFO] 
      [INFO] >>> maven-dependency-plugin:2.8:analyze (default-cli) > test-compile @ demo1 >>>
      [INFO] 
      [INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ demo1 ---
      [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
      [INFO] skip non existing resourceDirectory /Users/john/Desktop/demo1/demo1/src/main/resources
      [INFO] 
      [INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ demo1 ---
      [INFO] Nothing to compile - all classes are up to date
      [INFO] 
      [INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ demo1 ---
      [WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
      [INFO] skip non existing resourceDirectory /Users/john/Desktop/demo1/demo1/src/test/resources
      [INFO] 
      [INFO] --- maven-compiler-plugin:3.1:testCompile (default-testCompile) @ demo1 ---
      [INFO] Nothing to compile - all classes are up to date
      [INFO] 
      [INFO] <<< maven-dependency-plugin:2.8:analyze (default-cli) < test-compile @ demo1 <<<
      [INFO] 
      [INFO] 
      [INFO] --- maven-dependency-plugin:2.8:analyze (default-cli) @ demo1 ---
      [WARNING] Unused declared dependencies found:
      [WARNING]    org.springframework:spring-web:jar:5.2.1.RELEASE:compile
      [INFO] ------------------------------------------------------------------------
      [INFO] BUILD SUCCESS
      [INFO] ------------------------------------------------------------------------
      [INFO] Total time: 1.285 s
      [INFO] Finished at: 2019-12-14T18:41:43+08:00
      [INFO] ------------------------------------------------------------------------
原文  https://segmentfault.com/a/1190000021287778
正文到此结束
Loading...