(转)Maven使用总结

Maven使用总结

依赖范围

  • maven创建的工程的目录中包含maintest文件夹,分别表示主程序的文件夹和测试程序的文件夹

  • maven使用scop设置依赖范围,常用的依赖范围如下:

    1. compile :编译依赖范围,在测试和运行都有效,这个是默认的依赖范围

      • 对主程序是否有效:有效
      • 对测试程序是否 有效: 有效
      • 是否参与打包:参与``
      • 是否参与部署:参与
    2. test:测试依赖的范围

      • 对主程序是否有效:无效
      • 对测试程序是否 有效: 有效
      • 是否参与打包:不参与
      • 典型的例子: junit
    3. provided

      • 对主程序是否有效: 有效
      • 对测试程序是否有效:有效
      • 是否参与打包:不参与
      • 是否参与部署:不参与
      • 典型的例子:servlet-api
        • 主要解决在开发中需要用到的,但是在部署的时候不需要的依赖,比如servlet-api,在开发中没有Tomcat运行环境,因此需要这个servlet-api,但是一旦部署在Tomcat中,Tomcat中会提供这个servlet-api,如果此时在添加的话会产生依赖冲突
    4. Runtime :测试和运行时需要。编译不需要。如JDBC驱动包

      • 对测试程序是否有效:有效
      • 对主程序是否有效:有效
      • 是否参与部署: 参与
      • 是否参与打包:参与
    5. system:系统依赖范围。本地依赖,不在maven*仓库

      • 这个必须和systemPath结合使用,用来指定本地依赖的位置
      <!-- 添加服务提供者的jar接口 -->
             <dependency>
                 <groupId>cn.tedu.dubbo</groupId>
                 <artifactId>dubbo-provider</artifactId>
                 <version>0.0.1</version>
                 <scope>system</scope>
                 <systemPath>${basedir}/src/main/webapp/WEB-INF/lib/dubbo-provider-helloService-0.0.1.jar</systemPath>
             </dependency>
      

依赖传递

  • 在开发项目的时候,我们通常需要建立多个项目,如果一个项目中需要用到另外一个项目的类或者数据,那么需要引入这个项目快照
  • 如果HelloFriend项目依赖Hello这个项目,此时的HelloFriendpom.xml文件如下:
<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>cn.tedu</groupId>
    <artifactId>HelloFriend</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    
    <dependencies>
        <!-- 添加Hello这个项目的依赖快照 -->
        <dependency>
            <groupId>cn.tedu</groupId>
            <artifactId>Hello</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>
    
</project>
  • 此时项目HelloFriend中存在依赖只有Hello项目这个jar,但是如果我们在Hello项目的pom.xml文件中添加一个junit的依赖,这个依赖范围为设置为compile,如下:
<dependencies>
        <!-- Junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
  </dependencies>
  • 做了上面的操作,我们可以查看项目HelloFriendHello中都自动的导入了Junit依赖,这个就是依赖传递。

注意

  • 依赖传递只有是依赖范围为compile的情况下才有作用,如果我们需要一个servlet-api的依赖,因为servlet-api这个jar在部署的时候会和Tomcat冲突,因此只能设置为provided,但是此时就不能依赖传递了,只能在每个项目中的pom.xml文件中都添加了

