zoukankan      html  css  js  c++  java
  • Maven系列3:详解maven解决依赖问题(该系列从 路人甲java 学习)

    使用maven创建的项目,有一个重要的文件,就是pom.xml文件。想要用maven帮忙处理项目,我们就要在pom.xml中说明要导入什么包,解决什么依赖,怎么打包,部署,并且项目结构也要按照maven的规定来。

    1、约定配置

     使用maven搭建的项目时,提倡使用共同的标准目录结构,maven使用约定优于配置的原则。

     ${basedir}     放置pom.xml和所有的子目录

     ${basedir}/src/main/java   放置项目的java源代码

     ${basedir}/src/main/resources  放置项目的资源文件,例如property文件,springmvc.xml文件

     ${basedir}/src/main/webapp/WEB-INF web应用文件目录,web项目的信息,比如存放web.xml,本地图片,jsp视图页面

     ${basedir}/src/test/java    放置测试代码,例如junit

     ${basedir}/src/test/resources  放置测试用的资源

     ${basedir}/target  打包输出目录

     ${basedir}/target/classes  编译输出目录

     ${basedir}/target/test-classes  测试编译输出目录

     Test.java   maven只会自动运行符合该命名规则的测试类

     ~/.m2/repository  默认的本地仓库目录位置

    2、pom文件

     当我们使用maven来解决jar冲突,jar依赖导入,项目的编译,测试,打包,部署时,必须要有pom.xml文件,这些都是在pom文件配置的。

     pom(project object model,项目对象模型),是maven工作的基本工作单元,是一个xml文件,项目运行时,maven到pom中获取配置信息,然后执行目标

     pom中可以指定以下配置:

             项目依赖、插件、执行目标、项目构建、项目版本、开发者名单、相关邮件列表信息

    3、maven坐标

     maven引入了坐标的概念,每一个构件都有自己的坐标,我们使用maven创建的项目需要标柱其坐标信息,依赖的其他构件也需要这些构建的坐标信息

     maven中构建坐标是通过一些元素定义的,它们是groupId,artifactId,version,packaging,classifier

         <groupid>定义当前构件所属的组,通常与域名反向一一对应</groupid>

         <artifactId>项目组中构件的编号<artifactId/>                   (一个groupId中可以包含有多个项目,就是通过artifactId来进行区别的)

         <version>当前构件的版本号<version/>

         <packaging>定义该构件的打包方式,默认为jar,可选(jar,war,ear,pom,maven-plugin)<packaging/>

    其中前三个是必须要定义的

     例如:

      <groupId>com.javacode2018</groupId>
      <artifactId>springboot-chat01</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <packaging>jar</packaging>

    我们可以将创建的springboot项目发布出去,然后只需要告诉别人springboot这个项目的坐标信息,其他人就可以直接使用了,而不用知道该项目都依赖了什么

    4、maven导入依赖的构件(maven如何引入需要的依赖)

    maven可以帮我们引入需要的构件,而maven是如何定位到某个构件上的呢?

    当引入第三方jar包时,我们需要知道其坐标信息,然后将这些信息放入到pom文件的dependencies元素中

      <dependencies>

        <dependency>

          <groupId><groupId/>

          <artifactId><artifactId/>

          <version><version/>

          <type><type/>

          <scope><scope/>

          <optional><optional/>

          <exclusions>

            <exclusion><exclusion/>

            <exclusion><exclusion/>

          <exclusions/>

        <dependency/>

      <dependencies/>

    在dependencies中,有多个dependency,每一个dependency都是一个依赖的的构件,groupid、artifactid、version这个三个是必须的

    type:依赖的构件类型,和packaging对应,默认是jar

    scope:构件作用的范围(编译源码,编译测试代码,运行测试,运行项目)

    option:标记依赖是否可选

    exclusion:用于排除传递性的依赖

    5、maven依赖范围(scope)

    需求:一个项目引入的构件要让它在一些时期起作用,一些时期不起作用。例如junit,只在编译测试代码,运行测试用例时使用,项目发布后就不再使用

       这需求怎么实现呢?

       java中编译代码、运行代码都需要通过classpath变量,classpath用来列出当前项目需要依赖的jar包,maven需要用到classpath的阶段又4个,编译源代码,编译测试代码,运行测试代码,运行项目,这四个阶段需要的claspath值不一定相同,这个maven中scope可以提供这个支持,scope是用来控制被依赖的构建和classpath的关系(编译,打包,运行所用到的classpath)

       <scope><scope/>标签解决这一个问题:scope可选择的值:

               compile:编译依赖范围,默认值。编译代码,编译测试代码,运行测试用例,运行项目都起作用

          test:测试依赖范围,使用此依赖的话,只对测试代码编译,测试代码运行有用。比如junit

       provide:已提供的依赖范围。表示项目的运行环境中已经提供了所需要的构件,此构件在编译源码,编译测试代码,运行测试代码时都有效,但是在运行时无效。比如servlet-api,在运行时由web容器提供,不需要maven在帮忙引入。

         runtime:运行时依赖范围,使用此依赖范围的maven依赖,对于编译测试代码,运行测试,运行项目时都有效,但是在编译源码是无效。例如jdbc驱动实现

              system:系统依赖范围,该依赖与3中classpath的关系,和provided依赖范围完全一致。但是,使用system范围的依赖时必须通过systemPath元素显示第指定依赖文件的路径。这种依赖直接依赖于本地路径中的构件,可能每个开发者机器中构件的路径不一致,所以如果使用这种写法,你的机器中可能没有问题,别人的机器中就会有问题,所以建议谨慎使用。

    如下:

    <dependency>
        <groupId>com.javacode2018</groupId>
        <artifactId>rt</artifactId>
        <version>1.8</version>
        <scope>system</scope>
        <systemPath>${java.home}/lib/rt.jar</systemPath>
    </dependency>

    import:这个比较特殊,后面的文章中单独讲,springboot和springcloud中用到的比较多。


    *******:scope在运行范围中有效,意思是指依赖的jar包会被打包到运行包中,最后运行时被添加到classpath中运行


    6、依赖的传递
    假如项目中引入了a,而a又依赖b和c,这时候maven就会自动的把b和c给导入进来,这就是依赖的传递。依赖的传递会受到scope的影响
    假如a依赖于b,b依赖于c,我们说a对于b是第一直接依赖,b对于c是第二直接依赖,a对于c是传递性依赖,而第一直接依赖的scope和第二直接依赖的scope决定了传递依赖的范围,即决定了a对于c的scope的值。
    下面我们用表格来列一下这种依赖的效果,表格最左边一列表示第一直接依赖(即A->B的scope的值),而表格中的第一行表示第二直接依赖(即B->C的scope的值),行列交叉的值显示的是A对于C最后产生的依赖效果。


    理解:以a对b的scope是complie,b对c的scope是runtime为例
    a是在什么时候都需要b,但是当在运行项目时,b这时也是要运行了,就需要引入c。a对c的传递依赖就是在runtime了

    7、maven依赖调节功能


    现实中可能存在这样的情况,a->b->c->d(1.0),a->h->d(2.0),此时d出现了两个版本,maven会选择d的那个版本呢?
    解决这种问题,有两个原则:
    路径最近原则:
    上面d的2.0版本离a更近一点,所以会选择2.0。
    如果路径一样呢?像a->b->d(1.0),a->h->d(2.0)
    这时候遵循 最先声明原则:
    就看b和h在pom文件中谁最先声明

    8、可选依赖
    当 a->b:compile
    b->c:compile 时,
    c会传递到a,假如b不想c让a依赖,怎办么,就使用optional元素,在b依赖c的过程中将optional的值设置为true

    9、排除依赖
    a->b,b->c(1.0),这两个scope都是compile,此时c会传递到a,但是a要使用c的2.0版本,不能让c传递过来,就可以在b->c中的exclusions
    元素中配置,如:
    <exclusions>
    <exclusion>
    <groupId>c的groupid<groupId/>
           <artifactId>c的artifactId<artifactId/>
    <exclusion/>
    <exclusions/>









  • 相关阅读:
    centos7.4 系统安装指导
    win10下硬盘安装CentOS7
    CentOs7.X下配置FTP
    pyspider 安装使用过程的一些坑
    .Net Core 商城微服务项目系列(十三):搭建Log4net+ELK+Kafka日志框架
    .Net Core自动化部署系列(二):使用Jenkins打造镜像发布流水线
    Kubernetes 系列(六):Kubernetes部署Prometheus监控
    Kubernetes 系列(五):Prometheus监控框架简介
    .Net Core 商城微服务项目系列(十二):使用k8s部署商城服务
    Kubernetes 系列(四):使用Traefik访问.net core api
  • 原文地址:https://www.cnblogs.com/fbbg/p/13064546.html
Copyright © 2011-2022 走看看