依赖排除

  • HelloFriend项目依赖Hello项目,其中compile范围的依赖都会导入HelloFriend
  • 使用dubbo默认会添加给我们添加spring-framework的版本为2.5.6,默认添加的依赖只能排除,不能在项目中再添加一个其他的版本,只有排除之后才能添加,否则会导致jar包冲突
  • Hello项目中的依赖为:
    <!-- Junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
        <!-- 添加dubbo依赖的jar,会自动添加spring 2.5版本的依赖 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.5.3</version>
        </dependency>
  • 此时HelloFriend的项目需要使用4.3.13版本的spring,那么我们有如下解决办法:

    1. Hello项目中改变依赖,排除spring2.5版本的:
      • 一般在公司中项目的版本都是定制好的,我们不可能随意改动父项目中定义好的版本,因此这个方法明显是不行的
          <!-- 使用spring4.3.13 -->
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-webmvc</artifactId>
              <version>4.3.13.RELEASE</version>
          </dependency>
    
          <dependency>
              <groupId>com.alibaba</groupId>
              <artifactId>dubbo</artifactId>
              <version>2.5.3</version>
                <!--排除spring2.5版本-->
                <exclusions>
                  <exclusion>
                      <groupId>org.springframework</groupId>
                      <artifactId>spring</artifactId>
                  </exclusion>
              </exclusions>
          </dependency>
    
  1. 我们可以在项目HelloFriend排除这个spring的依赖,那么我们就可以不需要改变Hello项目中的依赖了,如下:
    • 这个才是正确的排除依赖的方式
        <!-- SpringMVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.13.RELEASE</version>
        </dependency>
        
        <!-- 添加Hello这个项目的依赖快照 -->
        <dependency>
            <groupId>cn.tedu</groupId>
            <artifactId>Hello</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <!--排除项目中的spring2.5的依赖,这个不会影响Hello项目中的版本-->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring</artifactId>
                </exclusion>
            </exclusions>
        </dependency>       

依赖原则

依赖路径最短优先原则

  • 假设项目MakeFriend依赖HelloFriend,并且HelloFriend依赖Hello项目。此时Hello项目中使用的log4j 1.2.14版本的,但是在HelloFriend版本中使用的是log4j1.2.17版本的,那么此时的MakeFriend应该选择什么版本呢?
  •   (转)Maven使用总结 image
  • Hello的依赖如下:
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.14</version>
        </dependency>   
  • HelloFriend依赖如下:
    <!-- 添加Hello这个项目的依赖快照 -->
        <dependency>
            <groupId>cn.tedu</groupId>
            <artifactId>Hello</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        
        <!--添加1.2.17版本的log4j-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
  • MakeFriend的依赖如下:
        <dependency>
            <groupId>cn.tedu</groupId>
            <artifactId>HelloFriend</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
  • 我们根据图形可以看到MakeFriendHelloFriendlog4j1.2.17的路径是2,但是到Hello中的log4j1.2.14的路径为3,因此Maven会选择HelloFriend中的log4j1.2.17版本作为MakeFriend的依赖

pom文件中申明顺序优先

  • 路径都是一样的情况下,那么就要看在pom.xml文件中申明的顺序了,先申明的就使用哪个项目中的依赖版本

  • 假设现在的依赖改变了,MakeFriend现在是直接依赖HelloHelloFriend,如下图

  •   (转)Maven使用总结 image
  • 我们可以看出此时到两个版本的依赖都是一样的路径为2,那么我们应该选择哪个版本呢,此时就需要看看在MakeFriend中的pom.xml文件的申明顺序

    • 可以看出先申明的是HelloFriend,因此MakeFriend使用的是log4j1.2.17
<!-- 先申明HelloFriend,那么就要使用log4j.1.2.17版本 -->
        <dependency>    
            <groupId>cn.tedu</groupId>
            <artifactId>HelloFriend</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        
        <dependency>
            <groupId>cn.tedu</groupId>
            <artifactId>Hello</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

覆写优先

生命周期

  • maven的生命周期有三个部分组成,分别为clean生命周期site生命周期default生命周期

生命周期调用的特点

  • 三大生命周期中也会包含各个阶段,并且各个阶段是有序进行的,maven为了实现构建的自动化,如果我们使用了命令调用生命周期后面的处理阶段,那么会从最前面的阶段开始执行,不用每一个阶段都执行一遍。

clean生命周期

  • 在进行真正的构建之前进行一些清理工作

  • clean生命周期包括:

    • per-clean:执行了一些需要在clean之前完成的工作
    • clean:移除所有上一次构建生成的文件
    • post-clean:执行一些需要在clean之后立刻完成的工作
  • 当我们执行mvn:clean命令的时候只会执行per-cleanclean这两个阶段的任务,不会执行post-clean的工作

default生命周期

  • 构建的核心部分,编译、测试、打包、部署
  • 包括如下的23个生命周期阶段:
生命周期阶段 描述
validate 检查工程配置是否正确,完成构建过程的所有必要信息是否能够获取到。
initialize 初始化构建状态,例如设置属性。
generate-sources 生成编译阶段需要包含的任何源码文件。
process-sources 处理源代码,例如,过滤任何值(filter any value)。
generate-resources 生成工程包中需要包含的资源文件。
process-resources 拷贝和处理资源文件到目的目录中,为打包阶段做准备。
compile 编译工程源码。
process-classes 处理编译生成的文件,例如 Java Class 字节码的加强和优化。
generate-test-sources 生成编译阶段需要包含的任何测试源代码。
process-test-sources 处理测试源代码,例如,过滤任何值(filter any values)。
test-compile 编译测试源代码到测试目的目录。
process-test-classes 处理测试代码文件编译后生成的文件。
test 使用适当的单元测试框架(例如JUnit)运行测试。
prepare-package 在真正打包之前,为准备打包执行任何必要的操作。
package 获取编译后的代码,并按照可发布的格式进行打包,例如 JAR、WAR 或者 EAR 文件。
pre-integration-test 在集成测试执行之前,执行所需的操作。例如,设置所需的环境变量。
integration-test 处理和部署必须的工程包到集成测试能够运行的环境中。
post-integration-test 在集成测试被执行后执行必要的操作。例如,清理环境。
verify 运行检查操作来验证工程包是有效的,并满足质量要求。
install 安装工程包到本地仓库中,该仓库可以作为本地其他工程的依赖。
deploy 拷贝最终的工程包到远程仓库中,以共享给其他开发人员和工程。
  • 当一个阶段通过 Maven 命令调用时,例如mvn compile,只有该阶段之前以及包括该阶段在内的所有阶段会被执行。
  • [图片上传失败...(image-7b5809-1538922827484)]

Site生命周期

  • Maven Site 插件一般用来创建新的报告文档、部署站点等。
  • 包含以下阶段
    • pre-site:执行一些需要在生成站点文档之前完成的工作
    • site:生成项目的站点文档
    • post-site:执行一些需要生成站点文档之后完成的工作
    • site-deploy:将生成站点文档部署到特定的服务器上

Maven统一管理依赖的版本号

  • 假设如下的依赖:
    <!-- SpringMVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.13.RELEASE</version>
        </dependency>

        <!-- Spring-JDBC,要和spring-webmvc的版本一致 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.13.RELEASE</version>
        </dependency>   
  • 那么当我们需要改变spring的依赖版本号为4.3.12.RELEASE,那么我们只有逐个改变version中的值,现在是两个依赖比较好改变的,如果要有很多个的话,那么难免会改错,因此我们需要使用一种方式统一管理依赖的版本号。我们可以使用<properties>标签来管理,新的配置文件如下:
    • properties中的标签体可以任意指定,如果需要引用定义的标签体中的内容,那么直接使用${标签体}即可
    • 此时我们要是改变版本,那么只需要改变<properties>中的版本即可
<!-- 使用properties管理版本号 -->
    <properties>
        <!-- 这里的标签体可以任意指定,后续只要使用${}引用标签体即可使用其中定义的内容 -->
        <spring-version>4.3.13.RELEASE</spring-version>
    </properties>
    
    <dependencies>
        <!-- SpringMVC -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <!-- version使用${} -->
            <version>${spring-version}</version>
        </dependency>

        <!-- Spring-JDBC,要和spring-webmvc的版本一致 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring-version}</version>
        </dependency>
        
    </dependencies>

继承

  • 我们知道只有compile范围内的依赖才可以传递,但是对于testprovided中的依赖却是不可以传递的,那么必须在每个项目中都要添加依赖,此时肯定会出现每个项目中依赖版本不一致的情况,这样对于每个人的开发来说是比较困难的,因为不同版本的依赖使用的方式也不同,此时我们就需要统一管理这个版本了。
  • 下面我们以junit的版本控制为例

步骤

  • 创建一个父工程Hello-Parent,打包的方式为pom
  • Hello-Parent中的pom.xml文件中使用dependencyManagement管理版本,控制junit的版本依赖
<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>cn.tedu</groupId>
  <artifactId>Hello-Parent</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>
    
  <!-- 使用properties控制版本号 -->
  <properties>
    <junit-version>4.12</junit-version>
  </properties>
  
  <!-- 使用dependencyManagement管理版本 -->
  <dependencyManagement>
    
    <dependencies>
        <!-- Junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit-version}</version>
            <scope>test</scope>
        </dependency>
        
    </dependencies>
  </dependencyManagement>
  
</project>
  • 在子工程中使用parent标签指定声明对父工程的引用
    <parent>
        <groupId>cn.tedu</groupId>
        <artifactId>Hello-Parent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <!-- 使用relativePath指定父工程的相对位置 -->
        <relativePath>../Hello-Parent</relativePath>
    </parent>
  • 将子工程坐标和父工程坐标重复的地方删除,不删除也没关系
  • 在子工程中删除junitversion标签,表明是继承自父工程的版本,不需要指定
        <!-- Junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <!--此时不需要指定version了,因为父工程中已经指定了-->
        </dependency>
  • 子工程全部的配置
<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和父工程中的重复了,因此可以删除 
    <groupId>cn.tedu</groupId>-->
    <artifactId>Hello</artifactId>
    <!-- 这里的version版本也和父工程的重复了,因此可以删除
    <version>0.0.1-SNAPSHOT</version> -->
    
    <parent>
        <groupId>cn.tedu</groupId>
        <artifactId>Hello-Parent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <!-- 使用relativePath指定父工程的相对位置 -->
        <relativePath>../Hello-Parent</relativePath>
    </parent>
    
    <dependencies>
        <!-- Junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <!--不需要指定version-->
        </dependency>
    </dependencies>
</project>

聚合

  • 我们在开发项目的时候都是分模块开发的,此时如果想要使用maven安装这个项目的话,那么需要一个一个的安装,但是我们可以使用聚合的方式,可以实现一次性安装。并且安装还是有先后顺序的,一定要先安装父工程,否则将会找不到依赖信息,我们使用聚合的方式就没有先后安装的障碍了,maven会为我们自动的解决

步骤

  1. 创建一个maven工程,打包方式为pom,当然也是可以直接使用父工程
  2. 在pom.xml配置文件中配置module
  3. 详细的pom.xml如下:
<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>cn.tedu</groupId>
  <artifactId>Hello-Manager</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>
  
  <!-- 继承父工程 -->
  <parent>
        <groupId>cn.tedu</groupId>
        <artifactId>Hello-Parent</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <!-- 使用relativePath指定父工程的相对位置 -->
        <relativePath>../Hello-Parent</relativePath>
    </parent>
  
  <!-- 使用聚合的方式 -->
  <modules>
    <module>../Hello-Parent</module>
    <module>../Hello</module>
    <module>../HelloFriend</module>
    <module>../MakeFriend</module>
  </modules>
  
</project>

原文:https://www.jianshu.com/p/b7d08690d242

上一篇:9.牛批了 Android 2022高级 资深面试题 一线大厂和二线大厂面试真题精选 (字节跳动 附答案)第九套 38k+


下一篇:面试官:谈谈你对Android性能优化方面的了解?